示例#1
0
文件: commit.py 项目: westernx/vee
def commit(args):

    home = args.assert_home()
    env_repo = home.get_env_repo(args.repo)

    if not env_repo.status():
        print style_error('Nothing to commit.')
        return 1

    # Pick the level of the patch.
    while not args.micro and args.semver_level is None:
        print '%s [%s]:' % (
            style('How severe are the changes?', 'green', bold=True),
            style('major,minor,PATCH,micro', faint=True),
        ),
        res = raw_input().strip() or 'patch'
        try:
            args.semver_level = dict(major=0, minor=1, patch=2, micro=None)[res]
        except KeyError:
            pass
        else:
            break

    if args.message is None:
        default_message = default_messages[args.semver_level]
        print '%s [%s]:' % (
            style('Enter a short commit message', 'green', bold=True),
            style(default_message, faint=True),
        ),
        args.message = raw_input().strip() or default_message

    env_repo.commit(args.message, args.semver_level)
示例#2
0
    def create_if_not_exists(self):

        python = os.path.join(self.path, 'bin', 'python')
        if not os.path.exists(python):
            makedirs(self.path)
            print style('Creating Python virtualenv', 'blue',
                        bold=True), style(self.path, bold=True)
            virtualenv.create_environment(self.path,
                                          no_setuptools=True,
                                          no_pip=True)

        if not os.path.exists(python + '-config'):
            names = (
                'python%d.%d-config' % sys.version_info[:2],
                'python%d-config' % sys.version_info[0],
                'python-config',
            )
            prefix = getattr(sys, 'real_prefix', sys.prefix)
            for name in names:
                old_path = os.path.join(prefix, 'bin', name)
                if os.path.exists(old_path):
                    for name in names:
                        new_path = os.path.join(self.path, 'bin', name)
                        self.rewrite_shebang_or_link(old_path, new_path)
                    break
            else:
                log.warning('Could not find python-config')
示例#3
0
def list_(args):

    home = args.assert_home()

    if args.availible:
        for req, url in iter_availible_requirements(home):
            print style_note(req.name, str(req))
        return

    if args.glob:
        cur = home.db.execute(
            'SELECT * FROM development_packages WHERE name GLOB ? ORDER BY lower(name)',
            [args.glob])
    else:
        cur = home.db.execute(
            'SELECT * FROM development_packages ORDER BY lower(name)')

    for dev_pkg in sorted(home.iter_development_packages(),
                          key=lambda p: p.name.lower()):

        if args.glob and not fnmatch.fnmatch(dev_pkg.name, args.glob):
            continue

        path = dev_pkg.work_tree.replace(home.dev_root, '$VEE_DEV').replace(
            home.root, '$VEE')
        print style_note(dev_pkg.name, path)
        if args.show_environ:
            for k, v in sorted(
                    render_envvars(dev_pkg.environ,
                                   dev_pkg.work_tree).iteritems()):
                if os.environ.get(k):
                    v = v.replace(os.environ[k], '$' + k)
                v = v.replace(home.dev_root, '$VEE_DEV')
                v = v.replace(home.root, '$VEE')
                print style('    %s=' % k) + v
示例#4
0
def install(args):
    """Install the given requirements without linking them into an environment.
    This is a low-level command, and is generally unused.

    Examples:

        # Install a single package.
        vee install [email protected]:westernx/sgmock

        # Install multiple packages.
        vee install [email protected]:westernx/sgmock [email protected]:westernx/sgsession \\
            http:/example.org/path/to/tarball.tgz --make-install

        # Install from a requirement set.
        vee install path/to/requirements.txt

    """

    home = args.assert_home()

    if not args.requirements:
        raise ValueError('please provide requirements to install')

    reqs = Requirements(args.requirements, home=home)
    pkgs = PackageSet(home=home)

    # TODO: Resolve everything at once like upgrade does.
    for req in reqs.iter_packages():
        pkg = pkgs.resolve(req, check_existing=not args.force)
        try:
            pkgs.install(pkg.name, reinstall=args.force)
        except AlreadyInstalled:
            print style('Already installed', 'blue', bold=True), style(str(pkg.freeze()), bold=True)
示例#5
0
def describe(pkg, cache, depth=0):

    print(('    ' * depth) + style(pkg.name, 'blue'), pkg.id,
          style('***' if pkg.id in cache else str(pkg), faint=True))

    if pkg.id in cache:
        return
    cache[pkg.id] = pkg

    for dep in pkg.dependencies:
        dep.resolve_existing()
        describe(dep, cache, depth + 1)
