From 9eaa44e268232895158e338a263bf4174611d1dd Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 17 Jun 2020 19:35:17 -0500 Subject: [PATCH] Start migration over to Python for emu command wrapper (#21) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * readme * test starting emu_utils.py from emu command * fixs * test * test * pass all! * test * test * functionality for Emu python class * functionality for Emu python class * fixup for DEBUG mode * test colors! * add formatting * add update function * make sure update.sh is executable * use update path * temp * does this fix it? * make executable * debug * debug * that works! use oh_my_comma_path for git pull * test * use subprocess * debug * fix * better * update using emu-utils.sh * fix * use python * test * test * test * debug * debug * only source if running first-install * updates to install.sh * add pandaflash2 * Add run and get_next_arg functions * debug * should fix it * should fix it * add newline * simplify newline * move newline * add newline * test * test * test * test * whoops * whoops * test * test * test * test * test * work on debug command * add controlsd * test * debug * debug * debug * debug * debug * debug * debug * test uploader * test logmessaged with call * write to file * debug * debug * debug * debug * debug * debug * debug * debug * without shell * test check_call * debug * weird, that worked. how about this? * test * test * ? * test killing updated * debug * debug * fix * test more * debug * debug * debug * debug * debug * clean up controlsd func, add warning * use prompt * add orange * add better warning * detect if python script failed * cause an error * will this work? * debug * debug * now cause error * change * test * add comment * add comment * add comment * now fix update! * fix name * use openpilot method of starting processes * test * test * test * test * use old method, add backup of openpilot's process method in case this doesn't work out * only attempt update if user tried to update and failed * add additional message * simplify * add color to success message * installfork command support * move static methods to emu_utils.py, verify fork URl and clone to temp fork folder and move once complete * use .bak instead of .old * catch ctrl+c * add end arg * debug * debug * fix * fix * fix * add flags to each command * change to flag * much better flag implementation lol * don't need to specify arg * add flags to help * test help interface * test help interface * try blue * test different colors * this looks good * formatting for list * add test flag * colors * colors * add branch alias * print commands in help * final updates before click * backup emu.py * test click * test click * test click * test click * test click * test click * test click * test click * test click * fix old/emu.py so it at least works. flags do not * add old emu.py back * use click * move * move * move * add 🐼's * add more * more emoji * change clone url back * temporarily change branch * Master cli updates patch1 (#22) * use prettier * allow for easier local dev? * more consistent use of env variables * prettier * warn about update source * easier local debug? * add encoding to colors * Update README.md * Update README.md * Update README.md * add sexy ascii * Update install.sh * Set theme jekyll-theme-slate * Update README.md * use error_msg arg of print_commands for all Co-authored-by: Shane * remove old from emu-utils.sh * clean ups for emu.py * add base and fork commands * fixes for install.sh * emu_utils updates * remove space * move main to base * add update function to new format * test * fix for commands with no subcommands * rename to CommandBase, add more emoji! * switch emoji * add emoji to commands * fix emoji * move * add panda command * add better emoji for panda to match fork's format * add better emoji for panda to match fork's format * fix for panda cmd * remove an extra line from art, update longest command length * automatically format based on longest command * add debug to new command format, clean up imports, switch around panda messages * remove old * test * test * remove since it inherits the function * emu.py is only 49 lines! clean up imports * remove commented * update aliases * fix * add log file flag to debug * fix * debug * fix * debug * debug * debug * debug * test required * debug * add flag's description to the argparser * fix * add final functionality for using user-supplied output file path * display version * display version * remove old * debug the wait time * debug the wait time * debug the wait time * debug the wait time * debug the wait time * debug the wait time * debug the wait time * debug the wait time * debug the wait time * i couldn't figure it out... :( * test showing flags * debug * debug * fix * test * test * test * test * test * test * don't show flags if main * better * add leading * add leading * just a test of the new menu format * just a test of the new menu format * test no leading * test no leading * remove * add todo * add todo Co-authored-by: Comma Device Co-authored-by: AskAlice Co-authored-by: Alice Knag --- aliases.sh | 4 +- emu-utils.sh | 90 ++++-------------------- emu.py | 48 +++++++++++++ emu_commands/base.py | 78 +++++++++++++++++++++ emu_commands/debug.py | 25 +++++++ emu_commands/fork.py | 78 +++++++++++++++++++++ emu_commands/panda.py | 20 ++++++ emu_commands/update.py | 11 +++ install.sh | 42 ++++++------ py_utils/colors.py | 22 ++++++ py_utils/emu_utils.py | 151 +++++++++++++++++++++++++++++++++++++++++ update.sh | 10 ++- 12 files changed, 476 insertions(+), 103 deletions(-) create mode 100644 emu.py create mode 100644 emu_commands/base.py create mode 100644 emu_commands/debug.py create mode 100644 emu_commands/fork.py create mode 100644 emu_commands/panda.py create mode 100644 emu_commands/update.py mode change 100644 => 100755 install.sh create mode 100644 py_utils/colors.py create mode 100644 py_utils/emu_utils.py mode change 100644 => 100755 update.sh diff --git a/aliases.sh b/aliases.sh index 1b6fe6cf..d69aa72e 100644 --- a/aliases.sh +++ b/aliases.sh @@ -1,3 +1,3 @@ alias ll="ls -lhA" -alias pf="emu pandaflash" -alias controlsd="emu debug controls" +alias pf="emu panda flash" +alias controlsd="emu debug controlsd" diff --git a/emu-utils.sh b/emu-utils.sh index 65c983bf..b7b83d8b 100644 --- a/emu-utils.sh +++ b/emu-utils.sh @@ -1,93 +1,29 @@ #!/bin/bash SYSTEM_BASHRC_PATH=/home/.bashrc export COMMUNITY_PATH=/data/community -export COMMUNITY_BASHRC_PATH=/data/community/.bashrc +export COMMUNITY_BASHRC_PATH=${COMMUNITY_PATH}/.bashrc export OH_MY_COMMA_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" source ${OH_MY_COMMA_PATH}/powerline.sh - source ${OH_MY_COMMA_PATH}/aliases.sh -commands=" - - update: updates this tool, requires restart of ssh session - - pandaflash: flashes panda - - pandaflash2: flashes panda without make recover - - debug: debugging tools - - installfork: Specify the fork URL after. Moves openpilot to openpilot.old" -debugging_commands=" - - controls: logs controlsd to /data/output.log" - -function _pandaflash() { - cd /data/openpilot/panda/board && make recover -} - -function _pandaflash2() { - cd /data/openpilot/panda; pkill -f boardd; PYTHONPATH=..; python -c "from panda import Panda; Panda().flash()" -} - -function _controlsdebug(){ - pkill -f controlsd ; PYTHONPATH=/data/openpilot python /data/openpilot/selfdrive/controls/controlsd.py 2>&1 | tee /data/output.log -} - -function _installfork(){ - if [ $# -lt 1 ]; then - echo "You must specify a fork URL to clone!" - return 1 - fi - - old_dir="/data/openpilot.old" - old_count=0 - if [ -d $old_dir ]; then - while [ -d "/data/openpilot.old.${old_count}" ]; do - old_count=$((old_count+1)) # counts until we find an unused dir name - done - old_dir="${old_dir}.${old_count}" - fi - - echo "Moving current openpilot installation to ${old_dir}" - mv /data/openpilot ${old_dir} - echo "Fork will be installed to /data/openpilot" - git clone $1 /data/openpilot -} - -function _debug(){ - if [ $# -lt 1 ]; then # verify at least two arguments - printf "You must specify a command for emu debug. Some options are:" - printf '%s\n' "$debugging_commands" - return 1 - fi - - if [ $1 = "controls" ]; then - _controlsdebug - else - printf "Unsupported debugging command! Try one of these:" - printf '%s\n' "$debugging_commands" - fi -} - -function _updateohmycomma(){ - source /data/community/.oh-my-comma/update.sh +function _updateohmycomma(){ # good to keep a backup in case python CLI is broken + source ${OH_MY_COMMA_PATH}/update.sh + source ${OH_MY_COMMA_PATH}/emu-utils.sh } function emu(){ # main wrapper function - if [ $# -lt 1 ]; then - printf "You must specify a command for emu. Some options are:" - printf '%s\n' "$commands" - return 1 + if $(python -c 'import sys; print(".".join(map(str, sys.version_info[:3])))' | grep -q -e '^2') + then + python3 ${OH_MY_COMMA_PATH}/emu.py "$@" + else + python ${OH_MY_COMMA_PATH}/emu.py "$@" fi - if [ $1 = "update" ]; then + if [ $? = 1 ] && [ "$1" = "update" ]; then # fallback to updating immediately if CLI crashed updating + printf "\033[91mAn error occurred in the Python CLI, attempting to manually update .oh-my-comma...\n" + printf "Press Ctrl+C to cancel!\033[0m\n" + sleep 5 _updateohmycomma - elif [ $1 = "pandaflash" ]; then - _pandaflash - elif [ $1 = "pandaflash2" ]; then - _pandaflash2 - elif [ $1 = "installfork" ]; then - _installfork $2 - elif [ $1 = "debug" ]; then - _debug $2 - else - printf "Unsupported command! Try one of these:" - printf '%s\n' "$commands" fi } diff --git a/emu.py b/emu.py new file mode 100644 index 00000000..ca9aabb6 --- /dev/null +++ b/emu.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +if __package__ is None: + import sys + from os import path + sys.path.append(path.abspath(path.join(path.dirname(__file__), 'py_utils'))) + sys.path.append(path.abspath(path.join(path.dirname(__file__), 'emu_commands'))) + + from py_utils.emu_utils import BaseFunctions + from py_utils.emu_utils import OPENPILOT_PATH + from emu_commands.fork import Fork + from emu_commands.update import Update + from emu_commands.panda import Panda + from emu_commands.debug import Debug + +sys.path.append(OPENPILOT_PATH) # for importlib +DEBUG = not path.exists('/data/params/d') + +class Emu(BaseFunctions): + def __init__(self, args): + self.args = args + self.commands = {'fork': Fork('🍴 control installed forks, or clone a new one'), + 'update': Update('🎉 updates this tool, recommended to restart ssh session'), + 'panda': Panda('🐼 panda interfacing tools'), + 'debug': Debug('de-🐛-ing tools')} + self.parse() + + def parse(self): + cmd = self.next_arg() + + if cmd is None: + self.print_commands(error_msg='You must specify a command for emu. Some options are:', ascii_art=True) + return + if cmd not in self.commands: + self.print_commands(error_msg='Unknown command! Try one of these:') + return + + self.commands[cmd].main(self.args, cmd) + + +if __name__ == "__main__": + args = sys.argv[1:] + if DEBUG: + args = input().split(' ') + if '' in args: + args.remove('') + emu = Emu(args) diff --git a/emu_commands/base.py b/emu_commands/base.py new file mode 100644 index 00000000..76f7777d --- /dev/null +++ b/emu_commands/base.py @@ -0,0 +1,78 @@ +from py_utils.colors import COLORS +from py_utils.emu_utils import ArgumentParser, BaseFunctions, warning, success + +class CommandBase(BaseFunctions): + def __init__(self, description): + self.description = description + self.commands = {} + + def main(self, args, cmd_name): + self.args = args + cmd = self.next_arg() + if len(self.commands) > 0: + if cmd is None: + self.print_commands(error_msg='You must specify a command for emu {}. Some options are:'.format(cmd_name)) + return + if cmd not in self.commands: + self.print_commands(error_msg='Unknown command! Try one of these:') + return + self.start_function_from_str(cmd) + else: + self.start_function_from_str(cmd_name) + + def start_function_from_str(self, cmd): + cmd = '_' + cmd + if not hasattr(self, cmd): + print('Command has not been implemented yet, please try updating.') + return + getattr(self, cmd)() # call command's function + + def parse_flags(self, parser): + try: + return parser.parse_args(self.args), None + except Exception as e: + return None, e + + def _help(self, cmd, show_description=True, leading=''): + description = self.commands[cmd].description + if show_description: + print('{}>> Description 📚: {}{}'.format(COLORS.CYAN, description, COLORS.ENDC)) + + flags = self.commands[cmd].flags + + flags_to_print = [] + if flags is not None and len(flags) > 0: + print(leading + '{}>> Flags 🎌:{}'.format(COLORS.WARNING, COLORS.ENDC)) + for flag in flags: + aliases = COLORS.SUCCESS + ', '.join(flag.aliases) + COLORS.WARNING + flags_to_print.append(leading + COLORS.WARNING + ' - {}: {}'.format(aliases, flag.description) + COLORS.ENDC) + print('\n'.join(flags_to_print)) + + commands = self.commands[cmd].commands + cmds_to_print = [] + if commands is not None and len(commands) > 0: + print(leading + '{}>> Commands 💻:{}'.format(COLORS.OKGREEN, COLORS.ENDC)) + for cmd in commands: + cmds_to_print.append(leading + COLORS.FAIL + ' - {}: {}'.format(cmd, success(commands[cmd].description, ret=True)) + COLORS.ENDC) + print('\n'.join(cmds_to_print)) + +class Flag: + def __init__(self, aliases, description, has_value=False): + self.aliases = aliases + self.description = description + self.has_value = has_value + +class Command: + def __init__(self, description=None, commands=None, flags=None): + self.parser = ArgumentParser() + self.description = description + self.commands = commands + self.has_flags = False + self.flags = flags + if flags is not None: + self.has_flags = True + for flag in flags: + # for each flag, add it as argument with aliases. + # if flag.has_value, parse value as string, if not, assume flag is boolean + action = 'store_true' if not flag.has_value else None + self.parser.add_argument(*flag.aliases, help=flag.description, action=action) diff --git a/emu_commands/debug.py b/emu_commands/debug.py new file mode 100644 index 00000000..d536f6ee --- /dev/null +++ b/emu_commands/debug.py @@ -0,0 +1,25 @@ +from emu_commands.base import CommandBase, Command, Flag +from py_utils.emu_utils import run, kill, warning, error +from py_utils.emu_utils import OPENPILOT_PATH + +class Debug(CommandBase): + def __init__(self, description): + super().__init__(description) + self.commands = {'controlsd': Command(description='🔬 logs controlsd to /data/output.log by default', + flags=[Flag(['-o', '--output'], 'Name of file to save log to', has_value=True)])} + self.default_path = '/data/output.log' + + def _controlsd(self): + flags, e = self.parse_flags(self.commands['controlsd'].parser) + if e is not None: + error(e) + return + + out_file = self.default_path + if flags.output is not None: + out_file = flags.output + # r = run('pkill -f controlsd') # terminates file for some reason # todo: remove me if not needed + r = kill('selfdrive.controls.controlsd') # seems to work, some process names are weird + if r is None: + warning('controlsd is already dead! (continuing...)') + run('python {}/selfdrive/controls/controlsd.py'.format(OPENPILOT_PATH), out_file=out_file) diff --git a/emu_commands/fork.py b/emu_commands/fork.py new file mode 100644 index 00000000..c4eb5354 --- /dev/null +++ b/emu_commands/fork.py @@ -0,0 +1,78 @@ +import shutil +from os import path +from emu_commands.base import CommandBase, Command, Flag +from py_utils.emu_utils import run, error, warning, success, verify_fork_url, is_affirmative +from py_utils.emu_utils import OPENPILOT_PATH + +class Fork(CommandBase): + def __init__(self, description): + super().__init__(description) + self.commands = {'install': Command(description='🦉 Whoooose fork do you wanna install?', + flags=[Flag(['clone_url'], '🍴 URL of fork to clone', has_value=True), + Flag(['-l', '--lite'], '💡 Clones only the default branch with all commits flattened for quick cloning'), + Flag(['-b', '--branch'], '🌿 Specify the branch to clone after this flag', has_value=True)])} + + def _install(self): + if self.next_arg(ingest=False) is None: + error('You must supply command arguments!') + self._help('install') + return + + flags, e = self.parse_flags(self.commands['install'].parser) + if e is not None: + error(e) + return + + if flags.clone_url is None: + error('You must specify a fork URL to clone!') + return + if not verify_fork_url(flags.clone_url): # verify we can clone before moving folder! + error('The specified fork URL is not valid!') + return + + OPENPILOT_TEMP_PATH = '{}.temp'.format(OPENPILOT_PATH) + if path.exists(OPENPILOT_TEMP_PATH): + warning('{} already exists, should it be deleted to continue?'.format(OPENPILOT_TEMP_PATH)) + if is_affirmative(): + shutil.rmtree(OPENPILOT_TEMP_PATH) + else: + error('Exiting...') + return + + # Clone fork to temp folder + warning('Fork will be installed to {}'.format(OPENPILOT_PATH)) + clone_flags = [] + if flags.lite: + warning('- Performing a lite clone! (--depth 1)') + clone_flags.append('--depth 1') + if flags.branch is not None: + warning('- Only cloning branch: {}'.format(flags.branch)) + clone_flags.append('-b {} --single-branch'.format(flags.branch)) + if len(clone_flags): + clone_flags.append('') + try: # catch ctrl+c and clean up after + r = run('git clone {}{} {}'.format(' '.join(clone_flags), flags.clone_url, OPENPILOT_TEMP_PATH)) # clone to temp folder + except: + r = False + + # If openpilot.bak exists, determine a good non-exiting path + # todo: make a folder that holds all installed forks and provide an interface of switching between them + bak_dir = '{}.bak'.format(OPENPILOT_PATH) + bak_count = 0 + while path.exists(bak_dir): + bak_count += 1 + bak_dir = '{}.{}'.format(bak_dir, bak_count) + + if r: + success('Cloned successfully! Installing fork...') + if path.exists(OPENPILOT_PATH): + shutil.move(OPENPILOT_PATH, bak_dir) # move current installation to old dir + shutil.move(OPENPILOT_TEMP_PATH, OPENPILOT_PATH) # move new clone temp folder to main installation dir + success("Installed! Don't forget to restart your device") + else: + error('\nError cloning specified fork URL!', end='') + if path.exists(OPENPILOT_TEMP_PATH): # git usually does this for us + error(' Cleaning up...') + shutil.rmtree(OPENPILOT_TEMP_PATH) + else: + print() diff --git a/emu_commands/panda.py b/emu_commands/panda.py new file mode 100644 index 00000000..2d35a24f --- /dev/null +++ b/emu_commands/panda.py @@ -0,0 +1,20 @@ +import importlib +from emu_commands.base import CommandBase, Command +from py_utils.emu_utils import run, error +from py_utils.emu_utils import OPENPILOT_PATH + +class Panda(CommandBase): + def __init__(self, description): + super().__init__(description) + self.commands = {'flash': Command(description='🐼 flashes panda with make recover (usually works with the C2)'), + 'flash2': Command(description='🎍 flashes panda using Panda module (usually works with the EON)')} + + def _flash(self): + r = run('make -C {}/panda/board recover'.format(OPENPILOT_PATH)) + if not r: + error('Error running make command!') + + def _flash2(self): + if not run('pkill -f boardd'): + error('Error killing boardd! Is it running? (continuing...)') + importlib.import_module('panda', 'Panda').Panda().flash() diff --git a/emu_commands/update.py b/emu_commands/update.py new file mode 100644 index 00000000..01e1a01f --- /dev/null +++ b/emu_commands/update.py @@ -0,0 +1,11 @@ +from emu_commands.base import CommandBase +from py_utils.emu_utils import run, error +from py_utils.emu_utils import UPDATE_PATH + +class Update(CommandBase): + def __init__(self, description): + super().__init__(description) + + def _update(self): + if not run(['sh', UPDATE_PATH]): + error('Error updating!') diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 29745f3f..1576e54b --- a/install.sh +++ b/install.sh @@ -3,45 +3,41 @@ SYSTEM_BASHRC_PATH=/home/.bashrc COMMUNITY_PATH=/data/community COMMUNITY_BASHRC_PATH=/data/community/.bashrc OH_MY_COMMA_PATH=/data/community/.oh-my-comma +OH_MY_COMMA_PATH=/data/community/.oh-my-comma +OMC_VERSION=0.1.0 update=false if [ $# -ge 1 ] && [ $1 = "update" ]; then update=true fi -if [ "$(cd ${OH_MY_COMMA_PATH} && git rev-parse --abbrev-ref HEAD)" != "master" ]; then - printf "\n\033[0;31mWarning:\033[0m your current .oh-my-comma git branch is $(cd ${OH_MY_COMMA_PATH} && git rev-parse --abbrev-ref HEAD). Run cd /data/community/.oh-my-comma && git checkout master if this is unintentional\n" -fi - -if [ ! update ]; then - [ "$DEBUG" == 'true' ] && set -x +if [ $update = false ]; then + [[ "$DEBUG" == 'true' ]] && set -x fi if [ ! -d "/data/community" ]; then mkdir /data/community fi -cd /data/community - if [ ! -d "$OH_MY_COMMA_PATH" ]; then echo "Cloning..." - git clone -b master https://github.com/emu-sh/.oh-my-comma.git + git clone -b master https://github.com/emu-sh/.oh-my-comma.git ${OH_MY_COMMA_PATH} fi -cd ${OH_MY_COMMA_PATH} - if [ ! -x "$(command -v powerline-shell)" ] && [ $update = false ]; then echo "Do you want to install powerline? [You will also need to install the fonts on your local terminal.]" read -p "[Y/n] > " choices - case $choices in + case ${choices} in y|Y ) pip install powerline-shell;; * ) echo "Skipping...";; esac fi -echo "Installing emu utilities..." +if [ $update = true ]; then + echo "Installing emu utilities..." +fi -echo "Remounting /system as rewritable (until neos 15)" +echo "Remounting /system as rewritable (until NEOS 15)" mount -o rw,remount /system if [ -f "$SYSTEM_BASHRC_PATH" ]; then @@ -50,8 +46,8 @@ if [ -f "$SYSTEM_BASHRC_PATH" ]; then then echo "Found an entry point point for ${COMMUNITY_BASHRC_PATH} in ${SYSTEM_BASHRC_PATH}, skipping changes to /system" else - echo "Your bashrc file is different than the one on the repo. neos 15 will redirect all users to store their bashrc in /data/community" - echo "moving your current bashrc to /data/community" + echo "Your bashrc file is different than the one on the repo. NEOS 15 will redirect all users to store their bashrc in /data/community" + echo "Moving your current bashrc to /data/community" mv ${SYSTEM_BASHRC_PATH} ${COMMUNITY_BASHRC_PATH} echo "Copying .bashrc that sources local bashrc to system partition (wont be needed in neos 15)" cp ${OH_MY_COMMA_PATH}/default-bashrcs/.bashrc-system ${SYSTEM_BASHRC_PATH} @@ -97,19 +93,21 @@ if [ $update = false ]; then printf "End of $COMMUNITY_BASHRC_PATH\n" fi -echo "Sourcing /home/.bashrc to init the changes made during installation" -source /home/.bashrc +printf "\033[92m" if [ $update = true ]; then printf "\nSuccessfully updated emu utilities!\n" else - printf "\nSuccessfully installed emu utilities!\n" + echo "Sourcing /home/.bashrc to apply the changes made during installation" + source /home/.bashrc + printf "\nSuccessfully installed emu utilities\n" + printf "You may need to run the following to reflect the update:\n source ${OH_MY_COMMA_PATH}/emu-utils.sh" fi - +echo "Current version: $OMC_VERSION" +printf "\033[0m" if [ "$(cd ${OH_MY_COMMA_PATH} && git rev-parse --abbrev-ref HEAD)" != "master" ]; then printf "\n\033[0;31mWarning:\033[0m your current .oh-my-comma git branch is $(git rev-parse --abbrev-ref HEAD). Run cd /data/community/.oh-my-comma && git checkout master if this is unintentional\n" fi - -if [ ! update ]; then +if [ $update = false ]; then set +x fi diff --git a/py_utils/colors.py b/py_utils/colors.py new file mode 100644 index 00000000..a61a025c --- /dev/null +++ b/py_utils/colors.py @@ -0,0 +1,22 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +class COLORS: + # HEADER = '\033[95m' + OKBLUE = '\033[94m' + CBLUE = '\33[44m' + # BOLD = '\033[1m' + OKGREEN = '\033[92m' + CWHITE = '\33[37m' + ENDC = '\033[0m' + CWHITE + UNDERLINE = '\033[4m' + + RED = '\033[91m' + PURPLE_BG = '\33[45m' + YELLOW = '\033[93m' + + FAIL = RED + INFO = PURPLE_BG + SUCCESS = OKGREEN + PROMPT = YELLOW + CYAN = '\033[36m' + WARNING = '\033[33m' diff --git a/py_utils/emu_utils.py b/py_utils/emu_utils.py new file mode 100644 index 00000000..5c9a33c0 --- /dev/null +++ b/py_utils/emu_utils.py @@ -0,0 +1,151 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import psutil +import requests +import argparse +import subprocess +import sys +if __package__ is None: + from os import path + sys.path.append(path.abspath(path.join(path.dirname(__file__), '../py_utils'))) + from py_utils.colors import COLORS +else: + from py_utils.colors import COLORS + +SYSTEM_BASHRC_PATH = '/home/.bashrc' +COMMUNITY_PATH = '/data/community' +COMMUNITY_BASHRC_PATH = '/data/community/.bashrc' +OH_MY_COMMA_PATH = '/data/community/.oh-my-comma' +UPDATE_PATH = '{}/update.sh'.format(OH_MY_COMMA_PATH) +OPENPILOT_PATH = '/data/openpilot' + + +class ArgumentParser(argparse.ArgumentParser): + def error(self, message): + raise Exception('error: {}'.format(message)) + + +class BaseFunctions: + def print_commands(self, error_msg=None, ascii_art=False): + if ascii_art: + print(EMU_ART) + + if error_msg is not None: + error(error_msg) + max_cmd = max([len(_c) for _c in self.commands]) + 1 + for idx, cmd in enumerate(self.commands): + desc = COLORS.CYAN + self.commands[cmd].description + print(COLORS.OKGREEN + ('- {:<%d} {}' % max_cmd).format(cmd + ':', desc)) + if hasattr(self, '_help'): + # leading is for better differentiating between the different commands + self._help(cmd, show_description=False, leading='') # todo: decide if leading is better than no leading + if idx < len(self.commands) - 1: # removes double newlines at end of loop + print() + print(COLORS.ENDC) + + def next_arg(self, lower=True, ingest=True): + """ + Returns next arg and deletes arg from self.args if ingest=True + :param lower: Returns arg.lower() + :param ingest: Deletes returned arg from self.arg + :return: + """ + if len(self.args): + arg = self.args[0] + if lower: + arg = arg.lower() + if ingest: + del self.args[0] + else: + arg = None + return arg + + +def run(cmd, out_file=None): + """ + If cmd is a string, it is split into a list, otherwise it doesn't modify cmd. + The status is returned, True being success, False for failure + """ + if isinstance(cmd, str): + cmd = cmd.split() + + f = None + if isinstance(out_file, str): + f = open(out_file, 'a') + + try: + r = subprocess.call(cmd, stdout=f) + return not r + except Exception as e: + print(e) + return False + + +def kill(procname): + for proc in psutil.process_iter(): + # check whether the process name matches + if proc.name() == procname: + proc.kill() + return True + return None + + +def is_affirmative(): + i = None + print(COLORS.PROMPT) + while i not in ['y', 'n', 'yes', 'no']: + i = input('[Y/n]: ').lower().strip() + print(COLORS.ENDC) + return i in ['y', 'yes'] + + +def error(msg, end='\n', ret=False): + """ + The following applies to error, warning, and success methods + :param msg: The message to display + :param end: The ending char, default is \n + :param ret: Whether to return the formatted string, or print it + :return: The formatted string if ret is True + """ + e = '{}{}{}'.format(COLORS.FAIL, msg, COLORS.ENDC) + if ret: + return e + print(e, end=end) + + +def warning(msg, end='\n', ret=False): + w = '{}{}{}'.format(COLORS.WARNING, msg, COLORS.ENDC) + if ret: + return w + print(w, end=end) + + +def success(msg, end='\n', ret=False): + s = '{}{}{}'.format(COLORS.SUCCESS, msg, COLORS.ENDC) + if ret: + return s + print(s, end=end) + + +def verify_fork_url(url): + if url[:4].lower() != 'http': + url = 'http://' + url + try: + return requests.get(url).status_code == 200 + except: + return False + + +EMU_ART = r""" _ + -=(""" + COLORS.RED + """'""" + COLORS.CWHITE + """) + ;; + // + // + : '.---.__ + | --_-_)__) + `.____,' + \ \ """ + COLORS.OKGREEN + """ ___ ._ _ _ _ _ """ + COLORS.CWHITE + """ + ___\ \ """ + COLORS.OKGREEN + """/ ._>| ' ' || | |""" + COLORS.CWHITE + """ + ( \ """ + COLORS.OKGREEN + """\___.|_|_|_|`___|""" + COLORS.CWHITE + """ + \ + /""" + '\n' diff --git a/update.sh b/update.sh old mode 100644 new mode 100755 index 1d3342e4..2bc46c36 --- a/update.sh +++ b/update.sh @@ -1,3 +1,9 @@ #!/bin/bash -git -C /data/community/.oh-my-comma pull -source ${OH_MY_COMMA_PATH}/install.sh 'update' +SYSTEM_BASHRC_PATH=/home/.bashrc +COMMUNITY_PATH=/data/community +COMMUNITY_BASHRC_PATH=/data/community/.bashrc +OH_MY_COMMA_PATH=/data/community/.oh-my-comma + +git -C ${OH_MY_COMMA_PATH} pull +sh ${OH_MY_COMMA_PATH}/install.sh 'update' +printf "You may need to run the following to reflect the update:\nsource ${OH_MY_COMMA_PATH}/emu-utils.sh\n\n"