diff --git a/README.md b/README.md new file mode 100644 index 0000000..f841d19 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +pyarc +===== + +A simple cli tool for Phabricator. Aims at being some sort of arcanist on +steroids. diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..8704293 --- /dev/null +++ b/setup.py @@ -0,0 +1,32 @@ +import sys +from os import path +from io import open +from setuptools import setup, find_packages + +here = path.abspath(path.dirname(__file__)) +src_dir = path.join(here, "src") + +# When executing the setup.py, we need to be able to import ourselves, this +# means that we need to add the src/ directory to the sys.path. +sys.path.insert(0, src_dir) + +# Get the long description from the README file +with open(path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + +setup( + name='pyarc', + version='0.0.1', + description='', + long_description=long_description, + long_description_content_type='text/markdown', + install_requires=[ + 'click', + 'phabricator', + 'gitpython'], + package_dir={"": "src"}, + packages=find_packages('src'), + entry_points={ + 'console_scripts': [ + 'pyarc=pyarc.cli:pyarc']}, + ) diff --git a/src/pyarc/__init__.py b/src/pyarc/__init__.py new file mode 100644 index 0000000..37a11af --- /dev/null +++ b/src/pyarc/__init__.py @@ -0,0 +1,4 @@ +from . import whoami +from . import diff + +__all__ = (whoami, diff) diff --git a/src/pyarc/cli.py b/src/pyarc/cli.py new file mode 100644 index 0000000..0c8fa2e --- /dev/null +++ b/src/pyarc/cli.py @@ -0,0 +1,24 @@ +import click +from phabricator import Phabricator + + +class options(dict): + def __getattr__(self, key): + return self[key] + + def __setattr__(self, key, value): + self[key] = value + + +@click.group() +@click.option('-v', '--verbose/--no-verbose', default=False, envvar='VERBOSE') +@click.pass_context +def pyarc(ctx, verbose): + """Entry point""" + ctx.ensure_object(dict) + ctx.obj['cnx'] = Phabricator() + ctx.obj['options'] = options(verbose=verbose) + + +if __name__ == '__main__': + pyarc(obj={}) diff --git a/src/pyarc/diff.py b/src/pyarc/diff.py new file mode 100644 index 0000000..9068f9b --- /dev/null +++ b/src/pyarc/diff.py @@ -0,0 +1,84 @@ +from itertools import chain +import click +import git +from .cli import pyarc +from .whoami import get_user +from .tools import wrap, object_from_phid + + +def get_repositories(cnx, uris): + if isinstance(uris, str): + uris = [uris] + return cnx.diffusion.repository.search( + constraints={'uris': uris}).data + + +def repo_from_phid(cnx, phid): + repo = cnx.diffusion.repository.search( + constraints={'phids': [phid]}).data + return repo and repo[0] or None + + +def format_diff(kw): + kw = kw.copy() + kw['id'] = click.style(str(kw['id']), bold=True) + kw['fields']['status']['name'] = click.style( + kw['fields']['status']['name'], + fg=kw['fields']['status']['color.ansi']) + return kw + + +@pyarc.command() +@click.option('-u', '--mine/--all-users', default=False) +@click.option('-A', '--all-repos/--current-repo', default=False) +@click.option('-s', '--summary/--default', default=False) +@click.pass_context +def diff(ctx, mine, all_repos, summary): + '''List Diffs''' + cnx = ctx.obj['cnx'] + user = get_user(cnx) + # options = ctx.obj['options'] + + query = {'statuses': ['open()']} + gitrepo = None + repos = None + if not all_repos: + try: + gitrepo = git.Repo() + remotes = list(chain(*(r.urls for r in gitrepo.remotes))) + repos = get_repositories(cnx, remotes) + except git.InvalidGitRepositoryError: + pass + if repos: + query['repositoryPHIDs'] = [r['phid'] for r in repos] + if mine: + query['authorPHIDs'] = [user.phid] + + # print('query=', query) + diffs = cnx.differential.revision.search(constraints=query).data + + for diff in sorted(diffs, key=lambda x: int(x['id'])): + fields = diff['fields'] + if summary: + click.echo( + '{fields[status][name]:25} D{id}: {fields[title]}'.format( + **format_diff(diff))) + else: + click.echo( + wrap('{fields[status][name]:25} D{id}'.format( + **format_diff(diff)))) + # give a bit more informations + phrepo = repo_from_phid(cnx, fields['repositoryPHID'])['fields'] + author = object_from_phid(cnx, fields['authorPHID']) + click.echo('{key}: {shortName} ({callsign})'.format( + key=click.style('Repo', fg='yellow'), + **phrepo)) + click.echo('{key}: {value}'.format( + key=click.style('Author', fg='yellow'), + value=author['name'])) + click.secho('Summary:', fg='yellow') + click.secho(' ' + fields['title'], bold=True) + click.echo() + click.echo('\n'.join(' ' + x + for x in fields['summary'].splitlines())) + click.echo() diff --git a/src/pyarc/tools.py b/src/pyarc/tools.py new file mode 100644 index 0000000..24dff9b --- /dev/null +++ b/src/pyarc/tools.py @@ -0,0 +1,13 @@ +import os + +ROWS, COLUMNS = map(int, os.popen('stty size', 'r').read().split()) + + +def wrap(msg, width=COLUMNS): + if len(msg) > width: + return msg[:width-1] + '\u2026' + return msg + + +def object_from_phid(cnx, phid): + return cnx.phid.query(phids=[phid])[phid] diff --git a/src/pyarc/whoami.py b/src/pyarc/whoami.py new file mode 100644 index 0000000..1c96eae --- /dev/null +++ b/src/pyarc/whoami.py @@ -0,0 +1,18 @@ +import click +from .cli import pyarc + + +def get_user(cnx): + return cnx.user.whoami() + + +@pyarc.command() +@click.pass_context +def whoami(ctx): + '''Gives informations on the current user''' + user = get_user(ctx.obj['cnx']) + click.echo("{userName} ({realName})".format(**user)) + options = ctx.obj['options'] + if options.verbose: + for k in ('phid', 'primaryEmail', 'roles', 'uri'): + click.echo(" {}: {}".format(k, user[k]))