示例#6
0
文件: log.py 项目: westernx/vee
 def format(self, record):
     record.message = record.msg % record.args if record.args else record.msg
     if record.levelname == 'DEBUG':
         record.message = style(
             'Debug [%s:%s]: %s' %
             (record.name, record.lineno or '', record.message),
             faint=True)
     elif record.levelname != 'INFO':
         colour = {'WARNING': 'yellow'}.get(record.levelname, 'red')
         record.message = '%s %s' % (
             style(record.levelname.title() + ':', fg=colour),
             record.message,
         )
     return record.message
示例#7
0
def format_cli_exc(e, verbose=False):
    res = ''
    tb = sys.exc_info()[2]
    if verbose and tb:
        stack = traceback.format_list(traceback.extract_tb(tb))
        res = style(''.join(stack).rstrip(), faint=True) + '\n'
    return res + cli_exc_str(e)
示例#8
0
def list_(args):

    home = args.assert_home()

    if args.availible:
        for req, url in iter_availible_requirements(home):
            log.info(style_note(req.name, str(req)))
        return

    for dev_pkg in sorted(home.iter_development_packages(),
                          key=lambda p: p.name.lower()):

        if args.glob and not fnmatch.fnmatch(dev_pkg.name, args.glob):
            continue

        path = dev_pkg.work_tree.replace(home.dev_root, '$VEE_DEV').replace(
            home.root, '$VEE')
        log.info(style_note(dev_pkg.name, path))
        if args.show_environ:
            for k, v in sorted(
                    render_envvars(dev_pkg.environ,
                                   dev_pkg.work_tree).items()):
                if os.environ.get(k):
                    v = v.replace(os.environ[k], '$' + k)
                v = v.replace(home.dev_root, '$VEE_DEV')
                v = v.replace(home.root, '$VEE')
                log.info(style('    %s=' % k) + v)
示例#9
0
 def find_command(name):
     path = which(name)
     if path:
         print(style_note(repr(path) + ":"))
         return 0
     else:
         print(style(name + ":", 'yellow'), None)
         return 1
示例#10
0
def list_environments(args):

    home = args.assert_home()
    con = home.db.connect()

    cache = {}

    for env in con.execute(
            'SELECT * from environments ORDER by created_at ASC'):
        print(env['created_at'], style(env['name'], 'blue'), env['id'])
示例#11
0
def cli_exc_str(obj, use_magic=True):

    # Need to be able to avoid recursion.
    if use_magic:
        method = getattr(obj, '__cli_str__', None)
        if method:
            return method()

    title = getattr(obj, '__cli_title__', None) or obj.__class__.__name__
    format = getattr(obj, '__cli_format__', None)
    if format is not None:
        message = format.format(self=obj)
    else:
        message = str(obj)
    detail = getattr(obj, '__cli_detail__', None)

    return ('%s %s\n%s' %
            (style('%s:' % title, 'red', bold=True) if title is not None else
             '', style(message, bold=True) if message is not None else '',
             style(detail, faint=True) if detail is not None else '')).strip()
示例#12
0
    def environ_diff(self):
        if self._environ_diff is None:

            self._environ_diff = {}
            for e in (self.base_environ, self.environ):
                for k, v in e.items():
                    self._environ_diff[k] = self.render_template(v, name=k)

            # Just for debugging...
            for k, v in sorted(self._environ_diff.items()):
                old_v = os.environ.get(k)
                if old_v is not None:
                    v = v.replace(old_v, '@')
                v = v.replace(self.home.root, '$VEE')
                log.debug('%s %s=%s' % (style('setenv', 'blue'), k, v),
                          verbosity=2)

        return self._environ_diff
示例#13
0
文件: status.py 项目: westernx/vee
def summarize_rev_distance(
    local,
    remote,
    local_name='You',
    local_verb='are',
    remote_name='',
    fork_action='please rebase.',
    ahead_action='you may push.',
    behind_action='please pull.',
    indent='    ',
):
    if local and remote:
        print indent + style_warning(
            '%s and %s have forked%s' %
            (local_name, remote_name
             or 'the remote', '; ' + fork_action if fork_action else '.'))
        print indent + style_warning(
            'There are %d local commit%s, and %d remote commit%s.' % (
                local,
                's' if local > 1 else '',
                remote,
                's' if remote > 1 else '',
            ))
    elif local:
        print indent + style('%s %s ahead%s by %d commit%s%s' % (
            local_name,
            local_verb,
            ' of ' + remote_name if remote_name else '',
            local,
            's' if local > 1 else '',
            '; ' + ahead_action if ahead_action else '.',
        ),
                             fg='green',
                             reset=True)
    elif remote:
        print indent + style_warning('%s %s behind%s by %d commit%s%s' % (
            local_name,
            local_verb,
            ' ' + remote_name if remote_name else '',
            remote,
            's' if remote > 1 else '',
            '; ' + behind_action if behind_action else '.',
        ))
