-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Start migration over to Python for emu command wrapper (#21)
* 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 <[email protected]> * 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 <[email protected]> Co-authored-by: AskAlice <[email protected]> Co-authored-by: Alice Knag <[email protected]>
- Loading branch information
1 parent
b590892
commit 9eaa44e
Showing
12 changed files
with
476 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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!') |
Oops, something went wrong.