def __prune_remote_branches( self, username): # remove deleted remote branches locally last_prune = self.fork_params.get('last_prune') if isinstance(last_prune, str) and datetime.now().strftime("%d") == last_prune: return self.fork_params.put('last_prune', datetime.now().strftime("%d")) r = check_output([ 'git', '-C', OPENPILOT_PATH, 'remote', 'prune', username, '--dry-run' ]) if r.output == '': # nothing to prune return branches_to_prune = [ b.strip() for b in r.output.split('\n') if 'would prune' in b ] branches_to_prune = [b[b.index(username):] for b in branches_to_prune] error('Deleted remote branches detected:', start='\n') for b in branches_to_prune: print(COLORS.CYAN + ' - {}'.format(b) + COLORS.ENDC) warning('\nWould you like to delete them locally?') if is_affirmative(): r = check_output( ['git', '-C', OPENPILOT_PATH, 'remote', 'prune', username]) if r.success: success('Pruned local branches successfully!') else: error('Please try again, something went wrong:') print(r.output)
def _shutdown(self): flags = self.get_flags('shutdown') if flags.reboot: self.__reboot() return check_output( 'am start -n android/com.android.internal.app.ShutdownActivity') success('🌙 Goodnight!')
def _settings(self): flags = self.get_flags('settings') if flags.close: check_output('kill $(pgrep com.android.settings)', shell=True) success('⚙️ Closed settings!') else: check_output('am start -a android.settings.SETTINGS') success('⚙️ Opened settings!')
def _shutdown(self): flags, e = self.parse_flags(self.commands['shutdown'].parser) if e is not None: error(e) self._help('shutdown') return if flags.reboot: self.__reboot() return check_output( 'am start -n android/com.android.internal.app.ShutdownActivity') success('🌙 Goodnight!')
def _reload(): info('This will kill the current openpilot tmux session, set up a new one, and relaunch openpilot.') info('Confirm you would like to continue') if not is_affirmative(): error('Aborting!') return r = check_output('tmux kill-session -t comma') if r.success: info('Killed the current openpilot session') else: warning('Error killing current openpilot session, continuing...') # Command below thanks to mlp r = check_output(['tmux', 'new', '-s', 'comma', '-d', "echo $$ > /dev/cpuset/app/tasks;" # add pid of current shell to app cpuset "echo $PPID > /dev/cpuset/app/tasks;" # (our parent, tmux, also gets all the cores) "/data/openpilot/launch_openpilot.sh"]) if r.success: success('Succesfully started a new tmux session for openpilot!') success('Type {}tmux a{} to attach to it'.format(COLORS.FAIL, COLORS.SUCCESS))
def _list(self): if not self._init(): return flags = self.get_flags('list') specified_fork = flags.fork installed_forks = self.fork_params.get('installed_forks') if specified_fork is None: max_branches = 4 # max branches to display per fork when listing all forks success('Installed forks:') for idi, fork in enumerate(installed_forks): print('- {}{}{}'.format(COLORS.OKBLUE, fork, COLORS.ENDC), end='') current_fork = self.fork_params.get('current_fork') if current_fork == fork: print(' (current)') else: print() branches = installed_forks[fork]['installed_branches'] current_branch = self.fork_params.get('current_branch') if current_branch in branches: branches.remove(current_branch) branches.insert( 0, current_branch) # move cur_branch to beginning if len(branches) > 0: success(' Branches:') for idx, branch in enumerate(branches): if idx < max_branches: print(' - {}{}{}'.format(COLORS.RED, branch, COLORS.ENDC), end='') if branch == current_branch and fork == current_fork: print(' (current)') else: print() else: print( ' - {}...see more branches: {}emu fork list {}{}' .format(COLORS.RED, COLORS.CYAN, fork, COLORS.ENDC)) break print() else: specified_fork = specified_fork.lower() remote_info = self.__get_remote_info(specified_fork) if remote_info is not None: # there's an overriding default username available specified_fork = remote_info.username if specified_fork not in installed_forks: error( '{} not an installed fork! Try installing it with the {}switch{} command' .format(specified_fork, COLORS.CYAN, COLORS.RED)) return installed_branches = installed_forks[specified_fork][ 'installed_branches'] success('Installed branches for {}:'.format(specified_fork)) for branch in installed_branches: print(' - {}{}{}'.format(COLORS.RED, branch, COLORS.ENDC))
def _battery(): r = check_output('dumpsys batterymanager') if not r: error('Unable to get battery status!') return r = r.output.split('\n') r = [i.strip() for i in r if i != ''][1:] battery_idxs = {'level': 7, 'temperature': 10} success('Battery info:') for name in battery_idxs: idx = battery_idxs[name] info = r[idx] value = float(info.split(': ')[1]) if name == 'temperature': value /= 10 value = str(value) + '°C' else: value = str(value) + '%' value = COLORS.SUCCESS + str(value) name = COLORS.WARNING + name.title() print('- {}: {}{}'.format(name, value, COLORS.ENDC))
def _help(self, cmd, show_description=True, leading=''): has_extra_info = False 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: has_extra_info = True 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 usage_flags = [f.aliases for f in flags if not f.required and len(f.aliases) > 1 or f.aliases[0].startswith('-')] # if flag 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] if len(usage_flags): # formats flags to: "[-b BRANCH, -o OUTPUT]" usage_flags = ['{} {}'.format(min(u, key=len), max(u, key=len).upper()[2:]) for u in usage_flags] usage_flags = ['[{}]'.format(', '.join(usage_flags))] usage = ['emu', self.name, cmd] + usage_req + usage_non_req + usage_flags 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)) 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)) return has_extra_info
def __reboot(): check_output('am start -a android.intent.action.REBOOT') success('👋 See you in a bit!')
def _init(self): if os.path.isdir('/data/community/forks'): shutil.rmtree('/data/community/forks') # remove to save space if self.fork_params.get('setup_complete'): if os.path.exists(OPENPILOT_PATH): r = check_output( ['git', '-C', OPENPILOT_PATH, 'remote', 'show']) if self.comma_origin_name in r.output.split( '\n' ): # sign that we're set up correctly todo: check all forks exist as remotes return True self.fork_params.put( 'setup_complete', False ) # renamed origin -> commaai does not exist, restart setup self.fork_params.reset() warning( 'There was an error with your clone of commaai/openpilot, restarting initialization!' ) info( 'To set up emu fork management we will clone commaai/openpilot into {}' .format(OPENPILOT_PATH)) info('Confirm you would like to continue') if not is_affirmative(): error('Stopping initialization!') return # backup openpilot here to free up /data/openpilot if os.path.exists(OPENPILOT_PATH): bak_dir = '{}.bak'.format(OPENPILOT_PATH) idx = 0 while os.path.exists(bak_dir): bak_dir = '{}{}'.format(bak_dir, idx) idx += 1 shutil.move(OPENPILOT_PATH, bak_dir) success('Backed up your current openpilot install to {}'.format( bak_dir)) info('Cloning commaai/openpilot into {}, please wait...'.format( OPENPILOT_PATH)) r = run([ 'git', 'clone', '-b', self.comma_default_branch, GIT_OPENPILOT_URL, OPENPILOT_PATH ]) # default to stock/release2 for setup if not r: error('Error while cloning, please try again') return # rename origin to commaai so it's easy to switch to stock without any extra logic for url checking, etc r = check_output([ 'git', '-C', OPENPILOT_PATH, 'remote', 'rename', 'origin', self.comma_origin_name ]) if not r.success: error(r.output) return # rename release2 to commaai_release2 to align with emu fork standards r = check_output([ 'git', '-C', OPENPILOT_PATH, 'branch', '-m', f'{self.comma_origin_name}_{self.comma_default_branch}' ]) if not r.success: error(r.output) return # set git config push.default to `upstream` to remove differently named remote branch warning when pushing check_output([ 'git', '-C', OPENPILOT_PATH, 'config', 'push.default', 'upstream' ]) # not game breaking if this fails # remember username and password of user for pushing check_output([ 'git', '-C', OPENPILOT_PATH, 'config', 'credential.helper', 'cache --timeout=1440' ]) # cache for a day success('Fork management set up successfully! You\'re on {}/{}'.format( self.comma_origin_name, self.comma_default_branch)) success( 'To get started, try running: {}emu fork switch (username) [-b BRANCH]{}' .format(COLORS.RED, COLORS.ENDC)) self.__add_fork(self.comma_origin_name, self.comma_default_branch) self.fork_params.put('setup_complete', True) self.fork_params.put('current_fork', self.comma_origin_name) self.fork_params.put('current_branch', self.comma_default_branch) return True
def _switch(self): if not self._init(): return flags = self.get_flags('switch') if flags.username is flags.branch is None: # since both are non-required we need custom logic to check user supplied sufficient args/flags error('You must supply either username or branch or both') self._help('switch') return username = flags.username branch = flags.branch repo_name = flags.repo force_switch = flags.force if username is None: # branch is specified, so use current checked out fork/username _current_fork = self.fork_params.get('current_fork') if _current_fork is not None: # ...if available info('Assuming current fork for username: {}'.format( COLORS.SUCCESS + _current_fork + COLORS.ENDC)) username = _current_fork else: error( 'Current fork is unknown, please switch to a fork first before switching between branches!' ) return username = username.lower() remote_info = self.__get_remote_info(username) if remote_info is not None: # user entered an alias (ex. stock, dragonpilot) username = remote_info.username installed_forks = self.fork_params.get('installed_forks') fork_in_params = True if username not in installed_forks: fork_in_params = False if remote_info is not None: remote_url = f'https://github.com/{username}/{remote_info.fork_name}' # dragonpilot doesn't have a GH redirect else: # for most forks, GH will redirect from /openpilot if user renames fork if repo_name is None: repo_name = DEFAULT_REPO_NAME # openpilot remote_url = f'https://github.com/{username}/{repo_name}' if not valid_fork_url(remote_url): error('Invalid username{}! {} does not exist'.format( '' if flags.repo is None else ' or repository name', remote_url)) return r = check_output([ 'git', '-C', OPENPILOT_PATH, 'remote', 'add', username, remote_url ]) if r.success and r.output == '': success('Remote added successfully!') elif r.success and REMOTE_ALREADY_EXISTS in r.output: # remote already added, update params info('Fork exists but wasn\'t in params, updating now...') self.__add_fork(username) else: error(r.output) return # fork has been added as a remote, switch to it if fork_in_params: info('Fetching {}\'s latest changes...'.format(COLORS.SUCCESS + username + COLORS.WARNING)) else: info('Fetching {}\'s fork, this may take a sec...'.format( COLORS.SUCCESS + username + COLORS.WARNING)) r = run(['git', '-C', OPENPILOT_PATH, 'fetch', username]) if not r: error('Error while fetching remote, please try again') return self.__add_fork(username) self.__prune_remote_branches(username) r = check_output( ['git', '-C', OPENPILOT_PATH, 'remote', 'show', username]) remote_branches, default_remote_branch = self.__get_remote_branches(r) if remote_branches is None: return if DEFAULT_BRANCH_START not in r.output: error('Error: Cannot find default branch from fork!') return if branch is None: # user hasn't specified a branch, use remote's default branch if remote_info is not None: # there's an overriding default branch specified remote_branch = remote_info.default_branch local_branch = '{}_{}'.format(remote_info.username, remote_branch) else: remote_branch = default_remote_branch # for command to checkout correct branch from remote, branch is previously None since user didn't specify local_branch = '{}_{}'.format(username, default_remote_branch) else: if branch not in remote_branches: close_branches = most_similar( branch, remote_branches ) # remote_branches is gauranteed to have at least 1 branch if close_branches[0][1] > 0.5: branch = close_branches[0][0] info( 'Unknown branch, checking out most similar: {}'.format( COLORS.SUCCESS + branch + COLORS.WARNING)) else: error('The branch you specified does not exist!') self.__show_similar_branches( branch, remote_branches) # if possible return remote_branch = branch # branch is now gauranteed to be in remote_branches local_branch = f'{username}_{branch}' # checkout remote branch and prepend username so we can have multiple forks with same branch names locally if remote_branch not in installed_forks[username][ 'installed_branches']: info('New branch! Tracking and checking out {} from {}'.format( local_branch, f'{username}/{remote_branch}')) command = [ 'git', '-C', OPENPILOT_PATH, 'checkout', '--track', '-b', local_branch, f'{username}/{remote_branch}' ] else: # already installed branch, checking out fork_branch from f'{username}/{branch}' command = ['git', '-C', OPENPILOT_PATH, 'checkout', local_branch] if force_switch: command.append('-f') r = run(command) if not r: error( 'Error while checking out branch, please try again or use flag --force' ) return self.__add_branch( username, remote_branch ) # we can deduce fork branch from username and original branch f({username}_{branch}) # reset to remote/branch just to ensure we checked out fully. if remote branch has been force pushed, this will also reset local to remote r = check_output([ 'git', '-C', OPENPILOT_PATH, 'reset', '--hard', f'{username}/{remote_branch}' ]) if not r.success: error(r.output) return reinit_subs = self.__init_submodules() self.fork_params.put('current_fork', username) self.fork_params.put('current_branch', remote_branch) info('\n✅ Successfully checked out {}/{} as {}'.format( COLORS.SUCCESS + username, remote_branch + COLORS.WARNING, COLORS.SUCCESS + local_branch)) if reinit_subs: success('✅ Successfully reinitialized submodules!')
def _settings(): check_output('am start -a android.settings.SETTINGS') success('⚙️ Opened settings!')