示例#1
0
    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)
示例#2
0
  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.
        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)
示例#3
0
 def get_flags(self, cmd_name):
     try:
         return self.commands[cmd_name].parser.parse_args(self.args)
     except Exception as e:
         error(e)
         self._help(cmd_name)
         exit(1)
示例#4
0
    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))
示例#5
0
    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!')
示例#6
0
    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)
示例#7
0
 def __init_submodules():
     r = check_output(['git', '-C', OPENPILOT_PATH, 'submodule', 'status'])
     if len(r.output):
         info('Submodules detected, reinitializing!')
         r0 = check_output([
             'git', '-C', OPENPILOT_PATH, 'submodule', 'deinit', '--all',
             '-f'
         ])
         r1 = check_output([
             'git', '-C', OPENPILOT_PATH, 'submodule', 'update', '--init',
             '--recursive'
         ])
         if not r0.success or not r1.success:
             error('Error reinitializing submodules for this branch!')
         else:
             return True
     return False
示例#8
0
  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))
示例#9
0
    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))
示例#10
0
    def __get_remote_branches(r):
        # get remote's branches to verify from output of command in parent function
        if not r.success:
            error(r.output)
            return None, None
        if REMOTE_BRANCHES_START in r.output:
            start_remote_branches = r.output.index(REMOTE_BRANCHES_START)
            remote_branches_txt = r.output[start_remote_branches +
                                           len(REMOTE_BRANCHES_START):].split(
                                               '\n')
            remote_branches = []
            for b in remote_branches_txt:
                b = b.replace('tracked', '').strip()
                if 'stale' in b:  # support stale/to-be-pruned branches
                    b = b.split(' ')[0].split('/')[-1]
                if ' ' in b or b == '':  # end of branches
                    break
                remote_branches.append(b)
        elif REMOTE_BRANCH_START in r.output:  # remote has single branch, shouldn't need to handle stale here
            start_remote_branch = r.output.index(REMOTE_BRANCH_START)
            remote_branches = r.output[start_remote_branch +
                                       len(REMOTE_BRANCH_START):].split('\n')
            remote_branches = [
                b.replace('tracked', '').strip() for b in remote_branches
                if b.strip() != '' and 'tracked' in b
            ]
        else:
            error('Unable to parse remote branches!')
            return None, None

        if len(remote_branches) == 0:
            error('Error getting remote branches!')
            return None, None

        start_default_branch = r.output.index(
            DEFAULT_BRANCH_START)  # get default branch to return
        default_branch = r.output[start_default_branch +
                                  len(DEFAULT_BRANCH_START):]
        end_default_branch = default_branch.index('\n')
        default_branch = default_branch[:end_default_branch]
        return remote_branches, default_branch
示例#11
0
 def _uninstall():
     print('Are you sure you want to uninstall emu?')
     if input_with_options(['Y', 'n'], 'n')[0] == 0:
         run(['sh', UNINSTALL_PATH])
     else:
         error('Not uninstalling!')
示例#12
0
 def _flash():
     r = run('make -C {}/panda/board recover'.format(OPENPILOT_PATH))
     if not r:
         error('Error running make command!')
示例#13
0
    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
示例#14
0
 def _flash2():
     if not run('pkill -f boardd'):
         error('Error killing boardd! Is it running? (continuing...)')
     importlib.import_module('panda', 'Panda').Panda().flash()
示例#15
0
 def start_function_from_str(self, cmd):
   cmd = '_' + cmd
   if not hasattr(self, cmd):
     error('Command has not been implemented yet, please try updating.')
     return
   getattr(self, cmd)()  # call command's function
示例#16
0
    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!')
示例#17
0
 def _update():
     if not run(['sh', UPDATE_PATH]):
         error('Error updating!')
示例#18
0
#!/usr/bin/python
# -*- coding: utf-8 -*-
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)