Skip to content

Commit

Permalink
Fork manager (#32)
Browse files Browse the repository at this point in the history
* test clone now

* quick clone

* update switch command

* update switch command

* hopefully this should allow for optional args

* test

* flag rewrite

* disable all commands but fork

* debug

* whoops

* whoops

* this should be good, default to bool

* clean ups

* test help

* test

* test a fix

* test a fix

* debug

* debug

* debug

* debug

* debug

* debug

* duh

* fix?

* fix?

* fix?

* works, this should clean it up a bit

* test to see if this works as expected

* is this better?

* is this better?

* is this better?

* duh

* duh

* fix

* wrong

* just add an exception lol

* fix

* start to add some logic

* fix

* fix

* fix

* debug

* debug

* debug

* debug

* debug

* debug

* debug

* debug

* debug

* debug

* check url first since remote add doesn't actually check if remote url is good

* check url first since remote add doesn't actually check if remote url is good

* temp for debugging

* debug

* debug

* fix

* fix

* fix

* fix

* test

* see if this is faster

* see if this is faster

* updates

* fix

* debug

* debug

* debug

* debug

* debug

* fix

* fix

* fix

* debug

* debug

* track already checked out branches

* logic to checkout remote branches with custom names

* fix

* another fix

* update params

* i wasn't wrong

* simplify

* minor clean up

* changes

* remove

* remove ...

* remove ...

* fix

* revert temp test

* remove install command

* temp

* okay, revert

* some message updates

* start to check branch before

* debug

* debug

* debug

* debug

* debug

* debug

* debug

* debug

* debug

* fix

* move to class function

* move to class function

* debug

* print close branches

* print close branches

* print close branches

* print close branches

* debug close branches

* debug close branches

* lol can't believe i used format

* debug

* debug

* debug

* debug

* debug

* debug

* debug

* some clean up, move did you mean to a function

* debug

* fix

* rename origin to commaai, simplify errors with check_output

* spacing

* fix

* add origin as alias

* show

* fix key error

* debug

* full depth cloning

* clean up, remove debugging prints

* create symlink test

* create symlink test

* fix

* move instead

* add shutdown command

* update emoji

* fix

* remove fix, it's fixed

* update with msg

* update msg

* better

* add msg

* add commaai to forks.json

* ugh, debug

* more debugging

* debug

* debug

* think this is the issue

* remove debug

* niceties

* add list command

* print branches

* add help for switch

* formatting

* formatting

* formatting

* print clone output

* fix

* argument with 💢

* fix fork list

* one more branch

* display command to run

* color formatting

* color formatting

* switch to release2 by default after initalization

* add args to list cmd

* add args to list cmd

* add option to specify fork

* add colors and check that fork is installed

* add alias for stock

* add all commands back

* fix syntax since I changed flag class

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* test dynamic loading

* dynamic loading should be finished

* test error now

* test error now

* fix error

* test error

* if only fixing errors was this easy

* test

* test

* test

* test

* test

* test

* should work?

* should work!

* move all commands, test to see what happens if i don't rename uninstall

* okay, moved all commands

* rename emu_commands > commands

* add CHANGELOG.md

* update changelog

* remove bullet

* add dynamic loading

* sub bullets

* update a few descriptions, not done with readme yet

* test adding an optional descriptor to flags

* add warning after optional

* revert, optional should be red?

* debug

* this should work? maybe?

* ayy lmao it works

* might as well print newline at end too

* update readme with better command formatting

* does this look better?

* nah

* test new link

* this should link correctly

* move the more dense command docs to commands/README.md

* add fork management header

* lol

* two spaces indentation ftw

* debug

* only allow dir modules that aren't pycache

* default to release2 for commaai

* start to add usage

* start to add usage

* start to add usage

* this should be close

* this should be close

* test

* test

* test

* test

* test

* test

* oh duhhhhhhhhhh

* so this should work?

* no, but this should

* just so pycharm is happy

* yay!

* would this be too much?

* let's just leave it for now

* check that the appropriate symlink is found
  • Loading branch information
sshane authored Jul 6, 2020
1 parent cd2c63e commit 67faabd
Show file tree
Hide file tree
Showing 16 changed files with 480 additions and 136 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Release 0.1.3 (2020-07-06)
=====
* Make flags/arguments more robust. Optional non-positional arguments are now supported, as long as they are the last arguments.
* `emu fork switch` and `emu fork list` commands added. Uses one singular git repo and adds remotes of forks so that the time to install a new fork is reduced significantly since git is able to re-use blobs.
* A one-time setup is required when using the fork command, this full clones commaai/openpilot which may take a bit of time on first use.
* Change remote of `origin` to `commaai` so that no additional logic is required. Aliases of stock openpilot are: `['stock', 'commaai', 'origin']`
* Stores all installed forks and forks' branches in `/data/community/forks/forks.json` so that the forks command can easily identify when it needs to track and create a branch or just check it out.
* You should still run `git pull` to make sure you get the latest updates from the fork you're currently switched to.
* Dynamic loading of commands. If a command has an exception loading, it won't crash the CLI. Instead you will see an error when you try to call `emu`
34 changes: 21 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,32 @@ This will essentially perform a git pull and replace all current files in the `/
# Commands

### General

- `emu fork`: 🍴 manage installed forks, or clone a new one
- `install`: Clones a fork URL to `/data/openpilot`. Current folder is moved to `/data/openpilot.old` after cloning
- `emu update`: 🎉 updates this tool
- `emu info`: 📈 Statistics about your device
- `battery`: 🔋 see information about the state of your battery
- `emu update`: 🎉 Updates this tool, recommended to restart ssh session
- `emu uninstall`: 👋 Uninstalls emu

### [Forks](#fork-management)
- `emu fork`: 🍴 Manage installed forks, or install a new one
- `emu fork switch`: 🍴 Switch between any openpilot fork
- `emu fork list`: 📜 See a list of installed forks and branches
### Panda

- `emu panda`: 🐼 panda interfacing tools
- `flash`: 🐼 flashes panda with make recover (usually works with the C2)
- `flash2`: 🎍 flashes panda using Panda module (usually works with the EON)

- `emu panda flash`: 🐼 flashes panda with make recover (usually works with the C2)
- `emu panda flash2`: 🎍 flashes panda using Panda module (usually works with the EON)
### Debugging

- `emu debug`: de-🐛-ing tools
- `controlsd`: 🔬 logs controlsd to /data/output.log by default
- `emu debug controlsd`: 🔬 logs controlsd to /data/output.log by default
- `emu device`: 📈 Statistics about your device
- `emu device battery`: 🔋 see information about the state of your battery
- `emu device reboot`: ⚡ safely reboot your device
- `emu device shutdown`: 🔌 safely shutdown your device

To see more information about each command and its arguments, checkout the full [command documentation here.](/commands/README.md)

---

# Fork management
When you first run any `emu fork` command, `emu` will ask you to perform a one-time setup of cloning the base repository of openpilot from commaai. This may take a while, but upon finishing the setup you will be able to switch to any openpilot fork much quicker than the time it usually takes to full-clone a new fork the old fashioned way.

For each new fork you install with the `emu fork switch` command, Git is able to re-use blobs already downloaded from commaai/openpilot and other similar installed forks, enabling quicker install times.

# Git config

Expand Down
34 changes: 34 additions & 0 deletions commands/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Commands

#### `emu fork`:
🍴 Manage installed forks, or install a new one
- `emu fork switch`: 🍴 Switch between any openpilot fork
- Arguments 💢:
- username: 👤 The username of the fork's owner to install
- branch (optional): 🌿 Branch to switch to, will use default branch if not provided
- Example 📚:
- `emu fork switch stock devel`
- `emu fork list`: 📜 See a list of installed forks and branches
- Arguments 💢:
- fork (optional): 🌿 See branches of specified fork
- Example 📚:
- `emu fork list stock`

#### `emu panda`:
🐼 panda interfacing tools
- `emu panda flash`: 🐼 flashes panda with make recover (usually works with the C2)
- `emu panda flash2`: 🎍 flashes panda using Panda module (usually works with the EON)

#### `emu debug`:
de-🐛-ing tools
- `emu debug controlsd`: logs controlsd to /data/output.log by default
- Arguments 💢:
- -o, --output: Name of file to save log to
- Example 📚:
- `emu debug controlsd /data/controlsd_log`

#### `emu device`:
📈 Statistics about your device
- `emu device battery`: 🔋 see information about the state of your battery
- `emu device reboot`: ⚡ safely reboot your device
- `emu device shutdown`: 🔌 safely shutdown your device
16 changes: 16 additions & 0 deletions commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import os
import importlib
from py_utils.emu_utils import error

EMU_COMMANDS = []
basedir = os.path.dirname(__file__)
for module_name in os.listdir(basedir):
if module_name.endswith('.py') or module_name == '__pycache__' or not os.path.isdir(os.path.join(basedir, module_name)):
continue
try:
module = importlib.import_module('commands.{}'.format(module_name))
module = getattr(module, module_name.title())()
EMU_COMMANDS.append(module)
except Exception as e:
error('Error loading {} command, please try updating!'.format(module_name))
error(e)
47 changes: 40 additions & 7 deletions emu_commands/base.py → commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

class CommandBase(BaseFunctions):
def __init__(self):
self.name = ''
self.commands = {}

def main(self, args, cmd_name):
Expand Down Expand Up @@ -41,9 +42,19 @@ def _help(self, cmd, show_description=True, leading=''):

flags_to_print = []
if flags is not None and len(flags) > 0:
print(leading + '{}>> Flags 🎌:{}'.format(COLORS.WARNING, COLORS.ENDC))
usage_req = [f.aliases[0] for f in flags if f.required and len(f.aliases) == 1] # if required
usage_non_req = [f.aliases[0] for f in flags if not f.required and len(f.aliases) == 1] # if non-required non-positional
if len(usage_req) > 0 or len(usage_non_req) > 0: # print usage with proper braces
usage_req = ['[{}]'.format(u) for u in usage_req]
usage_non_req = ['({})'.format(u) for u in usage_non_req]
usage = ['emu', self.name, cmd] + usage_req + usage_non_req
print(leading + COLORS.WARNING + '>> Usage:{} {}'.format(COLORS.OKGREEN, ' '.join(usage)) + COLORS.ENDC)

print(leading + COLORS.WARNING + '>> Arguments 💢:' + COLORS.ENDC)
for flag in flags:
aliases = COLORS.SUCCESS + ', '.join(flag.aliases) + COLORS.WARNING
if not flag.required and '-' not in aliases:
aliases += COLORS.RED + ' (optional)' + COLORS.WARNING
flags_to_print.append(leading + COLORS.WARNING + ' - {}: {}'.format(aliases, flag.description) + COLORS.ENDC)
print('\n'.join(flags_to_print))

Expand All @@ -56,10 +67,16 @@ def _help(self, cmd, show_description=True, leading=''):
print('\n'.join(cmds_to_print))

class Flag:
def __init__(self, aliases, description, has_value=False):
self.aliases = aliases
def __init__(self, aliases, description, required=False, dtype='bool'):
if isinstance(aliases, str):
self.aliases = [aliases]
else:
self.aliases = aliases
self.description = description
self.has_value = has_value
self.required = required
self.dtype = dtype
if self.required and self.aliases[0][0] == '-':
raise Exception('Positional arguments cannot be required!')

class Command:
def __init__(self, description=None, commands=None, flags=None):
Expand All @@ -72,6 +89,22 @@ def __init__(self, description=None, commands=None, flags=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)
parser_args = {} # handle various conditions
if not flag.required and flag.dtype not in ['bool']:
parser_args['nargs'] = '?'

if flag.dtype != 'bool':
parser_args['action'] = 'store'
elif flag.dtype == 'bool':
parser_args['action'] = 'store_true'

if flag.dtype == 'bool': # type bool is not required when store_true
pass
elif flag.dtype == 'str':
parser_args['type'] = str
elif flag.dtype == 'int':
parser_args['type'] = int
else:
error('Unsupported dtype: {}'.format(flag.dtype))
return
self.parser.add_argument(*flag.aliases, help=flag.description, **parser_args)
4 changes: 2 additions & 2 deletions emu_commands/debug.py → commands/debug/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from emu_commands.base import CommandBase, Command, Flag
from commands.base import CommandBase, Command, Flag
from py_utils.emu_utils import run, kill, warning, error
from py_utils.emu_utils import OPENPILOT_PATH

Expand All @@ -9,7 +9,7 @@ def __init__(self):
self.description = 'de-🐛-ing tools'

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)])}
flags=[Flag(['-o', '--output'], 'Name of file to save log to', dtype='str')])}
self.default_path = '/data/output.log'

def _controlsd(self):
Expand Down
10 changes: 7 additions & 3 deletions emu_commands/device.py → commands/device/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from emu_commands.base import CommandBase, Command, Flag
from commands.base import CommandBase, Command, Flag
from py_utils.emu_utils import run, warning, error, check_output, COLORS, success

class Device(CommandBase):
Expand All @@ -8,17 +8,21 @@ def __init__(self):
self.description = '📈 Statistics about your device'

self.commands = {'battery': Command(description='🔋 see information about the state of your battery'),
'reboot': Command(description='🔌 safely reboot your device')}
'reboot': Command(description='⚡ safely reboot your device'),
'shutdown': Command(description='🔌 safely shutdown your device')}

def _reboot(self):
run('am start -a android.intent.action.REBOOT')

def _shutdown(self):
run('am start -n android/com.android.internal.app.ShutdownActivity')

def _battery(self):
r = check_output('dumpsys batterymanager')
if not r:
error('Unable to get battery status!')
return
r = r.decode('utf-8').split('\n')
r = r.output.split('\n')
r = [i.strip() for i in r if i != ''][1:]
battery_idxs = {'level': 7, 'temperature': 10}
success('Battery info:')
Expand Down
Loading

0 comments on commit 67faabd

Please sign in to comment.