示例#14
0
def doctor(args):
    """Perform self-checks to make sure VEE is OK."""

    if args.ping:
        print('pong')
        return

    import vee.__about__ as about

    if args.version:
        print(about.__version__ +
              ('+' + about.__revision__ if args.revision else ''))
        return
    if args.revision:
        print(about.__revision__)
        return

    print(style_note('==> core'))
    print(style_note('version:', repr(about.__version__)))
    print(style_note('revision:', repr(about.__revision__)))
    print(
        style_note('package:',
                   repr(os.path.abspath(os.path.join(__file__, '..', '..')))))

    res = 0

    def find_command(name):
        path = which(name)
        if path:
            print(style_note(repr(path) + ":"))
            return 0
        else:
            print(style(name + ":", 'yellow'), None)
            return 1

    print(style_note('==> dependencies'))
    for name, expected_version, in [
        ('setuptools', '36.0.0'),
        ('pip', '20.0.0'),
        ('virtualenv', '15.0.0'),
        ('packaging', '16.0'),
        ('wheel', '0.29.0'),
    ]:

        try:
            module = __import__(name)
        except ImportError as e:
            print(style(name + ":", 'yellow'), None)
            res = 2
            continue

        actual_version = module.__version__
        if parse_version(expected_version) <= parse_version(actual_version):
            print(
                style_note(
                    name + ":", "{!r} >= {!r}".format(actual_version,
                                                      expected_version)))
        else:
            print(
                style(name + ":", 'yellow'),
                "{!r} < {!r} (from {})".format(actual_version,
                                               expected_version,
                                               module.__file__))
            res = 2

    print(style_note('==> executables'))
    print(style_note('python:', sys.executable))
    res = find_command('git') or res
    if sys.platform == 'darwin':
        res = find_command('install_name_tool') or res
    if sys.platform.startswith('linux'):
        res = find_command('patchelf') or res

    print(style_note('==> runtime'))
    print(
        style_note('sys.real_prefix:', repr(getattr(sys, 'real_prefix',
                                                    None))))
    print(
        style_note('sys.base_prefix:', repr(getattr(sys, 'base_prefix',
                                                    None))))
    print(style_note('sys.prefix:', repr(sys.prefix)))

    print(style_note('==> config'))
    home = args.assert_home()
    print(style_note('home:', repr(home.root)))
    try:
        repo = home.get_repo()
        print(style_note('repo:', repr(repo.name), repr(repo.remote_url)))
    except ValueError:
        print(style("repo:", 'yellow'), None)
        res = res or 3

    print(style_note('==> summary'))
    if not res:
        print(style('Everything looks OK.', 'green'))
    else:
        print(style('Something looks wrong.', 'yellow'))

    return res
示例#15
0
    def install(self,
                names=None,
                link_env=None,
                reinstall=False,
                relink=False,
                no_deps=False):

        # I'd love to split this method into an "install" and "link" step, but
        # then we'd need to reimplement the dependency resolution. That would
        # be a good idea to do anyways, but... meh.

        if isinstance(names, str):
            names = [names]
        names = list(names if names else self.keys())

        for name in names:
            if name not in self:
                raise KeyError(name)

        if not isinstance(reinstall, set):
            reinstall = set(
                names if no_deps else self.keys()) if reinstall else set()
        if not isinstance(relink, set):
            relink = set(
                names if no_deps else self.keys()) if relink else set()

        while names:
            name = names.pop(0)

            self._parent_names.setdefault(name, None)

            parent_chain = []
            tip = name
            while tip and tip not in parent_chain:
                parent_chain.append(tip)
                tip = self._parent_names.get(tip)
            parent_chain = parent_chain[1:]

            print(
                '==>', style(name, 'blue'),
                style('(%s)' % ' < '.join(parent_chain), faint=True)
                if parent_chain else '')

            with log.indent():

                # Avoid infinite error loops.
                if name in self._errored:
                    log.warning('Skipping due to previous error.')
                    continue

                try:
                    self._install_one(names, name, link_env, reinstall, relink,
                                      no_deps)
                except PipelineError as e:
                    self._errored.add(name)
                    log.error(str(e))
                    continue
                except Exception as e:
                    self._errored.add(name)
                    print_cli_exc(e, verbose=True)
                    log.exception('Exception while processing %s' % name)
                    continue

        if self._errored:
            log.warning('There were errors in: %s' %
                        ', '.join(sorted(self._errored)))
示例#16
0
文件: link.py 项目: immersionroom/vee
def link(args):
    """Link the given requirement or requirements into the given environment,
    e.g.::
        
        # Install and link a single package.
        $ vee link [email protected]:vfxetc/sgmock

        # Install and link multiple packages.
        $ vee link [email protected]:vfxetc/sgmock [email protected]:vfxetc/sgsession \\
            http:/example.org/path/to/tarball.tgz --make-install

        # Install and link from a requirement set.
        $ vee link path/to/manifest.txt

    """

    if args.no_install and args.re_install:
        raise ValueError(
            'please use only one of --no-install and --re-install')

    home = args.assert_home()

    if sum(
            int(bool(x))
            for x in (args.repo, args.environment, args.directory)) > 1:
        raise ValueError(
            'use only one of --repo, --environment, or --directory')

    if args.environment:
        env = Environment(args.environment, home=home)
    elif args.directory:
        env = Environment(os.path.abspath(args.directory), home=home)
    else:
        repo = home.get_repo(args.repo)
        env = Environment('%s/%s' % (repo.name, repo.branch_name), home=home)

    if args.raw:
        for dir_ in args.requirements:
            log.info(style_note('Linking', dir_))
            env.link_directory(dir_)
        return

    manifest = Manifest(args.requirements, home=home)
    pkg_set = PackageSet(env=env, home=home)

    # Register the whole set, so that dependencies are pulled from here instead
    # of weakly resolved from installed packages.
    pkg_set.resolve_set(manifest)

    for req in manifest.iter_packages():

        # Skip if it wasn't requested.
        if args.subset and req.name not in args.subset:
            continue

        log.info(style('==> %s' % req.name, 'blue'))

        pkg = pkg_set.resolve(req, check_existing=not args.reinstall)

        if args.no_install and not pkg.installed:
            raise CliError('not installed: %s' % req)

        try:
            with log.indent():
                pkg_set.install(pkg.name,
                                link_env=env,
                                reinstall=args.reinstall,
                                relink=args.force)
        except AlreadyInstalled:
            pass
        except AlreadyLinked as e:
            log.info(style('Already linked ', 'blue') + str(req), verbosity=1)
        except Exception as e:
            print_cli_exc(e, verbose=True)
            log.exception('Failed to link %s' % req)
            continue
示例#17
0
文件: doctor.py 项目: westernx/vee
def doctor(args):
    """Perform self-checks to make sure VEE is OK."""

    if args.ping:
        print 'pong'
        return

    import vee.__about__ as about

    if args.version:
        print about.__version__ + ('+' +
                                   about.__revision__ if args.revision else '')
        return
    if args.revision:
        print about.__revision__
        return

    print style_note('==> VEE')
    print style_note('version:', about.__version__)
    print style_note('revision:', about.__revision__)
    print style_note('package:',
                     os.path.abspath(os.path.join(__file__, '..', '..')))

    res = 0

    def find_command(name, warn=False):
        path = which(name)
        if path:
            print style_note('%s:' % name, path)
        else:
            if warn:
                print style_warning('cannot find %s' % name)
            else:
                print style_error('cannot find %s' % name)
                return 1

    print style_note('==> dependencies')
    for name, expected_version, in [('setuptools', '18.0.1'),
                                    ('virtualenv', '13.1.0')]:
        module = globals()[name]
        actual_version = module.__version__
        if expected_version == actual_version:
            print style_note(name + ':', expected_version)
        else:
            print style(
                '%s: %s (expected vendored %s) from %s' %
                (name, actual_version, expected_version, module.__file__),
                'yellow')
            res = 2

    print style_note('==> executables')
    print style_note('python:', sys.executable)
    res = find_command('git') or res
    if sys.platform == 'darwin':
        res = find_command('install_name_tool') or res
    if sys.platform.startswith('linux'):
        res = find_command('patchelf', warn=True) or res

    print style_note('==> configuration')
    home = args.assert_home()
    print style_note('home:', home.root)

    try:
        repo = home.get_env_repo()
    except ValueError:
        print style_warning('no default repo.',
                            'Use `vee repo add --default URL`.')
        return
    print style_note('repo:', repo.name, repo.remote_url)

    print style_note('==> summary')
    if not res:
        print style('Everything looks OK', 'green')
    else:
        print style('Something may be wrong', 'yellow')

    return res
示例#18
0
文件: add.py 项目: westernx/vee
def add(args):

    home = args.assert_home()
    env_repo = home.get_env_repo(args.repo)
    req_set = env_repo.load_requirements()
    pkg_set = PackageSet(home=home)

    baked_any = None

    if args.update:
        baked_any = False
        for req in req_set.iter_packages():
            pkg = pkg_set.resolve(req, check_existing=False)
            if pkg.fetch_type != 'git':
                continue
            print style_note('Fetching', str(req))
            pkg.repo.fetch('origin',
                           'master')  # TODO: track these another way?
            if pkg.repo.check_ff_safety('origin/master'):
                pkg.repo.checkout('origin/master')
                head = pkg.repo.head[:8]
                if head != req.revision:
                    req.revision = pkg.repo.head[:8]
                    print style_note('Updated', str(req))
                    baked_any = True

    if args.bake_installed:
        baked_any = False

        for req in req_set.iter_packages():

            pkg = pkg_set.resolve(req)
            if pkg.fetch_type != 'git':
                continue
            repo = pkg.pipeline.steps['fetch'].repo

            if req.name and req.name == guess_name(req.url):
                req.name = None
                baked_any = True
                print style_note('Unset redundant name', req.name)

            if pkg.installed and req.revision != repo.head[:8]:
                req.revision = repo.head[:8]
                baked_any = True
                print style_note('Pinned', req.name, req.revision)

    if args.checksum:
        baked_any = False

        for req in req_set.iter_packages():
            pkg = pkg_set.resolve(req)
            if pkg.checksum:
                continue
            if not pkg.package_path or not os.path.isfile(pkg.package_path):
                continue
            req.checksum = checksum_file(pkg.package_path)
            print style_note('Checksummed', pkg.name, req.checksum)
            baked_any = True

    if baked_any is not None:
        if baked_any:
            env_repo.dump_requirements(req_set)
        else:
            print style_note('No changes.')
        return

    row = home.get_development_record(os.path.abspath(args.package))

    if not row:
        raise ValueError('No development package %r' % args.package)

    dev_repo = GitRepo(row['path'])

    # Get the normalized origin.
    dev_remote_urls = set()
    for url in dev_repo.remotes().itervalues():
        url = normalize_git_url(url, prefer='scp') or url
        log.debug('adding dev remote url: %s' % url)
        dev_remote_urls.add(url)
    if not dev_remote_urls:
        print style_error('No git remotes for %s' % row['path'])
        return 1

    for req in req_set.iter_packages(eval_control=False):

        # We only deal with git packages.
        pkg = pkg_set.resolve(req, check_existing=False)
        if pkg.fetch_type != 'git':
            continue

        req_url = normalize_git_url(req.url, prefer='scp')
        log.debug('does match package url?: %s' % req_url)
        if req_url in dev_remote_urls:
            if req.revision == dev_repo.head[:8]:
                print style_note('No change to', str(req))
            else:
                req.revision = dev_repo.head[:8]
                print style_note('Updated', str(req))
            break

    else:
        if not args.init:
            print '{error}: No required package {name}; would match one of:'.format(
                error=style('Error', 'red'),
                name=style(args.package, bold=True))
            for url in sorted(dev_remote_urls):
                print '    {}'.format(url)
            print 'Use {} to setup: git+{} --revision {}'.format(
                style('vee add --init %s' % args.package, 'green'),
                dev_repo.remotes()['origin'], dev_repo.head[:8])
            return 1

        req = Package(
            url=normalize_git_url(dev_repo.remotes()['origin'], prefix=True),
            revision=dev_repo.head[:8],
            home=home,
        )
        req_set.append(('', req, ''))

    env_repo.dump_requirements(req_set)
示例#19
0
文件: status.py 项目: westernx/vee
def status(args):

    home = args.assert_home()

    env_repo = home.get_env_repo(args.repo)
    pkg_set = PackageSet(home=home)

    by_name = {}

    # Dev packages.
    for row in home.db.execute('SELECT * FROM development_packages'):
        row = dict(row)

        if not os.path.exists(row['path']):
            continue

        dev_repo = GitRepo(row['path'])
        row['remotes'] = dev_repo.remotes()
        by_name.setdefault(row['name'], {})['dev'] = row

    # Current requirements.
    for revision, name in [
        (None, 'work'),
        ('HEAD', 'head'),
    ]:
        for req in env_repo.load_requirements(
                revision=revision).iter_packages():
            pkg = pkg_set.resolve(req, check_existing=False)
            if pkg.fetch_type != 'git':
                continue
            by_name.setdefault(pkg.name, {})[name] = req

    by_name = by_name.items()
    by_name.sort(key=lambda x: x[0].lower())

    if args.names:
        by_name = [x for x in by_name if x[0] in args.names]

    for name, everything in by_name:

        dev_row = everything.get('dev')
        work_req = everything.get('work')
        head_req = everything.get('head')

        has_dev = dev_row is not None
        only_has_dev = has_dev and not (work_req or head_req)

        # Skip dev-only stuff most of the time.
        if only_has_dev and not args.all_dev:
            continue

        # Title.
        print '%s %s' % (style(
            '%s %s' % ('==>' if has_dev else '-->', name),
            fg='blue'), '(dev only)' if only_has_dev else '')

        # Status of requirements.
        if work_req and head_req and str(work_req) == str(head_req):
            if args.verbose:
                print '=== %s' % work_req
        else:

            # Print a lovely coloured diff of the specific arguments that
            # are changing.
            # TODO: make this environment relative to the context.
            head_args = head_req.to_args(
                exclude=('base_environ', )) if head_req else []
            work_args = work_req.to_args(
                exclude=('base_environ', )) if work_req else []
            differ = difflib.SequenceMatcher(None, head_args, work_args)
            opcodes = differ.get_opcodes()
            if head_req is not None:
                print style('---', fg='red', bold=True),
                for tag, i1, i2, j1, j2 in opcodes:
                    if tag in ('replace', 'delete'):
                        print style(' '.join(head_args[i1:i2]),
                                    fg='red',
                                    bold=True)
                    elif tag in ('equal', ):
                        print ' '.join(head_args[i1:i2]),
            if work_req is not None:
                print style('+++', fg='green', bold=True),
                for tag, i1, i2, j1, j2 in opcodes:
                    if tag in ('replace', 'insert'):
                        print style(' '.join(work_args[j1:j2]),
                                    fg='green',
                                    bold=True)
                    elif tag in ('equal', ):
                        print ' '.join(work_args[j1:j2]),

        if dev_row:

            if 'warning' in dev_row:
                print dev_row['warning']

            if 'origin' in dev_row['remotes']:
                dev_row['remote_name'] = 'origin'
            else:
                remote_names = sorted(dev_row['remotes'])
                dev_row['remote_name'] = remote_names[0]
                if len(remote_names) != 1:
                    print '    ' + style_warning(
                        'More that one non-origin remote; picking %s' %
                        dev_row['remote_name'])

        dev_repo = dev_row and GitRepo(dev_row['path'])
        if dev_repo and not dev_repo.exists:
            print style_warning('Git repo does not exist.')
            dev_row = dev_repo = None

        if dev_repo:

            if dev_repo.status():
                print '    ' + style_warning('Work tree is dirty.')

            if args.fetch:
                dev_remote_head = dev_repo.fetch(dev_row['remote_name'],
                                                 'master')
            else:
                dev_remote_head = dev_repo.rev_parse(dev_row['remote_name'] +
                                                     '/master')

            # Check your local dev vs. its remote.
            dev_local, dev_remote = dev_repo.distance(dev_repo.head,
                                                      dev_remote_head)
            summarize_rev_distance(
                dev_local,
                dev_remote,
                local_name=name,
                local_verb='is',
                remote_name='%s/master' % dev_row['remote_name'],
                behind_action='please pull or `vee dev ff %s`' % name,
            )

        if dev_repo and work_req and work_req.revision:

            # Check your local dev vs the required revision
            try:
                pkg_revision = dev_repo.rev_parse(work_req.revision)
                pkg_local, pkg_remote = dev_repo.distance(
                    dev_repo.head, pkg_revision)
                summarize_rev_distance(
                    pkg_local,
                    pkg_remote,
                    local_name=name,
                    local_verb='is',
                    remote_name='%s repo' % env_repo.name,
                    ahead_action='you may `vee add %s`' % name,
                    behind_action='please `vee dev checkout --repo %s %s`' %
                    (env_repo.name, name),
                )

            except Exception as e:
                print '    ' + format_cli_exc(e)