From 493727715bbb511e5a57fa10846e5d6fa22c3d73 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Sat, 14 Apr 2018 08:34:50 +0200 Subject: [PATCH 01/49] Introduced new type field in sources.py to specify repo type (git, git-svn) and git-svn repo handling in git.py. --- gitman/git.py | 103 ++++++++++++++++++++++------------------ gitman/models/config.py | 8 ++++ gitman/models/source.py | 28 +++++++---- 3 files changed, 84 insertions(+), 55 deletions(-) diff --git a/gitman/git.py b/gitman/git.py index d929037a..866b4885 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -15,51 +15,59 @@ def git(*args, **kwargs): return call('git', *args, **kwargs) +def gitsvn(*args, **kwargs): + return call('git', 'svn', *args, **kwargs) -def clone(repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None): + +def clone(type, repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None): """Clone a new Git repository.""" log.debug("Creating a new repository...") - name = repo.split('/')[-1] - if name.endswith(".git"): - name = name[:-4] - - reference = os.path.join(cache, name + ".reference") - if not os.path.isdir(reference): - git('clone', '--mirror', repo, reference) - - normpath = os.path.normpath(path) - if sparse_paths: - os.mkdir(normpath) - git('-C', normpath, 'init') - git('-C', normpath, 'config', 'core.sparseCheckout', 'true') - git('-C', normpath, 'remote', 'add', '-f', 'origin', reference) - - with open("%s/%s/.git/info/sparse-checkout" % (os.getcwd(), normpath), 'w') as fd: - fd.writelines(sparse_paths) - with open("%s/%s/.git/objects/info/alternates" % (os.getcwd(), normpath), 'w') as fd: - fd.write("%s/objects" % reference) - - # We use directly the revision requested here in order to respect, - # that not all repos have `master` as their default branch - git('-C', normpath, 'pull', 'origin', rev) - else: - git('clone', '--reference', reference, repo, os.path.normpath(path)) - - -def fetch(repo, rev=None): - """Fetch the latest changes from the remote repository.""" - git('remote', 'set-url', 'origin', repo) - args = ['fetch', '--tags', '--force', '--prune', 'origin'] - if rev: - if len(rev) == 40: - pass # fetch only works with a SHA if already present locally - elif '@' in rev: - pass # fetch doesn't work with rev-parse + if type == 'git': + name = repo.split('/')[-1] + if name.endswith(".git"): + name = name[:-4] + + reference = os.path.join(cache, name + ".reference") + if not os.path.isdir(reference): + git('clone', '--mirror', repo, reference) + + normpath = os.path.normpath(path) + if sparse_paths: + os.mkdir(normpath) + git('-C', normpath, 'init') + git('-C', normpath, 'config', 'core.sparseCheckout', 'true') + git('-C', normpath, 'remote', 'add', '-f', 'origin', reference) + + with open("%s/%s/.git/info/sparse-checkout" % (os.getcwd(), normpath), 'w') as fd: + fd.writelines(sparse_paths) + with open("%s/%s/.git/objects/info/alternates" % (os.getcwd(), normpath), 'w') as fd: + fd.write("%s/objects" % reference) + + # We use directly the revision requested here in order to respect, + # that not all repos have `master` as their default branch + git('-C', normpath, 'pull', 'origin', rev) else: - args.append(rev) - git(*args) + git('clone', '--reference', reference, repo, os.path.normpath(path)) + elif type == 'git-svn': + gitsvn('clone', '-r', 'HEAD', repo, path) +def fetch(type, repo, rev=None): + """Fetch the latest changes from the remote repository.""" + + if type == 'git': + git('remote', 'set-url', 'origin', repo) + args = ['fetch', '--tags', '--force', '--prune', 'origin'] + if rev: + if len(rev) == 40: + pass # fetch only works with a SHA if already present locally + elif '@' in rev: + pass # fetch doesn't work with rev-parse + else: + args.append(rev) + git(*args) + elif type == 'git-svn': + gitsvn('rebase', rev) def valid(): """Confirm the current directory is a valid working tree.""" @@ -101,7 +109,7 @@ def changes(include_untracked=False, display_status=True, _show=False): return status -def update(rev, *, clean=True, fetch=False): # pylint: disable=redefined-outer-name +def update(type, rev, *, clean=True, fetch=False): # pylint: disable=redefined-outer-name """Update the working tree to the specified revision.""" hide = {'_show': False, '_ignore': True} @@ -109,13 +117,16 @@ def update(rev, *, clean=True, fetch=False): # pylint: disable=redefined-outer- if clean: git('clean', '--force', '-d', '-x', _show=False) - rev = _get_sha_from_rev(rev) - git('checkout', '--force', rev) - git('branch', '--set-upstream-to', 'origin/' + rev, **hide) + if type == 'git': + rev = _get_sha_from_rev(rev) + git('checkout', '--force', rev) + git('branch', '--set-upstream-to', 'origin/' + rev, **hide) - if fetch: - # if `rev` was a branch it might be tracking something older - git('pull', '--ff-only', '--no-rebase', **hide) + if fetch: + # if `rev` was a branch it might be tracking something older + git('pull', '--ff-only', '--no-rebase', **hide) + elif type == 'git-svn': + gitsvn('rebase', rev) def get_url(): diff --git a/gitman/models/config.py b/gitman/models/config.py index d77c46e1..bef510d0 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -29,6 +29,13 @@ def __init__(self, root=None, self.sources = [] self.sources_locked = [] + + def _on_post_load(self): + for source in self.sources: + source._on_post_load() + for source in self.sources_locked: + source._on_post_load() + @property def config_path(self): """Get the full path to the config file.""" @@ -288,6 +295,7 @@ def load_config(start=None, *, search=True): for filename in os.listdir(path): if _valid_filename(filename): config = Config(path, filename) + config._on_post_load() log.debug("Found config: %s", config.path) return config diff --git a/gitman/models/source.py b/gitman/models/source.py index 0e1521d9..8ef0b553 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -1,7 +1,7 @@ import os import logging import warnings - +from enum import Enum import yorm from yorm.types import String, NullableString, List, AttributeDictionary @@ -11,7 +11,9 @@ log = logging.getLogger(__name__) + @yorm.attr(name=String) +@yorm.attr(type=String) @yorm.attr(repo=String) @yorm.attr(sparse_paths=List.of_type(String)) @yorm.attr(rev=String) @@ -23,8 +25,9 @@ class Source(AttributeDictionary): DIRTY = '' UNKNOWN = '' - def __init__(self, repo, name=None, rev='master', link=None, scripts=None, sparse_paths=None): + def __init__(self, type, repo, name=None, rev='master', link=None, scripts=None, sparse_paths=None): super().__init__() + self.type = type or 'git' self.repo = repo self.name = self._infer_name(repo) if name is None else name self.rev = rev @@ -36,15 +39,20 @@ def __init__(self, repo, name=None, rev='master', link=None, scripts=None, spars if not self[key]: msg = "'{}' required for {}".format(key, repr(self)) raise exceptions.InvalidConfig(msg) + + print(str(self)) + + def _on_post_load(self): + self.type = self.type or 'git' def __repr__(self): return "".format(self) def __str__(self): - pattern = "'{r}' @ '{v}' in '{d}'" + pattern = "['{t}'] '{r}' @ '{v}' in '{d}'" if self.link: pattern += " <- '{s}'" - return pattern.format(r=self.repo, v=self.rev, d=self.name, s=self.link) + return pattern.format(t=self.type, r=self.repo, v=self.rev, d=self.name, s=self.link) def __eq__(self, other): return self.name == other.name @@ -61,7 +69,7 @@ def update_files(self, force=False, fetch=False, clean=True): # Clone the repository if needed if not os.path.exists(self.name): - git.clone(self.repo, self.name, sparse_paths=self.sparse_paths, rev=self.rev) + git.clone(self.type, self.repo, self.name, sparse_paths=self.sparse_paths, rev=self.rev) # Enter the working tree shell.cd(self.name) @@ -79,10 +87,10 @@ def update_files(self, force=False, fetch=False, clean=True): if fetch or self.rev not in (git.get_branch(), git.get_hash(), git.get_tag()): - git.fetch(self.repo, self.rev) + git.fetch(self.type, self.repo, self.rev) # Update the working tree to the desired revision - git.update(self.rev, fetch=fetch, clean=clean) + git.update(self.type, self.rev, fetch=fetch, clean=clean) def create_link(self, root, force=False): """Create a link from the target name to the current directory.""" @@ -175,8 +183,10 @@ def lock(self, rev=None): """Return a locked version of the current source.""" if rev is None: _, _, rev = self.identify(allow_dirty=False, allow_missing=False) - source = self.__class__(self.repo, self.name, rev, - self.link, self.scripts) + source = self.__class__(self.type, self.repo, + self.name, rev, + self.link, self.scripts, + self.sparse_paths) return source @property From cad22452489c4979cc766f611bdad144c0aa657b Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Wed, 13 Jun 2018 01:25:51 +0200 Subject: [PATCH 02/49] Introduced readonly git svn support --- gitman/git.py | 90 ++++++++++++++++++++++++++--------------- gitman/models/source.py | 17 ++++---- 2 files changed, 66 insertions(+), 41 deletions(-) diff --git a/gitman/git.py b/gitman/git.py index 866b4885..1022729e 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -1,6 +1,8 @@ """Utilities to call Git commands.""" import os +import shutil + import logging from contextlib import suppress @@ -18,6 +20,12 @@ def git(*args, **kwargs): def gitsvn(*args, **kwargs): return call('git', 'svn', *args, **kwargs) +def clean_dir(path): + for root, dirs, files in os.walk(path): + for f in files: + os.unlink(os.path.join(root, f)) + for d in dirs: + shutil.rmtree(os.path.join(root, d)) def clone(type, repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None): """Clone a new Git repository.""" @@ -50,7 +58,9 @@ def clone(type, repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None else: git('clone', '--reference', reference, repo, os.path.normpath(path)) elif type == 'git-svn': - gitsvn('clone', '-r', 'HEAD', repo, path) + # just the preperation for the svn deep clone / checkout here (clone will be made in update function to simplify source.py). + os.makedirs(path) + def fetch(type, repo, rev=None): """Fetch the latest changes from the remote repository.""" @@ -66,8 +76,8 @@ def fetch(type, repo, rev=None): else: args.append(rev) git(*args) - elif type == 'git-svn': - gitsvn('rebase', rev) + #elif type == 'git-svn': + #deep clone made in update function def valid(): """Confirm the current directory is a valid working tree.""" @@ -81,43 +91,45 @@ def valid(): return True -def changes(include_untracked=False, display_status=True, _show=False): +def changes(type, include_untracked=False, display_status=True, _show=False): """Determine if there are changes in the working tree.""" status = False - try: - # Refresh changes - git('update-index', '-q', '--refresh', _show=False) + if type == 'git': + try: + # Refresh changes + git('update-index', '-q', '--refresh', _show=False) - # Check for uncommitted changes - git('diff-index', '--quiet', 'HEAD', _show=_show) + # Check for uncommitted changes + git('diff-index', '--quiet', 'HEAD', _show=_show) - # Check for untracked files - lines = git('ls-files', '--others', '--exclude-standard', _show=_show) + # Check for untracked files + lines = git('ls-files', '--others', '--exclude-standard', _show=_show) - except ShellError: - status = True + except ShellError: + status = True - else: - status = bool(lines) and include_untracked + else: + status = bool(lines) and include_untracked - if status and display_status: - with suppress(ShellError): - lines = git('status', _show=True) - common.show(*lines, color='git_changes') + if status and display_status: + with suppress(ShellError): + lines = git('status', _show=True) + common.show(*lines, color='git_changes') return status -def update(type, rev, *, clean=True, fetch=False): # pylint: disable=redefined-outer-name - """Update the working tree to the specified revision.""" - hide = {'_show': False, '_ignore': True} +def update(type, repo, path, *, clean=True, fetch=False, rev=None): # pylint: disable=redefined-outer-name + + if type == 'git': + """Update the working tree to the specified revision.""" + hide = {'_show': False, '_ignore': True} - git('stash', **hide) - if clean: - git('clean', '--force', '-d', '-x', _show=False) + git('stash', **hide) + if clean: + git('clean', '--force', '-d', '-x', _show=False) - if type == 'git': rev = _get_sha_from_rev(rev) git('checkout', '--force', rev) git('branch', '--set-upstream-to', 'origin/' + rev, **hide) @@ -126,24 +138,38 @@ def update(type, rev, *, clean=True, fetch=False): # pylint: disable=redefined- # if `rev` was a branch it might be tracking something older git('pull', '--ff-only', '--no-rebase', **hide) elif type == 'git-svn': - gitsvn('rebase', rev) + # make deep clone here for simplification of sources.py + # and to realize consistent readonly clone (always forced) + clean_dir('.') + gitsvn('clone', '-r', rev, repo, '.') -def get_url(): +def get_url(type): """Get the current repository's URL.""" - return git('config', '--get', 'remote.origin.url', _show=False)[0] + if type == 'git': + return git('config', '--get', 'remote.origin.url', _show=False)[0] + elif type == 'git-svn': + return git('config', '--get', 'svn-remote.svn.url', _show=False)[0] -def get_hash(_show=False): +def get_hash(type, _show=False): """Get the current working tree's hash.""" - return git('rev-parse', 'HEAD', _show=_show)[0] - + if type == 'git': + return git('rev-parse', 'HEAD', _show=_show)[0] + elif type == 'git-svn': + return ''.join(filter(str.isdigit, gitsvn('info', _show=_show)[4])) def get_tag(): """Get the current working tree's tag (if on a tag).""" return git('describe', '--tags', '--exact-match', _show=False, _ignore=True)[0] +def is_fetch_required(type, rev): + if type == 'git': + return rev not in (get_branch(), + get_hash(type), + get_tag()) + return False def get_branch(): """Get the current working tree's branch.""" diff --git a/gitman/models/source.py b/gitman/models/source.py index 8ef0b553..5ba9ecd3 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -40,7 +40,8 @@ def __init__(self, type, repo, name=None, rev='master', link=None, scripts=None, msg = "'{}' required for {}".format(key, repr(self)) raise exceptions.InvalidConfig(msg) - print(str(self)) + #uncomment next line to print source configuration + #print(str(self)) def _on_post_load(self): self.type = self.type or 'git' @@ -79,18 +80,16 @@ def update_files(self, force=False, fetch=False, clean=True): # Check for uncommitted changes if not force: log.debug("Confirming there are no uncommitted changes...") - if git.changes(include_untracked=clean): + if git.changes(self.type, include_untracked=clean): msg = "Uncommitted changes in {}".format(os.getcwd()) raise exceptions.UncommittedChanges(msg) # Fetch the desired revision - if fetch or self.rev not in (git.get_branch(), - git.get_hash(), - git.get_tag()): + if fetch or git.is_fetch_required(self.type, self.rev): git.fetch(self.type, self.repo, self.rev) # Update the working tree to the desired revision - git.update(self.type, self.rev, fetch=fetch, clean=clean) + git.update(self.type, self.repo, self.name, fetch=fetch, clean=clean, rev=self.rev) def create_link(self, root, force=False): """Create a link from the target name to the current directory.""" @@ -156,8 +155,8 @@ def identify(self, allow_dirty=True, allow_missing=True): raise self._invalid_repository path = os.getcwd() - url = git.get_url() - if git.changes(display_status=not allow_dirty, _show=True): + url = git.get_url(self.type) + if git.changes(self.type, display_status=not allow_dirty, _show=True): if not allow_dirty: msg = "Uncommitted changes in {}".format(os.getcwd()) raise exceptions.UncommittedChanges(msg) @@ -166,7 +165,7 @@ def identify(self, allow_dirty=True, allow_missing=True): common.newline() return path, url, self.DIRTY else: - rev = git.get_hash(_show=True) + rev = git.get_hash(self.type, _show=True) common.show(rev, color='git_rev', log=False) common.newline() return path, url, rev From 04e536601a6e747c0d3f5ef19015407ced31dc12 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Mon, 25 Jun 2018 00:28:22 +0200 Subject: [PATCH 03/49] Cleaned up readonly git svn support --- gitman/git.py | 209 ++++++++++++++++++++++++++++---------------------- 1 file changed, 117 insertions(+), 92 deletions(-) diff --git a/gitman/git.py b/gitman/git.py index 1022729e..f0faa738 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -18,66 +18,67 @@ def git(*args, **kwargs): return call('git', *args, **kwargs) def gitsvn(*args, **kwargs): - return call('git', 'svn', *args, **kwargs) - -def clean_dir(path): - for root, dirs, files in os.walk(path): - for f in files: - os.unlink(os.path.join(root, f)) - for d in dirs: - shutil.rmtree(os.path.join(root, d)) + return call('git', 'svn', *args, **kwargs) def clone(type, repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None): """Clone a new Git repository.""" log.debug("Creating a new repository...") - if type == 'git': - name = repo.split('/')[-1] - if name.endswith(".git"): - name = name[:-4] - - reference = os.path.join(cache, name + ".reference") - if not os.path.isdir(reference): - git('clone', '--mirror', repo, reference) - - normpath = os.path.normpath(path) - if sparse_paths: - os.mkdir(normpath) - git('-C', normpath, 'init') - git('-C', normpath, 'config', 'core.sparseCheckout', 'true') - git('-C', normpath, 'remote', 'add', '-f', 'origin', reference) - - with open("%s/%s/.git/info/sparse-checkout" % (os.getcwd(), normpath), 'w') as fd: - fd.writelines(sparse_paths) - with open("%s/%s/.git/objects/info/alternates" % (os.getcwd(), normpath), 'w') as fd: - fd.write("%s/objects" % reference) - - # We use directly the revision requested here in order to respect, - # that not all repos have `master` as their default branch - git('-C', normpath, 'pull', 'origin', rev) - else: - git('clone', '--reference', reference, repo, os.path.normpath(path)) - elif type == 'git-svn': + if type == 'git-svn': # just the preperation for the svn deep clone / checkout here (clone will be made in update function to simplify source.py). os.makedirs(path) + return + + assert type == 'git' + + name = repo.split('/')[-1] + if name.endswith(".git"): + name = name[:-4] + + reference = os.path.join(cache, name + ".reference") + if not os.path.isdir(reference): + git('clone', '--mirror', repo, reference) + + normpath = os.path.normpath(path) + if sparse_paths: + os.mkdir(normpath) + git('-C', normpath, 'init') + git('-C', normpath, 'config', 'core.sparseCheckout', 'true') + git('-C', normpath, 'remote', 'add', '-f', 'origin', reference) + + with open("%s/%s/.git/info/sparse-checkout" % (os.getcwd(), normpath), 'w') as fd: + fd.writelines(sparse_paths) + with open("%s/%s/.git/objects/info/alternates" % (os.getcwd(), normpath), 'w') as fd: + fd.write("%s/objects" % reference) + + # We use directly the revision requested here in order to respect, + # that not all repos have `master` as their default branch + git('-C', normpath, 'pull', 'origin', rev) + else: + git('clone', '--reference', reference, repo, os.path.normpath(path)) + def fetch(type, repo, rev=None): """Fetch the latest changes from the remote repository.""" - if type == 'git': - git('remote', 'set-url', 'origin', repo) - args = ['fetch', '--tags', '--force', '--prune', 'origin'] - if rev: - if len(rev) == 40: - pass # fetch only works with a SHA if already present locally - elif '@' in rev: - pass # fetch doesn't work with rev-parse - else: - args.append(rev) - git(*args) - #elif type == 'git-svn': - #deep clone made in update function + if type == 'git-svn': + # deep clone happens in update function + return + + assert type == 'git' + + git('remote', 'set-url', 'origin', repo) + args = ['fetch', '--tags', '--force', '--prune', 'origin'] + if rev: + if len(rev) == 40: + pass # fetch only works with a SHA if already present locally + elif '@' in rev: + pass # fetch doesn't work with rev-parse + else: + args.append(rev) + git(*args) + def valid(): """Confirm the current directory is a valid working tree.""" @@ -95,69 +96,89 @@ def changes(type, include_untracked=False, display_status=True, _show=False): """Determine if there are changes in the working tree.""" status = False - if type == 'git': - try: - # Refresh changes - git('update-index', '-q', '--refresh', _show=False) + if type == 'git-svn': + # ignore changes in case of git-svn + return status - # Check for uncommitted changes - git('diff-index', '--quiet', 'HEAD', _show=_show) + assert type == 'git' + + try: + # Refresh changes + git('update-index', '-q', '--refresh', _show=False) - # Check for untracked files - lines = git('ls-files', '--others', '--exclude-standard', _show=_show) + # Check for uncommitted changes + git('diff-index', '--quiet', 'HEAD', _show=_show) - except ShellError: - status = True + # Check for untracked files + lines = git('ls-files', '--others', '--exclude-standard', _show=_show) - else: - status = bool(lines) and include_untracked + except ShellError: + status = True + + else: + status = bool(lines) and include_untracked - if status and display_status: - with suppress(ShellError): - lines = git('status', _show=True) - common.show(*lines, color='git_changes') + if status and display_status: + with suppress(ShellError): + lines = git('status', _show=True) + common.show(*lines, color='git_changes') return status def update(type, repo, path, *, clean=True, fetch=False, rev=None): # pylint: disable=redefined-outer-name - if type == 'git': - """Update the working tree to the specified revision.""" - hide = {'_show': False, '_ignore': True} - - git('stash', **hide) - if clean: - git('clean', '--force', '-d', '-x', _show=False) - - rev = _get_sha_from_rev(rev) - git('checkout', '--force', rev) - git('branch', '--set-upstream-to', 'origin/' + rev, **hide) - - if fetch: - # if `rev` was a branch it might be tracking something older - git('pull', '--ff-only', '--no-rebase', **hide) - elif type == 'git-svn': + if type == 'git-svn': # make deep clone here for simplification of sources.py # and to realize consistent readonly clone (always forced) - clean_dir('.') + + # completly empty current directory (remove also hidden content) + for root, dirs, files in os.walk('.'): + for f in files: + os.unlink(os.path.join(root, f)) + for d in dirs: + shutil.rmtree(os.path.join(root, d)) + + # clone specified svn revision gitsvn('clone', '-r', rev, repo, '.') + return + + assert type == 'git' + + """Update the working tree to the specified revision.""" + hide = {'_show': False, '_ignore': True} + + git('stash', **hide) + if clean: + git('clean', '--force', '-d', '-x', _show=False) + + rev = _get_sha_from_rev(rev) + git('checkout', '--force', rev) + git('branch', '--set-upstream-to', 'origin/' + rev, **hide) + + if fetch: + # if `rev` was a branch it might be tracking something older + git('pull', '--ff-only', '--no-rebase', **hide) def get_url(type): """Get the current repository's URL.""" - if type == 'git': - return git('config', '--get', 'remote.origin.url', _show=False)[0] - elif type == 'git-svn': + if type == 'git-svn': return git('config', '--get', 'svn-remote.svn.url', _show=False)[0] + + assert type == 'git' + + return git('config', '--get', 'remote.origin.url', _show=False)[0] def get_hash(type, _show=False): """Get the current working tree's hash.""" - if type == 'git': - return git('rev-parse', 'HEAD', _show=_show)[0] - elif type == 'git-svn': + if type == 'git-svn': return ''.join(filter(str.isdigit, gitsvn('info', _show=_show)[4])) + + assert type == 'git' + + return git('rev-parse', 'HEAD', _show=_show)[0] def get_tag(): """Get the current working tree's tag (if on a tag).""" @@ -165,11 +186,15 @@ def get_tag(): _show=False, _ignore=True)[0] def is_fetch_required(type, rev): - if type == 'git': - return rev not in (get_branch(), - get_hash(type), - get_tag()) - return False + if type == 'git-svn': + return False + + assert type == 'git' + + return rev not in (get_branch(), + get_hash(type), + get_tag()) + def get_branch(): """Get the current working tree's branch.""" From 6cff9f8bcf8dd18414db2ce47459edd575109083 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Tue, 26 Jun 2018 11:55:18 +0200 Subject: [PATCH 04/49] Added some documentation regarding setup and related use cases --- docs/setup/git-svn.md | 64 +++++++++++++++++++++++++++++++++++++++ docs/use-cases/git-svn.md | 44 +++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 docs/setup/git-svn.md create mode 100644 docs/use-cases/git-svn.md diff --git a/docs/setup/git-svn.md b/docs/setup/git-svn.md new file mode 100644 index 00000000..ca307db5 --- /dev/null +++ b/docs/setup/git-svn.md @@ -0,0 +1,64 @@ +# git-svn Setup + +## STEP 0: Install missing SVN packages + +```shell +sudo apt-get install git-svn +sudo apt-get install subversion libapache2-svn +``` + +## Credentials + +In order for `gitman` to interact with Git-SVN, it must be configured to store your SVN credentials (cached) for private repository access. + + +To test, trying cloning one of your private repositories: + +```shell +$ git svn clone -r +``` + +### Option 1: Enter manually credentials + +If authentication realm is not already properly configured then Username and Password needs to be entered. + +For example: + +```shell +$ git svn clone -r HEAD http://my-svn-repo/trunk/MyDirectory +Initialized empty Git repository in /home/Dev/MyDirectory/.git/ +Authentication realm: my-svn-repo repository access +Username: JohnDoe +Password for 'John Doe' +``` + +This credentials should be cached afterwards. +For further information about caching credentials see [here](http://svnbook.red-bean.com/vi/1.8/svn.serverconfig.netmodel.html). + +### Option 2: Manually store Credentials + +1. Generate the MD5 hash of the realmstring of the repository provider. +2. Create a file under /home//.subversion/auth/svn.simple, where the filename is the md5 hash. This is how git svn will find the credentials when challenged. +3. The content of the file will have key value pairs as shown below: + +``` +K 8 +passtype +V 6 +simple +K 8 +password +V + +K 15 +svn:realmstring +V 50 + +K 8 +username +V + +END +``` + +4. Now both git svn and svn should be able to check out from the repo without asking for credentials. diff --git a/docs/use-cases/git-svn.md b/docs/use-cases/git-svn.md new file mode 100644 index 00000000..110f82bd --- /dev/null +++ b/docs/use-cases/git-svn.md @@ -0,0 +1,44 @@ +# git svn + +Many development projects use Subversion (SVN) to manage their source code. It’s the most popular open source VCS and has been around for nearly a decade. It’s also very similar in many ways to CVS, which was the big boy of the source-control world before that. + +One of Git’s great features is a bidirectional bridge to Subversion called git svn. This tool allows you to use Git as a valid client to a Subversion server, so you can use all the local features of Git and then push to a Subversion server as if you were using Subversion locally. + +The gitman git svn support allows you to resolve SVN source dependencies. The gitman does resolve a specified SVN revision (e.g. HEAD) of an SVN repository source dependency (from whole branches to particular subdirectories). + +> **Important** +> +> The gitman git svn support does currently not track any changes in the imported svn repository. +> The focus of this feature is to just import svn dependencies +> in a readonly fashion. +> In this matter any changes in the imported svn repository +> will be overridden by an update/install process (like an implicit `--force` for each gitman command). + +To import svn repositories it is required to specify the repo source parameter `type` to `git-svn` for the corresponding entries. + +Example Configuration: + +```yaml +location: imports + +sources: +- name: MyDirectory + type: git-svn + repo: http:http://my-svn-repo/trunk/MyDirectory + rev: HEAD + +- name: MySecondDirectory + type: git-svn + repo: http:http://my-svn-repo/trunk/MySecondDirectory + rev: 72846 + +- name: lz4 + type: git + repo: https://github.com/lz4/lz4 + rev: v1.8.1.2 + +``` + +By default the repo source parameter `type` is `git`. + + From 8b35fee1247c743b2cad1a1057583c934e5e6a8b Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Tue, 26 Jun 2018 14:58:05 +0200 Subject: [PATCH 05/49] Fixed wrong merged git.fetch function --- gitman/git.py | 2 +- gitman/models/source.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gitman/git.py b/gitman/git.py index fe1bb8ba..24f468f1 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -70,7 +70,7 @@ def is_sha(rev): return re.match('^[0-9a-f]{7,40}$', rev) is not None -def fetch(repo, rev=None): +def fetch(type, repo, path, rev=None): """Fetch the latest changes from the remote repository.""" if type == 'git-svn': diff --git a/gitman/models/source.py b/gitman/models/source.py index 5ba9ecd3..3be77513 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -86,7 +86,7 @@ def update_files(self, force=False, fetch=False, clean=True): # Fetch the desired revision if fetch or git.is_fetch_required(self.type, self.rev): - git.fetch(self.type, self.repo, self.rev) + git.fetch(self.type, self.repo, self.name, rev=self.rev) # Update the working tree to the desired revision git.update(self.type, self.repo, self.name, fetch=fetch, clean=clean, rev=self.rev) From f6a0c9d3f7a092cf9acfd88ae24a659dedc8eba1 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Tue, 26 Jun 2018 18:22:37 +0200 Subject: [PATCH 06/49] Improved documentation regarding git-svn support and added entries in the mkdocs.yml --- docs/setup/git-svn.md | 10 +++++----- docs/use-cases/git-svn.md | 14 +++++++++++--- mkdocs.yml | 2 ++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/setup/git-svn.md b/docs/setup/git-svn.md index ca307db5..b7af93a2 100644 --- a/docs/setup/git-svn.md +++ b/docs/setup/git-svn.md @@ -1,6 +1,6 @@ -# git-svn Setup +# Git SVN Setup -## STEP 0: Install missing SVN packages +## Install missing SVN packages ```shell sudo apt-get install git-svn @@ -9,7 +9,7 @@ sudo apt-get install subversion libapache2-svn ## Credentials -In order for `gitman` to interact with Git-SVN, it must be configured to store your SVN credentials (cached) for private repository access. +In order for `gitman` to interact with `git svn`, it must be configured to store your SVN credentials (cached) for private repository access. To test, trying cloning one of your private repositories: @@ -38,7 +38,7 @@ For further information about caching credentials see [here](http://svnbook.red- ### Option 2: Manually store Credentials 1. Generate the MD5 hash of the realmstring of the repository provider. -2. Create a file under /home//.subversion/auth/svn.simple, where the filename is the md5 hash. This is how git svn will find the credentials when challenged. +2. Create a file under /home//.subversion/auth/svn.simple, where the filename is the md5 hash. This is how `git svn` will find the credentials when challenged. 3. The content of the file will have key value pairs as shown below: ``` @@ -61,4 +61,4 @@ V END ``` -4. Now both git svn and svn should be able to check out from the repo without asking for credentials. +4. Now both `git svn` and `svn` should be able to check out from the repo without asking for credentials. diff --git a/docs/use-cases/git-svn.md b/docs/use-cases/git-svn.md index 110f82bd..7e8e04e9 100644 --- a/docs/use-cases/git-svn.md +++ b/docs/use-cases/git-svn.md @@ -1,14 +1,14 @@ -# git svn +# Using Git SVN Many development projects use Subversion (SVN) to manage their source code. It’s the most popular open source VCS and has been around for nearly a decade. It’s also very similar in many ways to CVS, which was the big boy of the source-control world before that. -One of Git’s great features is a bidirectional bridge to Subversion called git svn. This tool allows you to use Git as a valid client to a Subversion server, so you can use all the local features of Git and then push to a Subversion server as if you were using Subversion locally. +One of Git’s great features is a bidirectional bridge to Subversion called `git svn`. This tool allows you to use Git as a valid client to a Subversion server, so you can use all the local features of Git and then push to a Subversion server as if you were using Subversion locally. The gitman git svn support allows you to resolve SVN source dependencies. The gitman does resolve a specified SVN revision (e.g. HEAD) of an SVN repository source dependency (from whole branches to particular subdirectories). > **Important** > -> The gitman git svn support does currently not track any changes in the imported svn repository. +> The gitman `git svn` support does currently not track any changes in the imported svn repository. > The focus of this feature is to just import svn dependencies > in a readonly fashion. > In this matter any changes in the imported svn repository @@ -41,4 +41,12 @@ sources: By default the repo source parameter `type` is `git`. +> **Note** +> +> The gitman `git svn` support uses internally +> ```shell +> $ git svn clone -r +> ``` +> to resolve the individual SVN source dependency. In this matter only the specified svn revsion will be fetched (shallow history). + diff --git a/mkdocs.yml b/mkdocs.yml index 58f6c39a..be7d0d4d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,6 +9,7 @@ pages: - Home: index.md - Setup: - Git: setup/git.md + - Git SVN: setup/git-svn.md - Environment: setup/environment.md - Interfaces: - Command Line: interfaces/cli.md @@ -20,6 +21,7 @@ pages: - Linking Feature Branches: use-cases/linked-features.md - Build System Integration: use-cases/build-integration.md - Sparse Checkouts: use-cases/sparse-checkouts.md + - Git SVN: use-cases/git-svn.md - About: - Release Notes: about/changelog.md - Contributing: about/contributing.md From ea06404876acf7cc011b70fd1d92ca15d54db8e9 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Wed, 27 Jun 2018 10:04:04 +0200 Subject: [PATCH 07/49] Disabled redefined-builtin in .pylint.ini --- .pylint.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/.pylint.ini b/.pylint.ini index e27f6ada..f5498da1 100644 --- a/.pylint.ini +++ b/.pylint.ini @@ -123,6 +123,7 @@ disable=print-statement, too-many-arguments, too-many-branches, keyword-arg-before-vararg, + redefined-builtin, # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option From cb47cab66bae25207851230582595247da9b6d85 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Wed, 27 Jun 2018 20:35:50 +0200 Subject: [PATCH 08/49] Adapted gitman/tests according changed git module functions --- gitman/tests/test_git.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/gitman/tests/test_git.py b/gitman/tests/test_git.py index 978401b7..88582601 100644 --- a/gitman/tests/test_git.py +++ b/gitman/tests/test_git.py @@ -15,7 +15,7 @@ class TestGit: @patch('os.path.isdir', Mock(return_value=False)) def test_clone(self, mock_call): """Verify the commands to set up a new reference repository.""" - git.clone('mock.git', 'mock/path', cache='cache') + git.clone('git', 'mock.git', 'mock/path', cache='cache') check_calls(mock_call, [ "git clone --mirror mock.git " + os.path.normpath("cache/mock.reference"), @@ -28,7 +28,7 @@ def test_clone(self, mock_call): @patch('os.path.isdir', Mock(return_value=True)) def test_clone_from_reference(self, mock_call): """Verify the commands to clone a Git repository from a reference.""" - git.clone('mock.git', 'mock/path', cache='cache') + git.clone('git', 'mock.git', 'mock/path', cache='cache') check_calls(mock_call, [ "git clone --reference " + os.path.normpath("cache/mock.reference") + @@ -38,7 +38,7 @@ def test_clone_from_reference(self, mock_call): def test_fetch(self, mock_call): """Verify the commands to fetch from a Git repository.""" - git.fetch('mock.git') + git.fetch('git', 'mock.git', 'mock/path') check_calls(mock_call, [ "git remote set-url origin mock.git", "git fetch --tags --force --prune origin", @@ -46,7 +46,7 @@ def test_fetch(self, mock_call): def test_fetch_rev(self, mock_call): """Verify the commands to fetch from a Git repository w/ rev.""" - git.fetch('mock.git', 'mock-rev') + git.fetch('git', 'mock.git', 'mock/path', 'mock-rev') check_calls(mock_call, [ "git remote set-url origin mock.git", "git fetch --tags --force --prune origin mock-rev", @@ -54,7 +54,7 @@ def test_fetch_rev(self, mock_call): def test_fetch_rev_sha(self, mock_call): """Verify the commands to fetch from a Git repository w/ SHA.""" - git.fetch('mock.git', 'abcdef1234' * 4) + git.fetch('git', 'mock.git', 'mock/path', 'abcdef1234' * 4) check_calls(mock_call, [ "git remote set-url origin mock.git", "git fetch --tags --force --prune origin", @@ -62,7 +62,7 @@ def test_fetch_rev_sha(self, mock_call): def test_fetch_rev_revparse(self, mock_call): """Verify the commands to fetch from a Git repository w/ rev-parse.""" - git.fetch('mock.git', 'master@{2015-02-12 18:30:00}') + git.fetch('git', 'mock.git', 'mock/path', 'master@{2015-02-12 18:30:00}') check_calls(mock_call, [ "git remote set-url origin mock.git", "git fetch --tags --force --prune origin", @@ -77,7 +77,7 @@ def test_valid(self, mock_call): def test_changes(self, mock_call): """Verify the commands to check for uncommitted changes.""" - git.changes(include_untracked=True) + git.changes('git', include_untracked=True) check_calls(mock_call, [ # based on: http://stackoverflow.com/questions/3878624 "git update-index -q --refresh", @@ -89,26 +89,26 @@ def test_changes(self, mock_call): def test_changes_false(self, _): """Verify the absence of changes can be detected.""" with patch('gitman.git.call', Mock(return_value=[""])): - assert False is git.changes() + assert False is git.changes('git') def test_changes_false_with_untracked(self, _): """Verify untracked files can be detected.""" with patch('gitman.git.call', Mock(return_value=["file_1"])): - assert False is git.changes() + assert False is git.changes('git') def test_changes_true_when_untracked_included(self, _): """Verify untracked files can be detected.""" with patch('gitman.git.call', Mock(return_value=["file_1"])): - assert True is git.changes(include_untracked=True) + assert True is git.changes('git', include_untracked=True) def test_changes_true_when_uncommitted(self, _): """Verify uncommitted changes can be detected.""" with patch('gitman.git.call', Mock(side_effect=ShellError)): - assert True is git.changes(display_status=False) + assert True is git.changes('git', display_status=False) def test_update(self, mock_call): """Verify the commands to update a working tree to a revision.""" - git.update('mock_rev') + git.update('git', 'mock.git', 'mock/path', rev='mock_rev') check_calls(mock_call, [ "git stash", "git clean --force -d -x", @@ -118,7 +118,7 @@ def test_update(self, mock_call): def test_update_branch(self, mock_call): """Verify the commands to update a working tree to a branch.""" - git.update('mock_branch', fetch=True) + git.update('git', 'mock.git', 'mock_branch', fetch=True) check_calls(mock_call, [ "git stash", "git clean --force -d -x", @@ -128,7 +128,7 @@ def test_update_branch(self, mock_call): ]) def test_update_no_clean(self, mock_call): - git.update('mock_rev', clean=False) + git.update('git', 'mock.git', 'mock/path', clean=False, rev='mock_rev') check_calls(mock_call, [ "git stash", "git checkout --force mock_rev", @@ -138,7 +138,7 @@ def test_update_no_clean(self, mock_call): def test_update_revparse(self, mock_call): """Verify the commands to update a working tree to a rev-parse.""" mock_call.return_value = ["abc123"] - git.update('mock_branch@{2015-02-12 18:30:00}') + git.update('git', 'mock.git', 'mock/path', rev='mock_branch@{2015-02-12 18:30:00}') check_calls(mock_call, [ "git stash", "git clean --force -d -x", @@ -150,12 +150,12 @@ def test_update_revparse(self, mock_call): def test_get_url(self, mock_call): """Verify the commands to get the current repository's URL.""" - git.get_url() + git.get_url('git') check_calls(mock_call, ["git config --get remote.origin.url"]) def test_get_hash(self, mock_call): """Verify the commands to get the working tree's hash.""" - git.get_hash() + git.get_hash('git') check_calls(mock_call, ["git rev-parse HEAD"]) def test_get_tag(self, mock_call): From c405ac6cb6a4b0d216cbefe21aa8808913c983a0 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Wed, 27 Jun 2018 20:51:22 +0200 Subject: [PATCH 09/49] Adapted some more gitman/tests according changed git module functions --- gitman/tests/test_models_source.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/gitman/tests/test_models_source.py b/gitman/tests/test_models_source.py index 5e8f3e17..290e85b6 100644 --- a/gitman/tests/test_models_source.py +++ b/gitman/tests/test_models_source.py @@ -17,7 +17,7 @@ class TestSource: def test_init_defaults(self): """Verify a source has a default revision.""" - source = Source('http://example.com/foo/bar.git') + source = Source('git', 'http://example.com/foo/bar.git') assert 'http://example.com/foo/bar.git' == source.repo assert 'bar' == source.name @@ -26,24 +26,24 @@ def test_init_defaults(self): def test_init_rev(self): """Verify the revision can be customized.""" - source = Source('http://mock.git', 'mock_name', 'v1.0') + source = Source('git', 'http://mock.git', 'mock_name', 'v1.0') assert 'v1.0' == source.rev def test_init_link(self): """Verify the link can be set.""" - source = Source('http://mock.git', 'mock_name', link='mock/link') + source = Source('git', 'http://mock.git', 'mock_name', link='mock/link') assert 'mock/link' == source.link def test_init_error(self): """Verify the repository, name, and rev are required.""" with pytest.raises(ValueError): - Source('', name='mock_name', rev='master') + Source('git', '', name='mock_name', rev='master') with pytest.raises(ValueError): - Source('http://mock.git', name='', rev='master') + Source('git', 'http://mock.git', name='', rev='master') with pytest.raises(ValueError): - Source('http://mock.git', name='mock_name', rev='') + Source('git', 'http://mock.git', name='mock_name', rev='') def test_repr(self, source): """Verify sources can be represented.""" @@ -64,11 +64,11 @@ def test_eq(self, source): def test_lt(self): sources = [ - Source('http://github.com/owner/123.git'), - Source('bbb', name='456'), - Source('ccc', '456'), - Source('BBB', 'AAA'), - Source('AAA', 'AAA'), + Source('git', 'http://github.com/owner/123.git'), + Source('git', 'bbb', name='456'), + Source('git', 'ccc', '456'), + Source('git', 'BBB', 'AAA'), + Source('git', 'AAA', 'AAA'), ] assert sources == sorted(sources) From 21917a57392554d2396e5775dda9bef343d7ea59 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Thu, 28 Jun 2018 07:52:37 +0200 Subject: [PATCH 10/49] Fixed test_api.py related tests --- gitman/commands.py | 3 ++- gitman/tests/files/gdm-custom.yml | 2 ++ gitman/tests/files/gdm-default.yml | 1 + gitman/tests/files/gitman.yml | 6 ++++++ tests/test_api.py | 31 ++++++++++++++++++++++++++++++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/gitman/commands.py b/gitman/commands.py index d87b970c..d40bbadc 100644 --- a/gitman/commands.py +++ b/gitman/commands.py @@ -33,7 +33,8 @@ def init(): else: config = Config() - source = Source(name="sample_dependency", + source = Source('git', + name="sample_dependency", repo="https://github.com/githubtraining/hellogitworld") config.sources.append(source) source = source.lock(rev="ebbbf773431ba07510251bb03f9525c7bab2b13a") diff --git a/gitman/tests/files/gdm-custom.yml b/gitman/tests/files/gdm-custom.yml index 3bc2c547..f5ca22bb 100644 --- a/gitman/tests/files/gdm-custom.yml +++ b/gitman/tests/files/gdm-custom.yml @@ -1,10 +1,12 @@ location: dependencies sources: - repo: https://github.com/jacebrowning/gitman + type: git name: gitman_1 rev: fb693447579235391a45ca170959b5583c5042d8 link: src/gitman_a - repo: https://github.com/jacebrowning/gitman + type: git name: gitman_2 rev: master link: src/gitman_b diff --git a/gitman/tests/files/gdm-default.yml b/gitman/tests/files/gdm-default.yml index f9cb4201..7fbe236e 100644 --- a/gitman/tests/files/gdm-default.yml +++ b/gitman/tests/files/gdm-default.yml @@ -1,5 +1,6 @@ location: gitman_modules sources: - repo: https://github.com/jacebrowning/gitman + type: git name: gitman_1 rev: fb693447579235391a45ca170959b5583c5042d8 diff --git a/gitman/tests/files/gitman.yml b/gitman/tests/files/gitman.yml index af7ee247..b328db02 100644 --- a/gitman/tests/files/gitman.yml +++ b/gitman/tests/files/gitman.yml @@ -1,27 +1,33 @@ location: ../../../tmp sources: - name: gitman_1 + type: git link: '' repo: https://github.com/jacebrowning/gitman-demo rev: example-branch - name: gitman_2 + type: git link: '' repo: https://github.com/jacebrowning/gitman-demo rev: example-tag - name: gitman_3 + type: git link: '' repo: https://github.com/jacebrowning/gitman-demo rev: master@{2015-06-18 11:11:11} sources_locked: - name: gitman_1 + type: git link: '' repo: https://github.com/jacebrowning/gitman-demo rev: eb37743011a398b208dd9f9ef79a408c0fc10d48 - name: gitman_2 + type: git link: '' repo: https://github.com/jacebrowning/gitman-demo rev: 7bd138fe7359561a8c2ff9d195dff238794ccc04 - name: gitman_3 + type: git link: '' repo: https://github.com/jacebrowning/gitman-demo rev: 2da24fca34af3748e3cab61db81a2ae8b35aec94 diff --git a/tests/test_api.py b/tests/test_api.py index d9bd61e0..2ad4c069 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -24,6 +24,7 @@ location: deps sources: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -32,6 +33,7 @@ scripts: - - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -40,6 +42,7 @@ scripts: - - name: gitman_3 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -84,6 +87,7 @@ def it_creates_a_new_config_file(tmpdir): location: gitman_sources sources: - name: sample_dependency + type: git repo: https://github.com/githubtraining/hellogitworld sparse_paths: - @@ -93,6 +97,7 @@ def it_creates_a_new_config_file(tmpdir): - sources_locked: - name: sample_dependency + type: git repo: https://github.com/githubtraining/hellogitworld sparse_paths: - @@ -127,6 +132,7 @@ def it_merges_sources(config): location: deps sources: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo rev: example-branch link: @@ -134,12 +140,14 @@ def it_merges_sources(config): - sources_locked: - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo rev: example-branch link: scripts: - - name: gitman_3 + type: git repo: https://github.com/jacebrowning/gitman-demo rev: 7bd138fe7359561a8c2ff9d195dff238794ccc04 link: @@ -163,6 +171,7 @@ def it_can_handle_missing_locked_sources(config): - sources_locked: - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo rev: 7bd138fe7359561a8c2ff9d195dff238794ccc04 link: @@ -229,6 +238,7 @@ def config_with_scripts(config): location: deps sources: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo rev: 7bd138fe7359561a8c2ff9d195dff238794ccc04 link: @@ -252,6 +262,7 @@ def config_with_scripts(config): location: deps sources: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - src/* @@ -343,6 +354,7 @@ def it_locks_previously_locked_dependnecies(config): location: deps sources: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -351,6 +363,7 @@ def it_locks_previously_locked_dependnecies(config): scripts: - - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -360,6 +373,7 @@ def it_locks_previously_locked_dependnecies(config): - sources_locked: - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -375,6 +389,7 @@ def it_locks_previously_locked_dependnecies(config): location: deps sources: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -383,6 +398,7 @@ def it_locks_previously_locked_dependnecies(config): scripts: - - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -392,6 +408,7 @@ def it_locks_previously_locked_dependnecies(config): - sources_locked: - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -406,6 +423,7 @@ def it_should_not_lock_dependnecies_when_disabled(config): location: deps sources: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -414,6 +432,7 @@ def it_should_not_lock_dependnecies_when_disabled(config): scripts: - - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -423,6 +442,7 @@ def it_should_not_lock_dependnecies_when_disabled(config): - sources_locked: - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -438,6 +458,7 @@ def it_should_not_lock_dependnecies_when_disabled(config): location: deps sources: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -446,6 +467,7 @@ def it_should_not_lock_dependnecies_when_disabled(config): scripts: - - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -455,6 +477,7 @@ def it_should_not_lock_dependnecies_when_disabled(config): - sources_locked: - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -470,6 +493,7 @@ def it_should_lock_all_dependencies_when_enabled(config): expect(config.__mapper__.text) == CONFIG + strip(""" sources_locked: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -478,6 +502,7 @@ def it_should_lock_all_dependencies_when_enabled(config): scripts: - - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -486,6 +511,7 @@ def it_should_lock_all_dependencies_when_enabled(config): scripts: - - name: gitman_3 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -526,6 +552,7 @@ def it_records_all_versions_when_no_arguments(config): expect(config.__mapper__.text) == CONFIG + strip(""" sources_locked: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -534,6 +561,7 @@ def it_records_all_versions_when_no_arguments(config): scripts: - - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -542,6 +570,7 @@ def it_records_all_versions_when_no_arguments(config): scripts: - - name: gitman_3 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -558,6 +587,7 @@ def it_records_specified_dependencies(config): expect(config.__mapper__.text) == CONFIG + strip(""" sources_locked: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -566,6 +596,7 @@ def it_records_specified_dependencies(config): scripts: - - name: gitman_3 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - From 4d64950d26a0a75e18e7bedf1bef9be18f5a9329 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Sun, 9 Sep 2018 20:34:56 -0400 Subject: [PATCH 11/49] Update coveragespace --- Makefile | 4 +-- Pipfile | 2 +- Pipfile.lock | 74 +++++++++++++++++++--------------------------------- 3 files changed, 30 insertions(+), 50 deletions(-) diff --git a/Makefile b/Makefile index 21c7d9e3..4ecc29b1 100644 --- a/Makefile +++ b/Makefile @@ -82,9 +82,9 @@ pydocstyle: install # TESTS ####################################################################### -PYTEST := pipenv run py.test +PYTEST := pipenv run pytest COVERAGE := pipenv run coverage -COVERAGE_SPACE := pipenv run coverage.space +COVERAGE_SPACE := pipenv run coveragespace RANDOM_SEED ?= $(shell date +%s) FAILURES := .cache/v/cache/lastfailed diff --git a/Pipfile b/Pipfile index 93b2b727..ceade764 100644 --- a/Pipfile +++ b/Pipfile @@ -28,7 +28,7 @@ pytest-cov = "*" freezegun = "*" # Reports -coverage-space = "*" +coveragespace = "*" # Documentation mkdocs = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 6a4a7ec3..1df7c0ec 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f21e5911273f4c2b13efd4d467e9f1db377738bb2b17dc19936a5af3ac35dcbc" + "sha256": "03c6cd22a411f26ab484ad44e094c07aa3f9b8bdfd12fdd77730544da7925857" }, "pipfile-spec": 6, "requires": { @@ -44,37 +44,20 @@ }, "simplejson": { "hashes": [ - "sha256:046ebeb1ac98d8fd1518977d7ee4003089981d80237a3e4b1b968b9be44c9dbb", - "sha256:05ab5ad4a514c7b84868d9c1bb84fbd2162a77f6d7e01a6f1a27caea50cb3738", - "sha256:15f04040c4fb5a36f07d580c8519f19b3f96fc475ffa3b355859132c8ee23095", - "sha256:1ad7e6621226e2e8e5e50cf7632221731ab5fa8f752e372a5a7bd03a9c44ae53", - "sha256:1d3c5707b3556b9d2801b7a896eec4c03ec66768a68a3594b98fcbf96ce33874", - "sha256:20c626174a3cfcc69c783930ac2d5daa72787a8e26398e33c978065a51cc8bf4", - "sha256:22682801650d2d0362b3ab332060a8ba38995e5ba1a059c0edeb9f9ab79938ea", - "sha256:2b36e41457ccc9e1c1795acd80834e3db6fc65ff9dff7baca4d6d8be1ef04eec", - "sha256:43d58832225a14b399f8686632848189677010168fb899098fd07356868f64e8", - "sha256:4f69a279a64627905303a388c8096298eda8bb058f0c9b49f0f4bd7bc28f5392", - "sha256:5505ea6da9f2e41829f6c18180457f4082aaa71e2ad543aff05c3fdbcb496c61", - "sha256:60edef86db53b9e260a8dc120b2f388d6832655b0577a40d048b6312b2928e8e", - "sha256:6e8ec1dfcda34e84b927a78ee08bdbeaa0a4aeaa031c7a36c39a7435e1049a67", - "sha256:7c2806ff87cf542b3042cee8060f1ba072cf246b697e7e91394511146379e2fd", - "sha256:83b7fc32ed02f42af3e1eb5cf853408e422bbaf3a6a6c9d4be67e1ec40c15a79", - "sha256:89561529582a7b0ed60a73d94b467bbedcded84e95f1789e508d6ef8ecc7711a", - "sha256:8ffe354a9aa48001288e224c1b34a6f7a5b63288b056879c5a7e4549874c8914", - "sha256:aab55363c9f582aea6f7b5bc0672c7a3de1e3a71b14d720a05c1c752f5d0f34c", - "sha256:abdecaa43a220e6fa395a5ba1f34bfd7bcb9f45fdf691727f1017bf79aebe805", - "sha256:b13b69ea5f82a8a930d8027cb48269857ff79bf52b5d8caffda2d701bb46702b", - "sha256:b91325d70e53134d5e6e5d03161366dc548ce40180c7adc705a32e9fb650bb32", - "sha256:cdf2f653d41ba1158a20c174b7312632ac2aaa726d73eb399e8a8f7be2f356fb", - "sha256:d6c9443ef04a8ae34fbaca2c99ace2ecb45727922d1fe0632795e345419e0dc3", - "sha256:d77ab2647a28cbc361e24708e3332721e06b82078df91c7b93a963a68a895d49", - "sha256:d92433c09b8256686f356219d5340ad5a3b7d7485b045791656159086f7bef25", - "sha256:d9b78e08e7d46144126485daed7813b57ebc48c59e11ae46b1e7e66b08628786", - "sha256:dd6addb95308a3b0df0b028dab032824e9ce86bd21c7c1c3afb9c09989e3bc82", - "sha256:fe8d1695cdfcfa738300f38aa33b1467c90ec7e7086f17a582c45084e48b3b9f" - ], - "markers": "python_version != '3.1.*' and python_version >= '2.5' and python_version != '3.2.*' and python_version != '3.0.*'", - "version": "==3.16.1" + "sha256:067a7177ddfa32e1483ba5169ebea1bc2ea27f224853211ca669325648ca5642", + "sha256:2fc546e6af49fb45b93bbe878dea4c48edc34083729c0abd09981fe55bdf7f91", + "sha256:354fa32b02885e6dae925f1b5bbf842c333c1e11ea5453ddd67309dc31fdb40a", + "sha256:37e685986cf6f8144607f90340cff72d36acf654f3653a6c47b84c5c38d00df7", + "sha256:3af610ee72efbe644e19d5eaad575c73fb83026192114e5f6719f4901097fce2", + "sha256:3b919fc9cf508f13b929a9b274c40786036b31ad28657819b3b9ba44ba651f50", + "sha256:3dd289368bbd064974d9a5961101f080e939cbe051e6689a193c99fb6e9ac89b", + "sha256:6c3258ffff58712818a233b9737fe4be943d306c40cf63d14ddc82ba563f483a", + "sha256:75e3f0b12c28945c08f54350d91e624f8dd580ab74fd4f1bbea54bc6b0165610", + "sha256:b1f329139ba647a9548aa05fb95d046b4a677643070dc2afc05fa2e975d09ca5", + "sha256:ee9625fc8ee164902dfbb0ff932b26df112da9f871c32f0f9c1bcf20c350fe2a", + "sha256:fb2530b53c28f0d4d84990e945c2ebb470edb469d63e389bf02ff409012fe7c5" + ], + "version": "==3.16.0" }, "yorm": { "hashes": [ @@ -104,7 +87,7 @@ "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", + "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.3.*'", "version": "==1.2.1" }, "attrs": { @@ -183,16 +166,15 @@ "sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", "sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version < '4' and python_version >= '2.6'", "version": "==4.5.1" }, - "coverage-space": { + "coveragespace": { "hashes": [ - "sha256:ab48b9729e54972708a6430321a0e552c10ece7c4561010d669484f453fa4e03", - "sha256:e47459028a0580d916ac3f3ccfe2cf03d1d073b3284da05c4a09f5b05114ee74" + "sha256:1d68699e4e54b1b9be3351216b34347521d95bdbd082c6787d0b622bfbdb3f99", + "sha256:55aee7929ef7dfb7af74d5da4d1d0389956944ddd3c924cb10f1e9d84d7cb6fc" ], "index": "pypi", - "version": "==1.0.2" + "version": "==2.0.0" }, "docopt": { "hashes": [ @@ -236,7 +218,6 @@ "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", "version": "==4.3.4" }, "jinja2": { @@ -364,7 +345,7 @@ "sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1", "sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", + "markers": "python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.1.*'", "version": "==0.7.1" }, "py": { @@ -372,7 +353,7 @@ "sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1", "sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", + "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.3.*'", "version": "==1.6.0" }, "pycodestyle": { @@ -402,10 +383,11 @@ }, "pyinstaller": { "hashes": [ - "sha256:715f81f24b1ef0e5fe3b3c71e7540551838e46e9de30882aa7c0a521147fd1ce" + "sha256:79d188bd995a96a9050573c419c07c1133b6afc2039910cd5629ebc01699a852", + "sha256:a5a6e04a66abfcf8761e89a2ebad937919c6be33a7b8963e1a961b55cb35986b" ], "index": "pypi", - "version": "==3.3.1" + "version": "==3.4" }, "pylint": { "hashes": [ @@ -473,7 +455,6 @@ "sha256:6faf42ba42f2826c38cf70dacb3ac51f248a418e48afc0e36593df11cf3ab1d2", "sha256:f42a6bb16fbfc5e2c66d553e7ad46524ea833872f75ee5d827c15115fafc94e2" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", "version": "==0.1.10" }, "pyyaml": { @@ -538,7 +519,7 @@ "sha256:c58757e37c4a3172949c99099d4d5106e4d7b63aa0617f9bb24bfbff712c7866", "sha256:d8984742ce86c0855cccecd5c6f54a9f7532c983947cff06f3a0e2115b47f85c" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", + "markers": "python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.3.*' and python_version != '3.1.*' and python_version != '3.2.*'", "version": "==5.1" }, "tqdm": { @@ -546,7 +527,7 @@ "sha256:5ef526702c0d265d5a960a3b27f3971fac13c26cf0fb819294bfa71fc6026c88", "sha256:a3364bd83ce4777320b862e3c8a93d7da91e20a95f06ef79bed7dd71c654cafa" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version >= '2.6'", + "markers": "python_version >= '2.6' and python_version != '3.0.*' and python_version != '3.1.*'", "version": "==4.25.0" }, "twine": { @@ -591,7 +572,6 @@ "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf", "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5" ], - "markers": "python_version != '3.0.*' and python_version < '4' and python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.3.*' and python_version >= '2.6'", "version": "==1.23" }, "wheel": { From 2dddb77c5fd0886bc2b61a30b8401e04951e1798 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Tue, 18 Sep 2018 14:22:05 -0400 Subject: [PATCH 12/49] Update Scrutinizer config --- .scrutinizer.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 67407d9c..ac5cff86 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -2,6 +2,7 @@ build: tests: override: - pylint-run --rcfile=.pylint.ini + - py-scrutinizer-run nodes: py35: environment: From f5b93c6e9cd32a9186650aadf8c1126234047dd5 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Wed, 31 Oct 2018 11:30:48 -0400 Subject: [PATCH 13/49] Update dependencies --- Pipfile.lock | 133 +++++++++++++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 58 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 1df7c0ec..006d29cc 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -87,7 +87,6 @@ "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee" ], - "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.3.*'", "version": "==1.2.1" }, "attrs": { @@ -104,12 +103,19 @@ ], "version": "==1.0.0" }, + "bleach": { + "hashes": [ + "sha256:48d39675b80a75f6d1c3bdbffec791cf0bbbab665cf01e20da701c77de278718", + "sha256:73d26f018af5d5adcdabf5c1c974add4361a9c76af215fe32fdec8a6fc5fb9b9" + ], + "version": "==3.0.2" + }, "certifi": { "hashes": [ - "sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638", - "sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a" + "sha256:339dc09518b07e2fa7eda5450740925974815557727d6bd35d319c1524a04a4c", + "sha256:6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a" ], - "version": "==2018.8.24" + "version": "==2018.10.15" }, "chardet": { "hashes": [ @@ -120,10 +126,10 @@ }, "click": { "hashes": [ - "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", - "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" + "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", + "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" ], - "version": "==6.7" + "version": "==7.0" }, "colorama": { "hashes": [ @@ -136,6 +142,7 @@ "hashes": [ "sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba", "sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed", + "sha256:0bf8cbbd71adfff0ef1f3a1531e6402d13b7b01ac50a79c97ca15f030dba6306", "sha256:10a46017fef60e16694a30627319f38a2b9b52e90182dddb6e37dcdab0f4bf95", "sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640", "sha256:23d341cdd4a0371820eb2b0bd6b88f5003a7438bbedb33688cd33b8eae59affd", @@ -164,17 +171,18 @@ "sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd", "sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d", "sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", + "sha256:f05a636b4564104120111800021a92e43397bc12a5c72fed7036be8556e0029e", "sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80" ], "version": "==4.5.1" }, "coveragespace": { "hashes": [ - "sha256:1d68699e4e54b1b9be3351216b34347521d95bdbd082c6787d0b622bfbdb3f99", - "sha256:55aee7929ef7dfb7af74d5da4d1d0389956944ddd3c924cb10f1e9d84d7cb6fc" + "sha256:498b54ec158a19e1f5647da681dc77fd9d17df11ecff1253d60ac7970209f6e5", + "sha256:7c5ce4641e0f995b9be0e8b53401fd7b6d17db1b8c23bfd06f0c845ad0de5b5f" ], "index": "pypi", - "version": "==2.0.0" + "version": "==2.1" }, "docopt": { "hashes": [ @@ -193,17 +201,17 @@ }, "freezegun": { "hashes": [ - "sha256:703caac155dcaad61f78de4cb0666dca778d854dfb90b3699930adee0559a622", - "sha256:94c59d69bb99c9ec3ca5a3adb41930d3ea09d2a9756c23a02d89fa75646e78dd" + "sha256:6cb82b276f83f2acce67f121dc2656f4df26c71e32238334eb071170b892a278", + "sha256:e839b43bfbe8158b4d62bb97e6313d39f3586daf48e1314fb1083d2ef17700da" ], "index": "pypi", - "version": "==0.3.10" + "version": "==0.3.11" }, "future": { "hashes": [ - "sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb" + "sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8" ], - "version": "==0.16.0" + "version": "==0.17.1" }, "idna": { "hashes": [ @@ -285,10 +293,10 @@ }, "markdown": { "hashes": [ - "sha256:9ba587db9daee7ec761cfc656272be6aabe2ed300fece21208e4aab2e457bc8f", - "sha256:a856869c7ff079ad84a3e19cd87a64998350c2b94e9e08e44270faef33400f81" + "sha256:c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa", + "sha256:d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c" ], - "version": "==2.6.11" + "version": "==3.0.1" }, "markupsafe": { "hashes": [ @@ -342,19 +350,17 @@ }, "pluggy": { "hashes": [ - "sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1", - "sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1" + "sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095", + "sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f" ], - "markers": "python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.1.*'", - "version": "==0.7.1" + "version": "==0.8.0" }, "py": { "hashes": [ - "sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1", - "sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6" + "sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", + "sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6" ], - "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.3.*'", - "version": "==1.6.0" + "version": "==1.7.0" }, "pycodestyle": { "hashes": [ @@ -383,7 +389,6 @@ }, "pyinstaller": { "hashes": [ - "sha256:79d188bd995a96a9050573c419c07c1133b6afc2039910cd5629ebc01699a852", "sha256:a5a6e04a66abfcf8761e89a2ebad937919c6be33a7b8963e1a961b55cb35986b" ], "index": "pypi", @@ -407,11 +412,11 @@ }, "pytest": { "hashes": [ - "sha256:453cbbbe5ce6db38717d282b758b917de84802af4288910c12442984bde7b823", - "sha256:a8a07f84e680482eb51e244370aaf2caa6301ef265f37c2bdefb3dd3b663f99d" + "sha256:a9e5e8d7ab9d5b0747f37740276eb362e6a76275d76cebbb52c6049d93b475db", + "sha256:bf47e8ed20d03764f963f0070ff1c8fda6e2671fc5dd562a4d3b7148ad60f5ca" ], "index": "pypi", - "version": "==3.8.0" + "version": "==3.9.3" }, "pytest-cov": { "hashes": [ @@ -445,10 +450,10 @@ }, "python-dateutil": { "hashes": [ - "sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0", - "sha256:e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8" + "sha256:063df5763652e21de43de7d9e00ccf239f953a832941e37be541614732cdfc93", + "sha256:88f9287c0174266bb0d8cedd395cfba9c58e87e5ad86b2ce58859bc11be3cf02" ], - "version": "==2.7.3" + "version": "==2.7.5" }, "python-termstyle": { "hashes": [ @@ -473,12 +478,19 @@ ], "version": "==3.13" }, + "readme-renderer": { + "hashes": [ + "sha256:bb16f55b259f27f75f640acf5e00cf897845a8b3e4731b5c1a436e4b8529202f", + "sha256:c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d" + ], + "version": "==24.0" + }, "requests": { "hashes": [ - "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1", - "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a" + "sha256:99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c", + "sha256:a84b8c9ab6239b578f22d1c21d51b696dcfe004032bb80ea832398d6909d7279" ], - "version": "==2.19.1" + "version": "==2.20.0" }, "requests-toolbelt": { "hashes": [ @@ -511,32 +523,30 @@ }, "tornado": { "hashes": [ - "sha256:1c0816fc32b7d31b98781bd8ebc7a9726d7dce67407dc353a2e66e697e138448", - "sha256:4f66a2172cb947387193ca4c2c3e19131f1c70fa8be470ddbbd9317fd0801582", - "sha256:5327ba1a6c694e0149e7d9126426b3704b1d9d520852a3e4aa9fc8fe989e4046", - "sha256:6a7e8657618268bb007646b9eae7661d0b57f13efc94faa33cd2588eae5912c9", - "sha256:a9b14804783a1d77c0bd6c66f7a9b1196cbddfbdf8bceb64683c5ae60bd1ec6f", - "sha256:c58757e37c4a3172949c99099d4d5106e4d7b63aa0617f9bb24bfbff712c7866", - "sha256:d8984742ce86c0855cccecd5c6f54a9f7532c983947cff06f3a0e2115b47f85c" + "sha256:0662d28b1ca9f67108c7e3b77afabfb9c7e87bde174fbda78186ecedc2499a9d", + "sha256:4e5158d97583502a7e2739951553cbd88a72076f152b4b11b64b9a10c4c49409", + "sha256:732e836008c708de2e89a31cb2fa6c0e5a70cb60492bee6f1ea1047500feaf7f", + "sha256:8154ec22c450df4e06b35f131adc4f2f3a12ec85981a203301d310abf580500f", + "sha256:8e9d728c4579682e837c92fdd98036bd5cdefa1da2aaf6acf26947e6dd0c01c5", + "sha256:d4b3e5329f572f055b587efc57d29bd051589fb5a43ec8898c77a47ec2fa2bbb", + "sha256:e5f2585afccbff22390cddac29849df463b252b711aa2ce7c5f3f342a5b3b444" ], - "markers": "python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.3.*' and python_version != '3.1.*' and python_version != '3.2.*'", - "version": "==5.1" + "version": "==5.1.1" }, "tqdm": { "hashes": [ - "sha256:5ef526702c0d265d5a960a3b27f3971fac13c26cf0fb819294bfa71fc6026c88", - "sha256:a3364bd83ce4777320b862e3c8a93d7da91e20a95f06ef79bed7dd71c654cafa" + "sha256:3c4d4a5a41ef162dd61f1edb86b0e1c7859054ab656b2e7c7b77e7fbf6d9f392", + "sha256:5b4d5549984503050883bc126280b386f5f4ca87e6c023c5d015655ad75bdebb" ], - "markers": "python_version >= '2.6' and python_version != '3.0.*' and python_version != '3.1.*'", - "version": "==4.25.0" + "version": "==4.28.1" }, "twine": { "hashes": [ - "sha256:08eb132bbaec40c6d25b358f546ec1dc96ebd2638a86eea68769d9e67fe2b129", - "sha256:2fd9a4d9ff0bcacf41fdc40c8cb0cfaef1f1859457c9653fd1b92237cc4e9f25" + "sha256:7d89bc6acafb31d124e6e5b295ef26ac77030bf098960c2a4c4e058335827c5c", + "sha256:fad6f1251195f7ddd1460cb76d6ea106c93adb4e56c41e0da79658e56e547d2c" ], "index": "pypi", - "version": "==1.11.0" + "version": "==1.12.1" }, "typed-ast": { "hashes": [ @@ -569,18 +579,25 @@ }, "urllib3": { "hashes": [ - "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf", - "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5" + "sha256:41c3db2fc01e5b907288010dec72f9d0a74e37d6994e6eb56849f59fea2265ae", + "sha256:8819bba37a02d143296a4d032373c4dd4aca11f6d4c9973335ca75f9c8475f59" + ], + "version": "==1.24" + }, + "webencodings": { + "hashes": [ + "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" ], - "version": "==1.23" + "version": "==0.5.1" }, "wheel": { "hashes": [ - "sha256:0a2e54558a0628f2145d2fc822137e322412115173e8a2ddbe1c9024338ae83c", - "sha256:80044e51ec5bbf6c894ba0bc48d26a8c20a9ba629f4ca19ea26ecfcf87685f5f" + "sha256:196c9842d79262bb66fcf59faa4bd0deb27da911dbc7c6cdca931080eb1f0783", + "sha256:c93e2d711f5f9841e17f53b0e6c0ff85593f3b416b6eec7a9452041a59a42688" ], "index": "pypi", - "version": "==0.31.1" + "version": "==0.32.2" }, "wrapt": { "hashes": [ From 20791fac6f1bc13440b4d91fe27c763e58e14fdb Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Mon, 5 Nov 2018 21:27:46 +0100 Subject: [PATCH 14/49] Fixed test_models_source.py related tests --- gitman/tests/test_models_source.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gitman/tests/test_models_source.py b/gitman/tests/test_models_source.py index 290e85b6..9fc73214 100644 --- a/gitman/tests/test_models_source.py +++ b/gitman/tests/test_models_source.py @@ -10,7 +10,7 @@ @pytest.fixture def source(): - return Source('repo', 'name', rev='rev', link='link') + return Source('git','repo', 'name', rev='rev', link='link') class TestSource: @@ -47,13 +47,13 @@ def test_init_error(self): def test_repr(self, source): """Verify sources can be represented.""" - assert "" == repr(source) + assert "" == repr(source) def test_repr_no_link(self, source): """Verify sources can be represented.""" source.link = None - assert "" == repr(source) + assert "" == repr(source) def test_eq(self, source): source2 = copy(source) From 65562178e73dc9dc8b125ec914519133b4eb87f5 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Mon, 5 Nov 2018 21:28:03 +0100 Subject: [PATCH 15/49] Fixed test_git.py related tests --- gitman/tests/test_git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitman/tests/test_git.py b/gitman/tests/test_git.py index 88582601..b8ef509b 100644 --- a/gitman/tests/test_git.py +++ b/gitman/tests/test_git.py @@ -118,7 +118,7 @@ def test_update(self, mock_call): def test_update_branch(self, mock_call): """Verify the commands to update a working tree to a branch.""" - git.update('git', 'mock.git', 'mock_branch', fetch=True) + git.update('git', 'mock.git', 'mock/path', fetch=True, rev = 'mock_branch') check_calls(mock_call, [ "git stash", "git clean --force -d -x", From cb131f212e348696c054c9e3b2ad66dfa7a1fbfc Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Mon, 5 Nov 2018 22:27:56 +0100 Subject: [PATCH 16/49] Fixed sources.py related tests in due to merge last develop state --- gitman/models/source.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitman/models/source.py b/gitman/models/source.py index b91371a5..1c2aba9a 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -165,7 +165,7 @@ def identify(self, allow_dirty=True, allow_missing=True): common.newline() return path, url, self.DIRTY - rev = git.get_hash(_show=True) + rev = git.get_hash(self.type, _show=True) common.show(rev, color='git_rev', log=False) common.newline() return path, url, rev From 6a9295e72ae35f8fa420fd6fc1aa184190d43ab7 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Tue, 6 Nov 2018 11:23:12 +0100 Subject: [PATCH 17/49] Added pathlib2 to pipfile to improve development support for python 3.5.2 --- Pipfile | 1 + Pipfile.lock | 53 +++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/Pipfile b/Pipfile index ceade764..2e9ce4a1 100644 --- a/Pipfile +++ b/Pipfile @@ -25,6 +25,7 @@ pytest-describe = "*" pytest-expecter = "*" pytest-random = "*" pytest-cov = "*" +pathlib2 = "*" freezegun = "*" # Reports diff --git a/Pipfile.lock b/Pipfile.lock index 006d29cc..81a1acdd 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "03c6cd22a411f26ab484ad44e094c07aa3f9b8bdfd12fdd77730544da7925857" + "sha256": "c9cd0ac6c20b96d31e6378a765cd0971f4c1d3d8d72b0c8804929599f5ba724b" }, "pipfile-spec": 6, "requires": { @@ -300,9 +300,36 @@ }, "markupsafe": { "hashes": [ - "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + "sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", + "sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", + "sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", + "sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", + "sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", + "sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", + "sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", + "sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", + "sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", + "sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", + "sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", + "sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", + "sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", + "sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", + "sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", + "sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", + "sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", + "sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", + "sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", + "sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", + "sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", + "sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", + "sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", + "sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", + "sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", + "sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", + "sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", + "sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1" ], - "version": "==1.0" + "version": "==1.1.0" }, "mccabe": { "hashes": [ @@ -335,6 +362,14 @@ ], "version": "==1.3.7" }, + "pathlib2": { + "hashes": [ + "sha256:8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83", + "sha256:d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a" + ], + "index": "pypi", + "version": "==2.3.2" + }, "pefile": { "hashes": [ "sha256:4c5b7e2de0c8cb6c504592167acf83115cbbde01fe4a507c16a1422850e86cd6" @@ -412,11 +447,11 @@ }, "pytest": { "hashes": [ - "sha256:a9e5e8d7ab9d5b0747f37740276eb362e6a76275d76cebbb52c6049d93b475db", - "sha256:bf47e8ed20d03764f963f0070ff1c8fda6e2671fc5dd562a4d3b7148ad60f5ca" + "sha256:630ff1dbe04f469ee78faa5660f712e58b953da7df22ea5d828c9012e134da43", + "sha256:a2b5232735dd0b736cbea9c0f09e5070d78fcaba2823a4f6f09d9a81bd19415c" ], "index": "pypi", - "version": "==3.9.3" + "version": "==3.10.0" }, "pytest-cov": { "hashes": [ @@ -579,10 +614,10 @@ }, "urllib3": { "hashes": [ - "sha256:41c3db2fc01e5b907288010dec72f9d0a74e37d6994e6eb56849f59fea2265ae", - "sha256:8819bba37a02d143296a4d032373c4dd4aca11f6d4c9973335ca75f9c8475f59" + "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", + "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" ], - "version": "==1.24" + "version": "==1.24.1" }, "webencodings": { "hashes": [ From c41b1acc5b139b2dc464dd9a01717bc39e9f4cec Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Wed, 7 Nov 2018 22:12:42 +0100 Subject: [PATCH 18/49] Fixed pylint warnings --- gitman/git.py | 45 ++++++++++++++++-------------- gitman/models/config.py | 7 ++--- gitman/models/source.py | 16 ++++++----- gitman/tests/test_git.py | 2 +- gitman/tests/test_models_source.py | 2 +- 5 files changed, 38 insertions(+), 34 deletions(-) diff --git a/gitman/git.py b/gitman/git.py index 2e544b51..45cf2318 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -3,9 +3,8 @@ import logging import os import re -from contextlib import suppress - import shutil +from contextlib import suppress from . import common, settings from .exceptions import ShellError @@ -18,15 +17,18 @@ def git(*args, **kwargs): return call('git', *args, **kwargs) + def gitsvn(*args, **kwargs): - return call('git', 'svn', *args, **kwargs) + return call('git', 'svn', *args, **kwargs) + def clone(type, repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None): """Clone a new Git repository.""" log.debug("Creating a new repository...") if type == 'git-svn': - # just the preperation for the svn deep clone / checkout here (clone will be made in update function to simplify source.py). + # just the preperation for the svn deep clone / checkout here + # clone will be made in update function to simplify source.py). os.makedirs(path) return @@ -61,7 +63,6 @@ def clone(type, repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None git('clone', '--reference', reference, repo, os.path.normpath(path)) - def is_sha(rev): """Heuristically determine whether a revision corresponds to a commit SHA. @@ -72,13 +73,13 @@ def is_sha(rev): return re.match('^[0-9a-f]{7,40}$', rev) is not None -def fetch(type, repo, path, rev=None): +def fetch(type, repo, path, rev=None): # pylint: disable=unused-argument """Fetch the latest changes from the remote repository.""" - + if type == 'git-svn': # deep clone happens in update function return - + assert type == 'git' git('remote', 'set-url', 'origin', repo) @@ -114,7 +115,7 @@ def changes(type, include_untracked=False, display_status=True, _show=False): return status assert type == 'git' - + try: # Refresh changes git('update-index', '-q', '--refresh', _show=False) @@ -139,26 +140,26 @@ def changes(type, include_untracked=False, display_status=True, _show=False): return status -def update(type, repo, path, *, clean=True, fetch=False, rev=None): # pylint: disable=redefined-outer-name - +def update(type, repo, path, *, clean=True, fetch=False, rev=None): # pylint: disable=redefined-outer-name,unused-argument + if type == 'git-svn': # make deep clone here for simplification of sources.py # and to realize consistent readonly clone (always forced) - + # completly empty current directory (remove also hidden content) for root, dirs, files in os.walk('.'): for f in files: os.unlink(os.path.join(root, f)) for d in dirs: shutil.rmtree(os.path.join(root, d)) - - # clone specified svn revision + + # clone specified svn revision gitsvn('clone', '-r', rev, repo, '.') return assert type == 'git' - """Update the working tree to the specified revision.""" + # Update the working tree to the specified revision. hide = {'_show': False, '_ignore': True} git('stash', **hide) @@ -178,7 +179,7 @@ def get_url(type): """Get the current repository's URL.""" if type == 'git-svn': return git('config', '--get', 'svn-remote.svn.url', _show=False)[0] - + assert type == 'git' return git('config', '--get', 'remote.origin.url', _show=False)[0] @@ -188,25 +189,27 @@ def get_hash(type, _show=False): """Get the current working tree's hash.""" if type == 'git-svn': return ''.join(filter(str.isdigit, gitsvn('info', _show=_show)[4])) - + assert type == 'git' - + return git('rev-parse', 'HEAD', _show=_show)[0] + def get_tag(): """Get the current working tree's tag (if on a tag).""" return git('describe', '--tags', '--exact-match', _show=False, _ignore=True)[0] + def is_fetch_required(type, rev): if type == 'git-svn': return False - + assert type == 'git' return rev not in (get_branch(), - get_hash(type), - get_tag()) + get_hash(type), + get_tag()) def get_branch(): diff --git a/gitman/models/config.py b/gitman/models/config.py index e78bb8a2..c3d74fb2 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -29,12 +29,11 @@ def __init__(self, root=None, self.sources = [] self.sources_locked = [] - def _on_post_load(self): for source in self.sources: - source._on_post_load() + source._on_post_load() # pylint: disable=protected-access for source in self.sources_locked: - source._on_post_load() + source._on_post_load() # pylint: disable=protected-access @property def config_path(self): @@ -296,7 +295,7 @@ def load_config(start=None, *, search=True): for filename in os.listdir(path): if _valid_filename(filename): config = Config(path, filename) - config._on_post_load() + config._on_post_load() # pylint: disable=protected-access log.debug("Found config: %s", config.path) return config diff --git a/gitman/models/source.py b/gitman/models/source.py index 1c2aba9a..28adbf92 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -11,7 +11,6 @@ log = logging.getLogger(__name__) - @yorm.attr(name=String) @yorm.attr(type=String) @yorm.attr(repo=String) @@ -25,7 +24,9 @@ class Source(AttributeDictionary): DIRTY = '' UNKNOWN = '' - def __init__(self, type, repo, name=None, rev='master', link=None, scripts=None, sparse_paths=None): + def __init__(self, type, repo, name=None, rev='master', + link=None, scripts=None, sparse_paths=None): + super().__init__() self.type = type or 'git' self.repo = repo @@ -39,9 +40,9 @@ def __init__(self, type, repo, name=None, rev='master', link=None, scripts=None, if not self[key]: msg = "'{}' required for {}".format(key, repr(self)) raise exceptions.InvalidConfig(msg) - - #uncomment next line to print source configuration - #print(str(self)) + + # uncomment next line to print source configuration + # print(str(self)) def _on_post_load(self): self.type = self.type or 'git' @@ -179,8 +180,9 @@ def lock(self, rev=None): """Return a locked version of the current source.""" if rev is None: _, _, rev = self.identify(allow_dirty=False, allow_missing=False) - source = self.__class__(self.type, self.repo, - self.name, rev, + + source = self.__class__(self.type, self.repo, + self.name, rev, self.link, self.scripts, self.sparse_paths) return source diff --git a/gitman/tests/test_git.py b/gitman/tests/test_git.py index 2b449858..6ef098b7 100644 --- a/gitman/tests/test_git.py +++ b/gitman/tests/test_git.py @@ -119,7 +119,7 @@ def test_update(self, mock_call): def test_update_branch(self, mock_call): """Verify the commands to update a working tree to a branch.""" - git.update('git', 'mock.git', 'mock/path', fetch=True, rev = 'mock_branch') + git.update('git', 'mock.git', 'mock/path', fetch=True, rev='mock_branch') check_calls(mock_call, [ "git stash", "git clean --force -d -x", diff --git a/gitman/tests/test_models_source.py b/gitman/tests/test_models_source.py index 534ef2b8..59058fa5 100644 --- a/gitman/tests/test_models_source.py +++ b/gitman/tests/test_models_source.py @@ -10,7 +10,7 @@ @pytest.fixture def source(): - return Source('git','repo', 'name', rev='rev', link='link') + return Source('git', 'repo', 'name', rev='rev', link='link') class TestSource: From 0c59a9247b9f4c54b28180d63cfff23b839e0272 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Thu, 8 Nov 2018 20:58:01 -0500 Subject: [PATCH 19/49] Clean up formatting --- .pylint.ini | 2 +- CHANGELOG.md | 4 ++++ gitman.yml | 8 ++++++++ gitman/__init__.py | 2 +- gitman/git.py | 3 ++- gitman/models/source.py | 15 ++++++++------- gitman/tests/test_git.py | 9 ++++++--- gitman/tests/test_models_source.py | 3 ++- mkdocs.yml | 2 +- 9 files changed, 33 insertions(+), 15 deletions(-) diff --git a/.pylint.ini b/.pylint.ini index a738d174..490e19d5 100644 --- a/.pylint.ini +++ b/.pylint.ini @@ -269,7 +269,7 @@ indent-after-paren=4 indent-string=' ' # Maximum number of characters on a single line. -max-line-length=100 +max-line-length=79 # Maximum number of lines in a module max-module-lines=1000 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b22b82b..09822dec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Revision History +## 1.6 (unreleased) + +- Added `git svn` support (@daniel-brosche). + ## 1.5 (2018-09-08) - Added `--keep-location` option on `uninstall` (@DavidWatkins). diff --git a/gitman.yml b/gitman.yml index 5bb23897..13bb0010 100644 --- a/gitman.yml +++ b/gitman.yml @@ -1,6 +1,7 @@ location: demo sources: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -10,6 +11,7 @@ sources: - cat .noserc - make foobar - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -18,6 +20,7 @@ sources: scripts: - - name: gitman_3 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -27,6 +30,7 @@ sources: - echo "Hello, World!" - pwd - name: gitman_4 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -36,6 +40,7 @@ sources: - sources_locked: - name: gitman_1 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -45,6 +50,7 @@ sources_locked: - cat .noserc - make foobar - name: gitman_2 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -53,6 +59,7 @@ sources_locked: scripts: - - name: gitman_3 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - @@ -62,6 +69,7 @@ sources_locked: - echo "Hello, World!" - pwd - name: gitman_4 + type: git repo: https://github.com/jacebrowning/gitman-demo sparse_paths: - diff --git a/gitman/__init__.py b/gitman/__init__.py index f5feae29..0dc26180 100644 --- a/gitman/__init__.py +++ b/gitman/__init__.py @@ -4,7 +4,7 @@ __project__ = 'GitMan' -__version__ = '1.5.post1' +__version__ = '1.6a1' CLI = 'gitman' PLUGIN = 'deps' diff --git a/gitman/git.py b/gitman/git.py index 45cf2318..19737f3a 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -22,7 +22,8 @@ def gitsvn(*args, **kwargs): return call('git', 'svn', *args, **kwargs) -def clone(type, repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None): +def clone(type, repo, path, *, + cache=settings.CACHE, sparse_paths=None, rev=None): """Clone a new Git repository.""" log.debug("Creating a new repository...") diff --git a/gitman/models/source.py b/gitman/models/source.py index 28adbf92..75dd37e9 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -41,9 +41,6 @@ def __init__(self, type, repo, name=None, rev='master', msg = "'{}' required for {}".format(key, repr(self)) raise exceptions.InvalidConfig(msg) - # uncomment next line to print source configuration - # print(str(self)) - def _on_post_load(self): self.type = self.type or 'git' @@ -54,7 +51,8 @@ def __str__(self): pattern = "['{t}'] '{r}' @ '{v}' in '{d}'" if self.link: pattern += " <- '{s}'" - return pattern.format(t=self.type, r=self.repo, v=self.rev, d=self.name, s=self.link) + return pattern.format(t=self.type, r=self.repo, + v=self.rev, d=self.name, s=self.link) def __eq__(self, other): return self.name == other.name @@ -71,7 +69,8 @@ def update_files(self, force=False, fetch=False, clean=True): # Clone the repository if needed if not os.path.exists(self.name): - git.clone(self.type, self.repo, self.name, sparse_paths=self.sparse_paths, rev=self.rev) + git.clone(self.type, self.repo, self.name, + sparse_paths=self.sparse_paths, rev=self.rev) # Enter the working tree shell.cd(self.name) @@ -90,7 +89,8 @@ def update_files(self, force=False, fetch=False, clean=True): git.fetch(self.type, self.repo, self.name, rev=self.rev) # Update the working tree to the desired revision - git.update(self.type, self.repo, self.name, fetch=fetch, clean=clean, rev=self.rev) + git.update(self.type, self.repo, self.name, + fetch=fetch, clean=clean, rev=self.rev) def create_link(self, root, force=False): """Create a link from the target name to the current directory.""" @@ -157,7 +157,8 @@ def identify(self, allow_dirty=True, allow_missing=True): path = os.getcwd() url = git.get_url(self.type) - if git.changes(self.type, display_status=not allow_dirty, _show=True): + if git.changes(self.type, + display_status=not allow_dirty, _show=True): if not allow_dirty: msg = "Uncommitted changes in {}".format(os.getcwd()) raise exceptions.UncommittedChanges(msg) diff --git a/gitman/tests/test_git.py b/gitman/tests/test_git.py index 6ef098b7..d1575781 100644 --- a/gitman/tests/test_git.py +++ b/gitman/tests/test_git.py @@ -63,7 +63,8 @@ def test_fetch_rev_sha(self, mock_call): def test_fetch_rev_revparse(self, mock_call): """Verify the commands to fetch from a Git repository w/ rev-parse.""" - git.fetch('git', 'mock.git', 'mock/path', 'master@{2015-02-12 18:30:00}') + git.fetch('git', 'mock.git', 'mock/path', + 'master@{2015-02-12 18:30:00}') check_calls(mock_call, [ "git remote set-url origin mock.git", "git fetch --tags --force --prune origin", @@ -119,7 +120,8 @@ def test_update(self, mock_call): def test_update_branch(self, mock_call): """Verify the commands to update a working tree to a branch.""" - git.update('git', 'mock.git', 'mock/path', fetch=True, rev='mock_branch') + git.update('git', 'mock.git', 'mock/path', + fetch=True, rev='mock_branch') check_calls(mock_call, [ "git stash", "git clean --force -d -x", @@ -139,7 +141,8 @@ def test_update_no_clean(self, mock_call): def test_update_revparse(self, mock_call): """Verify the commands to update a working tree to a rev-parse.""" mock_call.return_value = ["abc123"] - git.update('git', 'mock.git', 'mock/path', rev='mock_branch@{2015-02-12 18:30:00}') + git.update('git', 'mock.git', 'mock/path', + rev='mock_branch@{2015-02-12 18:30:00}') check_calls(mock_call, [ "git stash", "git clean --force -d -x", diff --git a/gitman/tests/test_models_source.py b/gitman/tests/test_models_source.py index 59058fa5..1f5d42dc 100644 --- a/gitman/tests/test_models_source.py +++ b/gitman/tests/test_models_source.py @@ -47,7 +47,8 @@ def test_init_error(self): def test_repr(self, source): """Verify sources can be represented.""" - assert "" == repr(source) + assert "" == \ + repr(source) def test_repr_no_link(self, source): """Verify sources can be represented.""" diff --git a/mkdocs.yml b/mkdocs.yml index be7d0d4d..568530a6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,7 +5,7 @@ repo_url: https://github.com/jacebrowning/gitman theme: readthedocs -pages: +nav: - Home: index.md - Setup: - Git: setup/git.md From 9b9c715f636ec0f2d03167b1d92862fadb7faf11 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Thu, 8 Nov 2018 21:01:39 -0500 Subject: [PATCH 20/49] Downgrade 'mkdocs' until content is ready --- Pipfile | 2 +- Pipfile.lock | 28 +++++++++++++--------------- mkdocs.yml | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/Pipfile b/Pipfile index 2e9ce4a1..69819930 100644 --- a/Pipfile +++ b/Pipfile @@ -32,7 +32,7 @@ freezegun = "*" coveragespace = "*" # Documentation -mkdocs = "*" +mkdocs = "<1" docutils = "*" pygments = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 81a1acdd..69db1562 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c9cd0ac6c20b96d31e6378a765cd0971f4c1d3d8d72b0c8804929599f5ba724b" + "sha256": "1614acf2333a1b4dc5ba33c941998436cee08ae89b051946ad13206b10e57778" }, "pipfile-spec": 6, "requires": { @@ -340,11 +340,11 @@ }, "mkdocs": { "hashes": [ - "sha256:17d34329aad75d5de604b9ed4e31df3a4d235afefdc46ce7b1964fddb2e1e939", - "sha256:8cc8b38325456b9e942c981a209eaeb1e9f3f77b493ad755bfef889b9c8d356a" + "sha256:1b4d46cd1cb517cd743358da96a3efc588fd86f81512fb9c28214597b6dc731f", + "sha256:cd7264ea42d76f5bc1a0bd8b0a2c6c6e6be3a8742f5e78f47104a452dbe93600" ], "index": "pypi", - "version": "==1.0.4" + "version": "==0.17.5" }, "more-itertools": { "hashes": [ @@ -522,10 +522,10 @@ }, "requests": { "hashes": [ - "sha256:99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c", - "sha256:a84b8c9ab6239b578f22d1c21d51b696dcfe004032bb80ea832398d6909d7279" + "sha256:65b3a120e4329e33c9889db89c80976c5272f56ea92d3e74da8a463992e3ff54", + "sha256:ea881206e59f41dbd0bd445437d792e43906703fff75ca8ff43ccdb11f33f263" ], - "version": "==2.20.0" + "version": "==2.20.1" }, "requests-toolbelt": { "hashes": [ @@ -558,15 +558,13 @@ }, "tornado": { "hashes": [ - "sha256:0662d28b1ca9f67108c7e3b77afabfb9c7e87bde174fbda78186ecedc2499a9d", - "sha256:4e5158d97583502a7e2739951553cbd88a72076f152b4b11b64b9a10c4c49409", - "sha256:732e836008c708de2e89a31cb2fa6c0e5a70cb60492bee6f1ea1047500feaf7f", - "sha256:8154ec22c450df4e06b35f131adc4f2f3a12ec85981a203301d310abf580500f", - "sha256:8e9d728c4579682e837c92fdd98036bd5cdefa1da2aaf6acf26947e6dd0c01c5", - "sha256:d4b3e5329f572f055b587efc57d29bd051589fb5a43ec8898c77a47ec2fa2bbb", - "sha256:e5f2585afccbff22390cddac29849df463b252b711aa2ce7c5f3f342a5b3b444" + "sha256:5ef073ac6180038ccf99411fe05ae9aafb675952a2c8db60592d5daf8401f803", + "sha256:6d14e47eab0e15799cf3cdcc86b0b98279da68522caace2bd7ce644287685f0a", + "sha256:92b7ca81e18ba9ec3031a7ee73d4577ac21d41a0c9b775a9182f43301c3b5f8e", + "sha256:ab587996fe6fb9ce65abfda440f9b61e4f9f2cf921967723540679176915e4c3", + "sha256:b36298e9f63f18cad97378db2222c0e0ca6a55f6304e605515e05a25483ed51a" ], - "version": "==5.1.1" + "version": "==4.5.3" }, "tqdm": { "hashes": [ diff --git a/mkdocs.yml b/mkdocs.yml index 568530a6..be7d0d4d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,7 +5,7 @@ repo_url: https://github.com/jacebrowning/gitman theme: readthedocs -nav: +pages: - Home: index.md - Setup: - Git: setup/git.md From 2fbf25b98d71e25ab34a553253d1b9b62a31d5f9 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Mon, 29 Oct 2018 21:43:15 +0100 Subject: [PATCH 21/49] Basic implementation to disable gitcache by set environment variable (GITMAN_CACHE_DISABLE) --- docs/setup/environment.md | 7 ++++ gitman/git.py | 67 +++++++++++++++++++++++++-------------- gitman/settings.py | 1 + 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/docs/setup/environment.md b/docs/setup/environment.md index 2a50b8a4..965de985 100644 --- a/docs/setup/environment.md +++ b/docs/setup/environment.md @@ -9,3 +9,10 @@ This variable specifies the path of a directory to store these repository refere The default value should be overridden if `$HOME` is not set on your target system. **Default**: `~/.gitcache` + +## `GITMAN_CACHE_DISABLE` + +This flag variable can be specified to disable the gitman cache. +When this variable is specified then the gitman does a full clone for each repository. + +**Default**: the gitman cache is enabled as long as the flag variable is not specified. diff --git a/gitman/git.py b/gitman/git.py index 19737f3a..c7c06972 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -39,29 +39,50 @@ def clone(type, repo, path, *, if name.endswith(".git"): name = name[:-4] - reference = os.path.join(cache, name + ".reference") - if not os.path.isdir(reference): - git('clone', '--mirror', repo, reference) - - normpath = os.path.normpath(path) - if sparse_paths: - os.mkdir(normpath) - git('-C', normpath, 'init') - git('-C', normpath, 'config', 'core.sparseCheckout', 'true') - git('-C', normpath, 'remote', 'add', '-f', 'origin', reference) - - with open("%s/%s/.git/info/sparse-checkout" % - (os.getcwd(), normpath), 'w') as fd: - fd.writelines(sparse_paths) - with open("%s/%s/.git/objects/info/alternates" % - (os.getcwd(), normpath), 'w') as fd: - fd.write("%s/objects" % reference) - - # We use directly the revision requested here in order to respect, - # that not all repos have `master` as their default branch - git('-C', normpath, 'pull', 'origin', rev) - else: - git('clone', '--reference', reference, repo, os.path.normpath(path)) + if settings.CACHE_DISABLE: + normpath = os.path.normpath(path) + if sparse_paths: + os.mkdir(normpath) + git('-C', normpath, 'init') + git('-C', normpath, 'config', 'core.sparseCheckout', 'true') + git('-C', normpath, 'remote', 'add', '-f', 'origin', repo) + + with open("%s/%s/.git/info/sparse-checkout" % + (os.getcwd(), normpath), 'w') as fd: + fd.writelines(sparse_paths) + with open("%s/%s/.git/objects/info/alternates" % + (os.getcwd(), normpath), 'w') as fd: + fd.write("%s/objects" % repo) + + # We use directly the revision requested here in order to respect, + # that not all repos have `master` as their default branch + git('-C', normpath, 'pull', 'origin', rev) + else: + git('clone', repo, os.path.normpath(path)) + else: + reference = os.path.join(cache, name + ".reference") + if not os.path.isdir(reference): + git('clone', '--mirror', repo, reference) + + normpath = os.path.normpath(path) + if sparse_paths: + os.mkdir(normpath) + git('-C', normpath, 'init') + git('-C', normpath, 'config', 'core.sparseCheckout', 'true') + git('-C', normpath, 'remote', 'add', '-f', 'origin', reference) + + with open("%s/%s/.git/info/sparse-checkout" % + (os.getcwd(), normpath), 'w') as fd: + fd.writelines(sparse_paths) + with open("%s/%s/.git/objects/info/alternates" % + (os.getcwd(), normpath), 'w') as fd: + fd.write("%s/objects" % reference) + + # We use directly the revision requested here in order to respect, + # that not all repos have `master` as their default branch + git('-C', normpath, 'pull', 'origin', rev) + else: + git('clone', '--reference', reference, repo, os.path.normpath(path)) def is_sha(rev): diff --git a/gitman/settings.py b/gitman/settings.py index 1678e8e1..042314a2 100644 --- a/gitman/settings.py +++ b/gitman/settings.py @@ -6,6 +6,7 @@ # Cache settings CACHE = os.path.expanduser(os.getenv('GITMAN_CACHE', "~/.gitcache")) +CACHE_DISABLE = True if os.getenv('GITMAN_CACHE_DISABLE') != None else False # Logging settings DEFAULT_LOGGING_FORMAT = "%(message)s" From da1d44403a757c08e6157ea982068c910e135a4b Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Thu, 29 Nov 2018 11:26:52 +0100 Subject: [PATCH 22/49] Reduced code duplication (concerning git.clone) and improved handling of env flag (GITMAN_CACHE_DISABLE). --- gitman/git.py | 71 ++++++++++++++++++---------------------------- gitman/settings.py | 2 +- 2 files changed, 28 insertions(+), 45 deletions(-) diff --git a/gitman/git.py b/gitman/git.py index c7c06972..76792dad 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -39,50 +39,33 @@ def clone(type, repo, path, *, if name.endswith(".git"): name = name[:-4] - if settings.CACHE_DISABLE: - normpath = os.path.normpath(path) - if sparse_paths: - os.mkdir(normpath) - git('-C', normpath, 'init') - git('-C', normpath, 'config', 'core.sparseCheckout', 'true') - git('-C', normpath, 'remote', 'add', '-f', 'origin', repo) - - with open("%s/%s/.git/info/sparse-checkout" % - (os.getcwd(), normpath), 'w') as fd: - fd.writelines(sparse_paths) - with open("%s/%s/.git/objects/info/alternates" % - (os.getcwd(), normpath), 'w') as fd: - fd.write("%s/objects" % repo) - - # We use directly the revision requested here in order to respect, - # that not all repos have `master` as their default branch - git('-C', normpath, 'pull', 'origin', rev) - else: - git('clone', repo, os.path.normpath(path)) - else: - reference = os.path.join(cache, name + ".reference") - if not os.path.isdir(reference): - git('clone', '--mirror', repo, reference) - - normpath = os.path.normpath(path) - if sparse_paths: - os.mkdir(normpath) - git('-C', normpath, 'init') - git('-C', normpath, 'config', 'core.sparseCheckout', 'true') - git('-C', normpath, 'remote', 'add', '-f', 'origin', reference) - - with open("%s/%s/.git/info/sparse-checkout" % - (os.getcwd(), normpath), 'w') as fd: - fd.writelines(sparse_paths) - with open("%s/%s/.git/objects/info/alternates" % - (os.getcwd(), normpath), 'w') as fd: - fd.write("%s/objects" % reference) - - # We use directly the revision requested here in order to respect, - # that not all repos have `master` as their default branch - git('-C', normpath, 'pull', 'origin', rev) - else: - git('clone', '--reference', reference, repo, os.path.normpath(path)) + normpath = os.path.normpath(path) + reference = os.path.join(cache, name + ".reference") + sparse_paths_repo = repo if settings.CACHE_DISABLE else reference + + if not settings.CACHE_DISABLE and not os.path.isdir(reference): + git('clone', '--mirror', repo, reference) + + if sparse_paths: + os.mkdir(normpath) + git('-C', normpath, 'init') + git('-C', normpath, 'config', 'core.sparseCheckout', 'true') + git('-C', normpath, 'remote', 'add', '-f', 'origin', sparse_paths_repo) + + with open("%s/%s/.git/info/sparse-checkout" % + (os.getcwd(), normpath), 'w') as fd: + fd.writelines(sparse_paths) + with open("%s/%s/.git/objects/info/alternates" % + (os.getcwd(), normpath), 'w') as fd: + fd.write("%s/objects" % sparse_paths_repo) + + # We use directly the revision requested here in order to respect, + # that not all repos have `master` as their default branch + git('-C', normpath, 'pull', 'origin', rev) + elif settings.CACHE_DISABLE: + git('clone', repo, normpath) + else: + git('clone', '--reference', reference, repo, normpath) def is_sha(rev): diff --git a/gitman/settings.py b/gitman/settings.py index 042314a2..52f58a6f 100644 --- a/gitman/settings.py +++ b/gitman/settings.py @@ -6,7 +6,7 @@ # Cache settings CACHE = os.path.expanduser(os.getenv('GITMAN_CACHE', "~/.gitcache")) -CACHE_DISABLE = True if os.getenv('GITMAN_CACHE_DISABLE') != None else False +CACHE_DISABLE = bool(os.getenv('GITMAN_CACHE_DISABLE')) # Logging settings DEFAULT_LOGGING_FORMAT = "%(message)s" From 05aa3d0653a6acd9d4d4e35d71f2e9257082f70a Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Thu, 29 Nov 2018 21:30:57 +0100 Subject: [PATCH 23/49] Added test to check git.clone with disabled gitcache (GITMAN_CACHE_DISABLE) --- gitman/tests/test_git.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/gitman/tests/test_git.py b/gitman/tests/test_git.py index d1575781..01193083 100644 --- a/gitman/tests/test_git.py +++ b/gitman/tests/test_git.py @@ -3,7 +3,7 @@ import os from unittest.mock import Mock, patch -from gitman import git +from gitman import git, settings from gitman.exceptions import ShellError from .utils import check_calls @@ -26,6 +26,17 @@ def test_clone(self, mock_call): os.path.normpath("mock/path") ]) + @patch('os.path.isdir', Mock(return_value=False)) + def test_clone_without_cache(self, mock_call): + # disable cache + settings.CACHE_DISABLE = True + """Verify the commands to set up a new reference repository.""" + git.clone('git', 'mock.git', 'mock/path', cache='cache') + check_calls(mock_call, [ + "git clone mock.git mock/path" + ]) + settings.CACHE_DISABLE = False + @patch('os.path.isdir', Mock(return_value=True)) def test_clone_from_reference(self, mock_call): """Verify the commands to clone a Git repository from a reference.""" From 39468e7786ebfddb90e8252a454f2431199bc59c Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Thu, 29 Nov 2018 15:59:53 -0500 Subject: [PATCH 24/49] Restore the cache setting even if the test fails --- gitman/tests/test_git.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/gitman/tests/test_git.py b/gitman/tests/test_git.py index 01193083..49d99999 100644 --- a/gitman/tests/test_git.py +++ b/gitman/tests/test_git.py @@ -28,14 +28,15 @@ def test_clone(self, mock_call): @patch('os.path.isdir', Mock(return_value=False)) def test_clone_without_cache(self, mock_call): - # disable cache + """Verify the commands to clone a repository.""" settings.CACHE_DISABLE = True - """Verify the commands to set up a new reference repository.""" - git.clone('git', 'mock.git', 'mock/path', cache='cache') - check_calls(mock_call, [ - "git clone mock.git mock/path" - ]) - settings.CACHE_DISABLE = False + try: + git.clone('git', 'mock.git', 'mock/path', cache='cache') + check_calls(mock_call, [ + "git clone mock.git mock/path" + ]) + finally: + settings.CACHE_DISABLE = False @patch('os.path.isdir', Mock(return_value=True)) def test_clone_from_reference(self, mock_call): From 8b381c1ef9effdd42331ce68b3d69a0f0e25d670 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Thu, 29 Nov 2018 16:11:03 -0500 Subject: [PATCH 25/49] Update docs --- .pylint.ini | 1 + docs/setup/environment.md | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.pylint.ini b/.pylint.ini index 490e19d5..b38c6328 100644 --- a/.pylint.ini +++ b/.pylint.ini @@ -126,6 +126,7 @@ disable= keyword-arg-before-vararg, logging-not-lazy, redefined-builtin, + too-many-public-methods, # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/docs/setup/environment.md b/docs/setup/environment.md index 965de985..103033c1 100644 --- a/docs/setup/environment.md +++ b/docs/setup/environment.md @@ -12,7 +12,7 @@ The default value should be overridden if `$HOME` is not set on your target syst ## `GITMAN_CACHE_DISABLE` -This flag variable can be specified to disable the gitman cache. -When this variable is specified then the gitman does a full clone for each repository. +This flag variable can be used to disable GitMan's local repository cache. +If set, a full clone will be performed for each repository. -**Default**: the gitman cache is enabled as long as the flag variable is not specified. +**Default**: _(none)_ From eade91667b712b5d68abe5062c9a6146b1cf84a5 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Thu, 29 Nov 2018 16:19:42 -0500 Subject: [PATCH 26/49] Normalize paths for Windows --- gitman/tests/test_git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitman/tests/test_git.py b/gitman/tests/test_git.py index 49d99999..d04b2b97 100644 --- a/gitman/tests/test_git.py +++ b/gitman/tests/test_git.py @@ -33,7 +33,7 @@ def test_clone_without_cache(self, mock_call): try: git.clone('git', 'mock.git', 'mock/path', cache='cache') check_calls(mock_call, [ - "git clone mock.git mock/path" + "git clone mock.git " + os.path.normpath("mock/path") ]) finally: settings.CACHE_DISABLE = False From cb0c0c93d7111902864ab9e58e4cf8c936a98b7b Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Thu, 29 Nov 2018 20:49:24 -0500 Subject: [PATCH 27/49] Bump version to 1.6a2 --- CHANGELOG.md | 11 ++++++----- gitman/__init__.py | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09822dec..dd0b0c8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,12 @@ ## 1.6 (unreleased) -- Added `git svn` support (@daniel-brosche). +- Added `git svn` support. (@daniel-brosche) +- Added `$GITMAN_CACHE_DISABLE` to disable repository mirrors. (@daniel-brosche) ## 1.5 (2018-09-08) -- Added `--keep-location` option on `uninstall` (@DavidWatkins). +- Added `--keep-location` option on `uninstall`. (@DavidWatkins) - Added feature to enable sparse checkouts. See the docs for further information. (@xenji) - **BREAKING**: Removed confusing `--lock` option on `update` command in favor of just using the `lock` command. - **BREAKING**: Renamed `--no-lock` to `--skip-lock` on `update` command. @@ -15,7 +16,7 @@ ## 1.4 (2017-03-21) - Allow config files to exist in subdirectories of the main project. -- Added `${GITMAN_CACHE}` to customize the repository cache location. +- Added `$GITMAN_CACHE` to customize the repository cache location. ## 1.3 (2017-02-03) @@ -25,7 +26,7 @@ ## 1.2 (2017-01-08) -- Added preliminary Windows support (@StudioEtrange). +- Added preliminary Windows support. (@StudioEtrange) ## 1.1 (2017-01-06) @@ -81,7 +82,7 @@ ## 0.7 (2015-12-22) -- Fixed `git remote rm` command (@hdnivara). +- Fixed `git remote rm` command. (@hdnivara) - Now applying the `update` dependency filter to locking as well. - Now only locking previous locked dependencies. - Added `lock` command to manually save all dependency versions. diff --git a/gitman/__init__.py b/gitman/__init__.py index 0dc26180..37e27613 100644 --- a/gitman/__init__.py +++ b/gitman/__init__.py @@ -4,7 +4,7 @@ __project__ = 'GitMan' -__version__ = '1.6a1' +__version__ = '1.6a2' CLI = 'gitman' PLUGIN = 'deps' From 87486c22b2df3170b9ea2788163bf680f05b089a Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Fri, 30 Nov 2018 11:53:51 +0100 Subject: [PATCH 28/49] Initial version of --skip-changes option --- docs/interfaces/api.md | 6 +++-- docs/interfaces/cli.md | 19 +++++++++++++++ gitman/cli.py | 10 ++++++-- gitman/commands.py | 12 ++++++---- gitman/models/config.py | 6 +++-- gitman/models/source.py | 17 ++++++++++---- gitman/plugin.py | 4 ++++ gitman/tests/test_cli.py | 46 +++++++++++++++++++++++++++---------- gitman/tests/test_plugin.py | 26 +++++++++++++++++---- 9 files changed, 115 insertions(+), 31 deletions(-) diff --git a/docs/interfaces/api.md b/docs/interfaces/api.md index be3fa519..cd5a82ab 100644 --- a/docs/interfaces/api.md +++ b/docs/interfaces/api.md @@ -15,7 +15,7 @@ gitman.init() To clone/checkout the specified dependencies, call: ```python -gitman.install(*names, root=None, depth=None, force=False, fetch=False, clean=True) +gitman.install(*names, root=None, depth=None, force=False, fetch=False, clean=True skip_changes=False) ``` with optional arguments: @@ -27,13 +27,14 @@ with optional arguments: script errors can be ignored - `fetch`: indicates the latest branches should always be fetched - `clean`: indicates untracked files should be deleted from dependencies +- `skip_changes`: indicates uncommited changes should be skipped ## Update If any of the dependencies track a branch (rather than a specific commit), the current upstream version of that branch can be checked out by calling: ```python -gitman.update(*names, root=None, depth=None, recurse=False, force=False, clean=True, lock=None) +gitman.update(*names, root=None, depth=None, recurse=False, force=False, clean=True, lock=None, skip_changes=False) ``` with optional arguments: @@ -46,6 +47,7 @@ with optional arguments: script errors can be ignored - `clean`: indicates untracked files should be deleted from dependencies - `lock`: indicates updated dependency versions should be recorded +- `skip_changes`: indicates uncommited changes should be skipped ## List diff --git a/docs/interfaces/cli.md b/docs/interfaces/cli.md index f8dbb114..8e175e8e 100644 --- a/docs/interfaces/cli.md +++ b/docs/interfaces/cli.md @@ -48,6 +48,13 @@ It will exit with an error if there are any uncommitted changes in dependencies $ gitman install --force ``` +Alternatively it is possible to skip the update process only for dependencies that have uncommited changes. + +```sh +$ gitman install --skip-changes +``` + + ## Update If any of the dependencies track a branch (rather than a specific commit), the current upstream version of that branch can be checked out by running: @@ -80,6 +87,18 @@ or to additionally get the latest versions of all nested dependencies, run: $ gitman update --all ``` +It will exit with an error if there are any uncommitted changes in dependencies or a post-install script fails. To overwrite all changes or ignore script failures, run: + +```sh +$ gitman update --force +``` + +Alternatively it is possible to skip the update process only for dependencies that have uncommited changes. + +```sh +$ gitman update --skip-changes +``` + ## List To display the currently checked out dependencies, run: diff --git a/gitman/cli.py b/gitman/cli.py index 05773034..f2876e07 100644 --- a/gitman/cli.py +++ b/gitman/cli.py @@ -35,6 +35,10 @@ def main(args=None, function=None): # pylint: disable=too-many-statements help="overwrite uncommitted changes in dependencies") options.add_argument('-c', '--clean', action='store_true', help="delete ignored files in dependencies") + options.add_argument('-s', '--skip-changes', action='store_true', + dest='skip_changes', + help="skip uncommitted changes in dependencies") + shared = {'formatter_class': common.WideHelpFormatter} # Main parser @@ -139,7 +143,8 @@ def _get_command(function, namespace): # pylint: disable=too-many-statements kwargs.update(root=namespace.root, depth=namespace.depth, force=namespace.force, - clean=namespace.clean) + clean=namespace.clean, + skip_changes=namespace.skip_changes) if namespace.command == 'install': kwargs.update(fetch=namespace.fetch) if namespace.command == 'update': @@ -189,7 +194,8 @@ def _run_command(function, args, kwargs): log.debug("Command canceled") except exceptions.UncommittedChanges as exception: _show_error(exception) - exit_message = "Run again with '--force' to discard changes" + exit_message = ("Run again with '--force' to discard changes " + "or '--skip-changes' to skip changes") except exceptions.ScriptFailure as exception: _show_error(exception) exit_message = "Run again with '--force' to ignore script errors" diff --git a/gitman/commands.py b/gitman/commands.py index 7debe040..fa840628 100644 --- a/gitman/commands.py +++ b/gitman/commands.py @@ -54,7 +54,7 @@ def init(): @restore_cwd def install(*names, root=None, depth=None, - force=False, fetch=False, clean=True): + force=False, fetch=False, clean=True, skip_changes=False): """Install dependencies for a project. Optional arguments: @@ -66,7 +66,7 @@ def install(*names, root=None, depth=None, script errors can be ignored - `fetch`: indicates the latest branches should always be fetched - `clean`: indicates untracked files should be deleted from dependencies - + - `skip_changes`: indicates uncommited changes should be skipped """ log.info("%sInstalling dependencies: %s", 'force-' if force else '', @@ -81,7 +81,7 @@ def install(*names, root=None, depth=None, common.newline() count = config.install_dependencies( *names, update=False, depth=depth, - force=force, fetch=fetch, clean=clean, + force=force, fetch=fetch, clean=clean, skip_changes=skip_changes ) if count: @@ -92,7 +92,8 @@ def install(*names, root=None, depth=None, @restore_cwd def update(*names, root=None, depth=None, - recurse=False, force=False, clean=True, lock=None): # pylint: disable=redefined-outer-name + recurse=False, force=False, clean=True, lock=None, # pylint: disable=redefined-outer-name + skip_changes=False): """Update dependencies for a project. Optional arguments: @@ -105,7 +106,7 @@ def update(*names, root=None, depth=None, script errors can be ignored - `clean`: indicates untracked files should be deleted from dependencies - `lock`: indicates updated dependency versions should be recorded - + - `skip_changes`: indicates uncommited changes should be skipped """ log.info("%s dependencies%s: %s", 'Force updating' if force else 'Updating', @@ -122,6 +123,7 @@ def update(*names, root=None, depth=None, count = config.install_dependencies( *names, update=True, depth=depth, recurse=recurse, force=force, fetch=True, clean=clean, + skip_changes=skip_changes ) if count and lock is not False: diff --git a/gitman/models/config.py b/gitman/models/config.py index c3d74fb2..30c86669 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -64,7 +64,8 @@ def get_path(self, name=None): def install_dependencies(self, *names, depth=None, update=True, recurse=False, - force=False, fetch=False, clean=True): + force=False, fetch=False, clean=True, + skip_changes=False): """Download or update the specified dependencies.""" if depth == 0: log.info("Skipped directory: %s", self.location_path) @@ -87,7 +88,8 @@ def install_dependencies(self, *names, depth=None, log.info("Skipped dependency: %s", source.name) continue - source.update_files(force=force, fetch=fetch, clean=clean) + source.update_files(force=force, fetch=fetch, clean=clean, + skip_changes=skip_changes) source.create_link(self.root, force=force) common.newline() count += 1 diff --git a/gitman/models/source.py b/gitman/models/source.py index 75dd37e9..351a3eae 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -63,7 +63,8 @@ def __ne__(self, other): def __lt__(self, other): return self.name < other.name - def update_files(self, force=False, fetch=False, clean=True): + def update_files(self, force=False, fetch=False, clean=True, + skip_changes=False): """Ensure the source matches the specified revision.""" log.info("Updating source files...") @@ -80,9 +81,17 @@ def update_files(self, force=False, fetch=False, clean=True): # Check for uncommitted changes if not force: log.debug("Confirming there are no uncommitted changes...") - if git.changes(self.type, include_untracked=clean): - msg = "Uncommitted changes in {}".format(os.getcwd()) - raise exceptions.UncommittedChanges(msg) + if skip_changes: + if git.changes(self.type, include_untracked=clean, + display_status=False): + msg = ("Skip update due to uncommitted changes " + "in {}").format(os.getcwd()) + common.show(msg, color='git_changes') + return + else: + if git.changes(self.type, include_untracked=clean): + msg = "Uncommitted changes in {}".format(os.getcwd()) + raise exceptions.UncommittedChanges(msg) # Fetch the desired revision if fetch or git.is_fetch_required(self.type, self.rev): diff --git a/gitman/plugin.py b/gitman/plugin.py index 00ecadc2..23917c4a 100644 --- a/gitman/plugin.py +++ b/gitman/plugin.py @@ -24,6 +24,10 @@ def main(args=None): '-f', '--force', action='store_true', help="overwrite uncommitted changes in dependencies", ) + parser.add_argument( + '-s', '--skip-changes', action='store_true', dest='skip_changes', + help="skip uncommitted changes in dependencies" + ) parser.add_argument( '-c', '--clean', action='store_true', help="delete ignored files when updating dependencies", diff --git a/gitman/tests/test_cli.py b/gitman/tests/test_cli.py index 547a4ad5..d202beaa 100644 --- a/gitman/tests/test_cli.py +++ b/gitman/tests/test_cli.py @@ -70,7 +70,8 @@ def test_install(self, mock_install): cli.main(['install']) mock_install.assert_called_once_with( - root=None, depth=5, force=False, fetch=False, clean=False) + root=None, depth=5, force=False, fetch=False, clean=False, + skip_changes=False) @patch('gitman.commands.install') def test_install_root(self, mock_install): @@ -79,7 +80,8 @@ def test_install_root(self, mock_install): mock_install.assert_called_once_with( root='mock/path/to/root', depth=5, - force=False, fetch=False, clean=False) + force=False, fetch=False, clean=False, + skip_changes=False) @patch('gitman.commands.install') def test_install_force(self, mock_install): @@ -87,7 +89,8 @@ def test_install_force(self, mock_install): cli.main(['install', '--force']) mock_install.assert_called_once_with( - root=None, depth=5, force=True, fetch=False, clean=False) + root=None, depth=5, force=True, fetch=False, clean=False, + skip_changes=False) @patch('gitman.commands.install') def test_install_fetch(self, mock_install): @@ -95,7 +98,8 @@ def test_install_fetch(self, mock_install): cli.main(['install', '--fetch']) mock_install.assert_called_once_with( - root=None, depth=5, force=False, fetch=True, clean=False) + root=None, depth=5, force=False, fetch=True, clean=False, + skip_changes=False) @patch('gitman.commands.install') def test_install_clean(self, mock_install): @@ -103,7 +107,8 @@ def test_install_clean(self, mock_install): cli.main(['install', '--clean']) mock_install.assert_called_once_with( - root=None, depth=5, force=False, fetch=False, clean=True) + root=None, depth=5, force=False, fetch=False, clean=True, + skip_changes=False) @patch('gitman.commands.install') def test_install_specific_sources(self, mock_install): @@ -112,7 +117,8 @@ def test_install_specific_sources(self, mock_install): mock_install.assert_called_once_with( 'foo', 'bar', root=None, depth=5, - force=False, fetch=False, clean=False) + force=False, fetch=False, clean=False, + skip_changes=False) @patch('gitman.commands.install') def test_install_with_depth(self, mock_update): @@ -120,7 +126,8 @@ def test_install_with_depth(self, mock_update): cli.main(['install', '--depth', '10']) mock_update.assert_called_once_with( - root=None, depth=10, force=False, fetch=False, clean=False) + root=None, depth=10, force=False, fetch=False, clean=False, + skip_changes=False) @patch('gitman.commands.install', Mock()) def test_install_with_depth_invalid(self): @@ -141,7 +148,8 @@ def test_update(self, mock_update): mock_update.assert_called_once_with( root=None, depth=5, - force=False, clean=False, recurse=False, lock=None) + force=False, clean=False, recurse=False, lock=None, + skip_changes=False) @patch('gitman.commands.update') def test_update_recursive(self, mock_update): @@ -150,7 +158,8 @@ def test_update_recursive(self, mock_update): mock_update.assert_called_once_with( root=None, depth=5, - force=False, clean=False, recurse=True, lock=None) + force=False, clean=False, recurse=True, lock=None, + skip_changes=False) @patch('gitman.commands.update') def test_update_no_lock(self, mock_update): @@ -159,7 +168,18 @@ def test_update_no_lock(self, mock_update): mock_update.assert_called_once_with( root=None, depth=5, - force=False, clean=False, recurse=False, lock=False) + force=False, clean=False, recurse=False, lock=False, + skip_changes=False) + + @patch('gitman.commands.update') + def test_update_skip_changes(self, mock_update): + """Verify the 'update' command with skip changes option.""" + cli.main(['update', '--skip-changes']) + + mock_update.assert_called_once_with( + root=None, depth=5, + force=False, clean=False, recurse=False, lock=None, + skip_changes=True) @patch('gitman.commands.update') def test_update_specific_sources(self, mock_install): @@ -168,7 +188,8 @@ def test_update_specific_sources(self, mock_install): mock_install.assert_called_once_with( 'foo', 'bar', root=None, depth=5, - force=False, clean=False, recurse=False, lock=None) + force=False, clean=False, recurse=False, lock=None, + skip_changes=False) @patch('gitman.commands.update') def test_update_with_depth(self, mock_update): @@ -177,7 +198,8 @@ def test_update_with_depth(self, mock_update): mock_update.assert_called_once_with( root=None, depth=10, - force=False, clean=False, recurse=False, lock=None) + force=False, clean=False, recurse=False, lock=None, + skip_changes=False) class TestList: diff --git a/gitman/tests/test_plugin.py b/gitman/tests/test_plugin.py index d1f6c422..87342dd2 100644 --- a/gitman/tests/test_plugin.py +++ b/gitman/tests/test_plugin.py @@ -18,7 +18,8 @@ def test_install(self, mock_commands): assert [ call.install(root=None, depth=None, - clean=False, fetch=True, force=False), + clean=False, fetch=True, force=False, + skip_changes=False), call.install().__bool__(), # command status check ] == mock_commands.mock_calls @@ -31,7 +32,8 @@ def test_update(self, mock_commands): assert [ call.update(root=None, depth=None, - clean=True, force=False, recurse=False, lock=True), + clean=True, force=False, recurse=False, lock=True, + skip_changes=False), call.update().__bool__(), # command status check ] == mock_commands.mock_calls @@ -44,7 +46,8 @@ def test_update_recursive(self, mock_commands): assert [ call.update(root=None, depth=None, - clean=False, force=False, recurse=True, lock=True), + clean=False, force=False, recurse=True, lock=True, + skip_changes=False), call.update().__bool__(), # command status check ] == mock_commands.mock_calls @@ -57,7 +60,22 @@ def test_update_no_lock(self, mock_commands): assert [ call.update(root=None, depth=None, - clean=False, force=False, recurse=False, lock=False), + clean=False, force=False, recurse=False, lock=False, + skip_changes=False), + call.update().__bool__(), # command status check + ] == mock_commands.mock_calls + + @patch('gitman.cli.commands') + def test_update_skip_changes(self, mock_commands): + """Verify the 'update' command with skip changes option.""" + mock_commands.update.__name__ = 'mock' + + plugin.main(['--update', '--skip-changes']) + + assert [ + call.update(root=None, depth=None, + clean=False, force=False, recurse=False, lock=True, + skip_changes=True), call.update().__bool__(), # command status check ] == mock_commands.mock_calls From d560169dc537d48f97658d8c8f36637c0fd99343 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Fri, 30 Nov 2018 16:14:27 +0100 Subject: [PATCH 29/49] Improved documentation --- docs/interfaces/api.md | 4 ++-- gitman/cli.py | 2 +- gitman/commands.py | 6 ++++-- gitman/models/source.py | 2 +- gitman/plugin.py | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/interfaces/api.md b/docs/interfaces/api.md index cd5a82ab..54831e37 100644 --- a/docs/interfaces/api.md +++ b/docs/interfaces/api.md @@ -27,7 +27,7 @@ with optional arguments: script errors can be ignored - `fetch`: indicates the latest branches should always be fetched - `clean`: indicates untracked files should be deleted from dependencies -- `skip_changes`: indicates uncommited changes should be skipped +- `skip_changes`: indicates dependencies with uncommited changes should be skipped ## Update @@ -47,7 +47,7 @@ with optional arguments: script errors can be ignored - `clean`: indicates untracked files should be deleted from dependencies - `lock`: indicates updated dependency versions should be recorded -- `skip_changes`: indicates uncommited changes should be skipped +- `skip_changes`: indicates dependencies with uncommited changes should be skipped ## List diff --git a/gitman/cli.py b/gitman/cli.py index f2876e07..5344a8ab 100644 --- a/gitman/cli.py +++ b/gitman/cli.py @@ -37,7 +37,7 @@ def main(args=None, function=None): # pylint: disable=too-many-statements help="delete ignored files in dependencies") options.add_argument('-s', '--skip-changes', action='store_true', dest='skip_changes', - help="skip uncommitted changes in dependencies") + help="skip dependencies with uncommitted changes") shared = {'formatter_class': common.WideHelpFormatter} diff --git a/gitman/commands.py b/gitman/commands.py index fa840628..bbdf2570 100644 --- a/gitman/commands.py +++ b/gitman/commands.py @@ -66,7 +66,8 @@ def install(*names, root=None, depth=None, script errors can be ignored - `fetch`: indicates the latest branches should always be fetched - `clean`: indicates untracked files should be deleted from dependencies - - `skip_changes`: indicates uncommited changes should be skipped + - `skip_changes`: indicates dependencies with uncommited changes + should be skipped """ log.info("%sInstalling dependencies: %s", 'force-' if force else '', @@ -106,7 +107,8 @@ def update(*names, root=None, depth=None, script errors can be ignored - `clean`: indicates untracked files should be deleted from dependencies - `lock`: indicates updated dependency versions should be recorded - - `skip_changes`: indicates uncommited changes should be skipped + - `skip_changes`: indicates dependencies with uncommited changes + should be skipped """ log.info("%s dependencies%s: %s", 'Force updating' if force else 'Updating', diff --git a/gitman/models/source.py b/gitman/models/source.py index 351a3eae..161d02d2 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -84,7 +84,7 @@ def update_files(self, force=False, fetch=False, clean=True, if skip_changes: if git.changes(self.type, include_untracked=clean, display_status=False): - msg = ("Skip update due to uncommitted changes " + msg = ("Skipped update due to uncommitted changes " "in {}").format(os.getcwd()) common.show(msg, color='git_changes') return diff --git a/gitman/plugin.py b/gitman/plugin.py index 23917c4a..41d3a97e 100644 --- a/gitman/plugin.py +++ b/gitman/plugin.py @@ -26,7 +26,7 @@ def main(args=None): ) parser.add_argument( '-s', '--skip-changes', action='store_true', dest='skip_changes', - help="skip uncommitted changes in dependencies" + help="skip dependencies with uncommitted changes" ) parser.add_argument( '-c', '--clean', action='store_true', From 490860091b19ed00b28bb1be505427a020d383aa Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Fri, 30 Nov 2018 10:44:21 -0500 Subject: [PATCH 30/49] Update wording --- gitman/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitman/cli.py b/gitman/cli.py index 5344a8ab..54ad5f1e 100644 --- a/gitman/cli.py +++ b/gitman/cli.py @@ -195,7 +195,7 @@ def _run_command(function, args, kwargs): except exceptions.UncommittedChanges as exception: _show_error(exception) exit_message = ("Run again with '--force' to discard changes " - "or '--skip-changes' to skip changes") + "or '--skip-changes' to skip this dependency") except exceptions.ScriptFailure as exception: _show_error(exception) exit_message = "Run again with '--force' to ignore script errors" From 1fa09e4aa5b296c18cfa943e58389b3ebe4ec7d6 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Sat, 1 Dec 2018 07:03:07 +0100 Subject: [PATCH 31/49] Add add_mutually_exclusive_group for --force and --skip-changes --- gitman/cli.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/gitman/cli.py b/gitman/cli.py index 54ad5f1e..176d2c7e 100644 --- a/gitman/cli.py +++ b/gitman/cli.py @@ -18,10 +18,10 @@ def main(args=None, function=None): # pylint: disable=too-many-statements # Shared options debug = argparse.ArgumentParser(add_help=False) debug.add_argument('-V', '--version', action='version', version=VERSION) - group = debug.add_mutually_exclusive_group() - group.add_argument('-v', '--verbose', action='count', default=0, + debug_group = debug.add_mutually_exclusive_group() + debug_group.add_argument('-v', '--verbose', action='count', default=0, help="enable verbose logging") - group.add_argument('-q', '--quiet', action='store_const', const=-1, + debug_group.add_argument('-q', '--quiet', action='store_const', const=-1, dest='verbose', help="only display errors and prompts") project = argparse.ArgumentParser(add_help=False) project.add_argument('-r', '--root', metavar='PATH', @@ -31,11 +31,12 @@ def main(args=None, function=None): # pylint: disable=too-many-statements default=5, metavar="NUM", help="limit the number of dependency levels") options = argparse.ArgumentParser(add_help=False) - options.add_argument('-f', '--force', action='store_true', - help="overwrite uncommitted changes in dependencies") options.add_argument('-c', '--clean', action='store_true', help="delete ignored files in dependencies") - options.add_argument('-s', '--skip-changes', action='store_true', + options_group = options.add_mutually_exclusive_group() + options_group.add_argument('-f', '--force', action='store_true', + help="overwrite uncommitted changes in dependencies") + options_group.add_argument('-s', '--skip-changes', action='store_true', dest='skip_changes', help="skip dependencies with uncommitted changes") From fb5809a2fc576145976189432a9a460bcca73708 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Sat, 1 Dec 2018 07:23:24 +0100 Subject: [PATCH 32/49] Fix: --skip-changes should also be used recursively --- gitman/models/config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gitman/models/config.py b/gitman/models/config.py index 30c86669..e24e4fbe 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -104,6 +104,7 @@ def install_dependencies(self, *names, depth=None, force=force, fetch=fetch, clean=clean, + skip_changes=skip_changes ) common.dedent() From 37d8e3c401d084552059cd43889882a36f24872d Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Sat, 1 Dec 2018 14:32:19 +0100 Subject: [PATCH 33/49] Fix pylint issues --- gitman/cli.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/gitman/cli.py b/gitman/cli.py index 176d2c7e..03a509d6 100644 --- a/gitman/cli.py +++ b/gitman/cli.py @@ -20,9 +20,10 @@ def main(args=None, function=None): # pylint: disable=too-many-statements debug.add_argument('-V', '--version', action='version', version=VERSION) debug_group = debug.add_mutually_exclusive_group() debug_group.add_argument('-v', '--verbose', action='count', default=0, - help="enable verbose logging") + help="enable verbose logging") debug_group.add_argument('-q', '--quiet', action='store_const', const=-1, - dest='verbose', help="only display errors and prompts") + dest='verbose', + help="only display errors and prompts") project = argparse.ArgumentParser(add_help=False) project.add_argument('-r', '--root', metavar='PATH', help="root directory of the project") @@ -35,10 +36,12 @@ def main(args=None, function=None): # pylint: disable=too-many-statements help="delete ignored files in dependencies") options_group = options.add_mutually_exclusive_group() options_group.add_argument('-f', '--force', action='store_true', - help="overwrite uncommitted changes in dependencies") + help=("overwrite uncommitted changes " + "in dependencies")) options_group.add_argument('-s', '--skip-changes', action='store_true', - dest='skip_changes', - help="skip dependencies with uncommitted changes") + dest='skip_changes', + help=("skip dependencies with " + "uncommitted changes")) shared = {'formatter_class': common.WideHelpFormatter} From 57a97679ad497b72278f9af37e9cf6acefe31fa9 Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Sat, 1 Dec 2018 14:36:00 +0100 Subject: [PATCH 34/49] Skip locking for dependencies with uncommited changes (when --skip-changes option is used) --- gitman/commands.py | 3 ++- gitman/models/config.py | 20 ++++++++++++-------- gitman/models/source.py | 42 ++++++++++++++++++++++++++++++----------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/gitman/commands.py b/gitman/commands.py index bbdf2570..43432d21 100644 --- a/gitman/commands.py +++ b/gitman/commands.py @@ -132,7 +132,8 @@ def update(*names, root=None, depth=None, common.show("Recording installed versions...", color='message', log=False) common.newline() - config.lock_dependencies(*names, obey_existing=lock is None) + config.lock_dependencies(*names, obey_existing=lock is None, + skip_changes=skip_changes) if count: _run_scripts(*names, depth=depth, force=force, _config=config) diff --git a/gitman/models/config.py b/gitman/models/config.py index e24e4fbe..4c2d1879 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -151,7 +151,8 @@ def run_scripts(self, *names, depth=None, force=False): return count - def lock_dependencies(self, *names, obey_existing=True): + def lock_dependencies(self, *names, obey_existing=True, + skip_changes=False): """Lock down the immediate dependency versions.""" sources = self._get_sources(use_locked=obey_existing).copy() sources_filter = list(names) if names else [s.name for s in sources] @@ -166,13 +167,16 @@ def lock_dependencies(self, *names, obey_existing=True): log.info("Skipped dependency: %s", source.name) continue - try: - index = self.sources_locked.index(source) - except ValueError: - self.sources_locked.append(source.lock()) - else: - self.sources_locked[index] = source.lock() - count += 1 + source_locked = source.lock(skip_changes=skip_changes) + + if source_locked is not None: + try: + index = self.sources_locked.index(source) + except ValueError: + self.sources_locked.append(source_locked) + else: + self.sources_locked[index] = source_locked + count += 1 shell.cd(self.location_path, _show=False) diff --git a/gitman/models/source.py b/gitman/models/source.py index 161d02d2..03a22e3c 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -156,7 +156,8 @@ def run_scripts(self, force=False): common.show(*lines, color='shell_output') common.newline() - def identify(self, allow_dirty=True, allow_missing=True): + def identify(self, allow_dirty=True, allow_missing=True, + skip_changes=False): """Get the path and current repository URL and hash.""" if os.path.isdir(self.name): @@ -167,14 +168,23 @@ def identify(self, allow_dirty=True, allow_missing=True): path = os.getcwd() url = git.get_url(self.type) if git.changes(self.type, - display_status=not allow_dirty, _show=True): - if not allow_dirty: - msg = "Uncommitted changes in {}".format(os.getcwd()) - raise exceptions.UncommittedChanges(msg) + display_status=not allow_dirty and not skip_changes, + _show=not skip_changes): + + if allow_dirty: + common.show(self.DIRTY, color='git_dirty', log=False) + common.newline() + return path, url, self.DIRTY + + if skip_changes: + msg = ("Skipped lock due to uncommitted changes " + "in {}").format(os.getcwd()) + common.show(msg, color='git_changes') + common.newline() + return path, url, self.DIRTY - common.show(self.DIRTY, color='git_dirty', log=False) - common.newline() - return path, url, self.DIRTY + msg = "Uncommitted changes in {}".format(os.getcwd()) + raise exceptions.UncommittedChanges(msg) rev = git.get_hash(self.type, _show=True) common.show(rev, color='git_rev', log=False) @@ -186,10 +196,20 @@ def identify(self, allow_dirty=True, allow_missing=True): raise self._invalid_repository - def lock(self, rev=None): - """Return a locked version of the current source.""" + def lock(self, rev=None, allow_dirty=False, skip_changes=False): + """Create a locked source object. + + Return a locked version of the current source if not dirty + otherwise None. + """ + if rev is None: - _, _, rev = self.identify(allow_dirty=False, allow_missing=False) + _, _, rev = self.identify(allow_dirty=allow_dirty, + allow_missing=False, + skip_changes=skip_changes) + + if rev == self.DIRTY: + return None source = self.__class__(self.type, self.repo, self.name, rev, From 18b2e4d9d0601f8d91cccf75868ad5c936b40f16 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Sat, 1 Dec 2018 21:20:29 -0500 Subject: [PATCH 35/49] Update docs --- docs/interfaces/api.md | 10 ++++++---- docs/interfaces/cli.md | 5 ++--- gitman/__init__.py | 2 +- gitman/commands.py | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/interfaces/api.md b/docs/interfaces/api.md index 54831e37..b335ba82 100644 --- a/docs/interfaces/api.md +++ b/docs/interfaces/api.md @@ -15,7 +15,8 @@ gitman.init() To clone/checkout the specified dependencies, call: ```python -gitman.install(*names, root=None, depth=None, force=False, fetch=False, clean=True skip_changes=False) +gitman.install(*names, root=None, depth=None, + force=False, fetch=False, clean=True skip_changes=False) ``` with optional arguments: @@ -27,14 +28,15 @@ with optional arguments: script errors can be ignored - `fetch`: indicates the latest branches should always be fetched - `clean`: indicates untracked files should be deleted from dependencies -- `skip_changes`: indicates dependencies with uncommited changes should be skipped +- `skip_changes`: indicates dependencies with uncommitted changes should be skipped ## Update If any of the dependencies track a branch (rather than a specific commit), the current upstream version of that branch can be checked out by calling: ```python -gitman.update(*names, root=None, depth=None, recurse=False, force=False, clean=True, lock=None, skip_changes=False) +gitman.update(*names, root=None, depth=None, recurse=False, + force=False, clean=True, lock=None, skip_changes=False) ``` with optional arguments: @@ -47,7 +49,7 @@ with optional arguments: script errors can be ignored - `clean`: indicates untracked files should be deleted from dependencies - `lock`: indicates updated dependency versions should be recorded -- `skip_changes`: indicates dependencies with uncommited changes should be skipped +- `skip_changes`: indicates dependencies with uncommitted changes should be skipped ## List diff --git a/docs/interfaces/cli.md b/docs/interfaces/cli.md index 8e175e8e..b1185833 100644 --- a/docs/interfaces/cli.md +++ b/docs/interfaces/cli.md @@ -48,13 +48,12 @@ It will exit with an error if there are any uncommitted changes in dependencies $ gitman install --force ``` -Alternatively it is possible to skip the update process only for dependencies that have uncommited changes. +Alternatively, it is possible to skip the update process for dependencies that have uncommitted changes: ```sh $ gitman install --skip-changes ``` - ## Update If any of the dependencies track a branch (rather than a specific commit), the current upstream version of that branch can be checked out by running: @@ -93,7 +92,7 @@ It will exit with an error if there are any uncommitted changes in dependencies $ gitman update --force ``` -Alternatively it is possible to skip the update process only for dependencies that have uncommited changes. +Alternatively, it is possible to skip the update process only for dependencies that have uncommitted changes: ```sh $ gitman update --skip-changes diff --git a/gitman/__init__.py b/gitman/__init__.py index 37e27613..769c4a5c 100644 --- a/gitman/__init__.py +++ b/gitman/__init__.py @@ -4,7 +4,7 @@ __project__ = 'GitMan' -__version__ = '1.6a2' +__version__ = '1.6a3' CLI = 'gitman' PLUGIN = 'deps' diff --git a/gitman/commands.py b/gitman/commands.py index 43432d21..f82c7d71 100644 --- a/gitman/commands.py +++ b/gitman/commands.py @@ -66,7 +66,7 @@ def install(*names, root=None, depth=None, script errors can be ignored - `fetch`: indicates the latest branches should always be fetched - `clean`: indicates untracked files should be deleted from dependencies - - `skip_changes`: indicates dependencies with uncommited changes + - `skip_changes`: indicates dependencies with uncommitted changes should be skipped """ log.info("%sInstalling dependencies: %s", @@ -107,7 +107,7 @@ def update(*names, root=None, depth=None, script errors can be ignored - `clean`: indicates untracked files should be deleted from dependencies - `lock`: indicates updated dependency versions should be recorded - - `skip_changes`: indicates dependencies with uncommited changes + - `skip_changes`: indicates dependencies with uncommitted changes should be skipped """ log.info("%s dependencies%s: %s", From 8b6f4531912f292133b73933671c142efb6ea85c Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Tue, 25 Dec 2018 12:50:52 -0500 Subject: [PATCH 36/49] Update project tooling --- .appveyor.yml | 5 +- .coveragerc | 9 + .isort.cfg | 7 +- .mypy.ini | 7 + .pycodestyle.ini | 9 - .pylint.ini | 5 +- .travis.yml | 5 +- .verchew.ini | 12 +- CHANGELOG.md | 70 ++- CONTRIBUTING.md | 41 +- MANIFEST.in | 4 - Makefile | 159 +++---- Pipfile | 49 --- Pipfile.lock | 642 --------------------------- bin/verchew | 22 +- gitman/__init__.py | 34 +- gitman/__main__.py | 11 +- gitman/cli.py | 264 +++++++---- gitman/commands.py | 90 ++-- gitman/common.py | 13 +- gitman/git.py | 29 +- gitman/models/config.py | 35 +- gitman/models/source.py | 79 ++-- gitman/plugin.py | 73 +++- gitman/settings.py | 2 +- gitman/shell.py | 17 +- gitman/system.py | 3 +- gitman/tests/conftest.py | 3 +- gitman/tests/test_cli.py | 148 ++++--- gitman/tests/test_commands.py | 7 - gitman/tests/test_common.py | 36 +- gitman/tests/test_git.py | 180 ++++---- gitman/tests/test_models_config.py | 20 +- gitman/tests/test_models_source.py | 4 +- gitman/tests/test_plugin.py | 62 ++- gitman/tests/test_shell.py | 5 +- gitman/tests/test_system.py | 1 - mkdocs.yml | 2 +- poetry.lock | 673 +++++++++++++++++++++++++++++ pyproject.toml | 95 ++++ scent.py | 7 +- setup.py | 81 ---- tests/__init__.py | 2 +- tests/test_api.py | 94 ++-- tests/test_cli.py | 6 +- tests/test_main.py | 1 - 46 files changed, 1681 insertions(+), 1442 deletions(-) create mode 100644 .mypy.ini delete mode 100644 .pycodestyle.ini delete mode 100644 MANIFEST.in delete mode 100644 Pipfile delete mode 100644 Pipfile.lock create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/.appveyor.yml b/.appveyor.yml index 32138abf..e25255be 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -10,7 +10,7 @@ environment: PYTHON_MINOR: 7 cache: - - .venv -> Pipfile.lock + - .venv -> Makefile install: # Add Make and Python to the PATH @@ -19,7 +19,8 @@ install: - set PATH=C:\Python%PYTHON_MAJOR%%PYTHON_MINOR%;%PATH% - set PATH=C:\Python%PYTHON_MAJOR%%PYTHON_MINOR%\Scripts;%PATH% # Install system dependencies - - pip install pipenv + - curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python + - set PATH=%USERPROFILE%\.poetry\bin;%PATH% - make doctor # Install project dependencies - make install diff --git a/.coveragerc b/.coveragerc index 5033e7f3..5aa119cc 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,6 +2,15 @@ branch = true +data_file = .cache/coverage + omit = .venv/* */tests/* + */__main__.py + +[report] + +exclude_lines = + pragma: no cover + raise NotImplementedError diff --git a/.isort.cfg b/.isort.cfg index 361814db..55a392b7 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -2,12 +2,15 @@ not_skip = __init__.py -multi_line_output = 5 +multi_line_output = 3 +known_standard_library = dataclasses,typing_extensions known_third_party = click,log -known_first_party = demo +known_first_party = gitman combine_as_imports = true +force_grid_wrap = false include_trailing_comma = true lines_after_imports = 2 +line_length = 88 diff --git a/.mypy.ini b/.mypy.ini new file mode 100644 index 00000000..264105fe --- /dev/null +++ b/.mypy.ini @@ -0,0 +1,7 @@ +[mypy] + +ignore_missing_imports = true +no_implicit_optional = true +check_untyped_defs = true + +cache_dir = .cache/mypy/ diff --git a/.pycodestyle.ini b/.pycodestyle.ini deleted file mode 100644 index 16c85a65..00000000 --- a/.pycodestyle.ini +++ /dev/null @@ -1,9 +0,0 @@ -[pycodestyle] - -# W504 line break after binary operator -# E401 multiple imports on one line (checked by PyLint) -# E402 module level import not at top of file (checked by PyLint) -# E501 line too long (checked by PyLint) -# E711 comparison to None (used to improve test style) -# E712 comparison to True (used to improve test style) -ignore = W504,E401,E402,E501,E711,E712 diff --git a/.pylint.ini b/.pylint.ini index b38c6328..c915f699 100644 --- a/.pylint.ini +++ b/.pylint.ini @@ -127,6 +127,7 @@ disable= logging-not-lazy, redefined-builtin, too-many-public-methods, + bad-continuation, # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option @@ -270,7 +271,7 @@ indent-after-paren=4 indent-string=' ' # Maximum number of characters on a single line. -max-line-length=79 +max-line-length=88 # Maximum number of lines in a module max-module-lines=1000 @@ -315,7 +316,7 @@ ignore-docstrings=yes ignore-imports=no # Minimum lines number of a similarity. -min-similarity-lines=4 +min-similarity-lines=6 [SPELLING] diff --git a/.travis.yml b/.travis.yml index 03524e7c..058b695c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,14 +11,15 @@ matrix: cache: pip: true directories: - - .venv + - ${VIRTUAL_ENV} env: global: - RANDOM_SEED=0 before_install: - - pip install pipenv + - curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python + - source $HOME/.poetry/env - make doctor install: diff --git a/.verchew.ini b/.verchew.ini index ba9d09dc..a6eb2695 100644 --- a/.verchew.ini +++ b/.verchew.ini @@ -6,22 +6,22 @@ version = GNU Make [Python] cli = python -version = Python 3. +version = Python 3 -[pipenv] +[Poetry] -cli = pipenv -versions = 10. | 11. +cli = poetry +version = 0.12 [Git] cli = git -version = 2. +version = 2 [Graphviz] cli = dot cli_version_arg = -V -version = 2. +version = 2 optional = true message = This is only needed to generate UML diagrams for documentation. diff --git a/CHANGELOG.md b/CHANGELOG.md index dd0b0c8f..c601b9c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,9 @@ -# Revision History - -## 1.6 (unreleased) +# 1.6 (unreleased) - Added `git svn` support. (@daniel-brosche) - Added `$GITMAN_CACHE_DISABLE` to disable repository mirrors. (@daniel-brosche) -## 1.5 (2018-09-08) +# 1.5 (2018-09-08) - Added `--keep-location` option on `uninstall`. (@DavidWatkins) - Added feature to enable sparse checkouts. See the docs for further information. (@xenji) @@ -13,74 +11,74 @@ - **BREAKING**: Renamed `--no-lock` to `--skip-lock` on `update` command. - **BREAKING**: Renamed `--no-dirty` to `--fail-if-dirty` on `list` command. -## 1.4 (2017-03-21) +# 1.4 (2017-03-21) - Allow config files to exist in subdirectories of the main project. - Added `$GITMAN_CACHE` to customize the repository cache location. -## 1.3 (2017-02-03) +# 1.3 (2017-02-03) - Added `init` command to generate sample config files. - Added support for post-install scripts on dependencies. - Updated config format to support `null` for links. -## 1.2 (2017-01-08) +# 1.2 (2017-01-08) - Added preliminary Windows support. (@StudioEtrange) -## 1.1 (2017-01-06) +# 1.1 (2017-01-06) - Added coloring to the command-line output. - Fixed issue where `` could be saved as a locked revision. -## 1.0.2 (2016-07-28) +# 1.0.2 (2016-07-28) - Moved documentation to http://gitman.readthedocs.io/. -## 1.0.1 (2016-05-31) +# 1.0.1 (2016-05-31) - Replaced calls to `git remote add origin` with `git remote set-url origin`. -## 1.0 (2016-05-22) +# 1.0 (2016-05-22) - Initial stable release. -## 0.11 (2016-05-10) +# 0.11 (2016-05-10) - Removed dependency on `sh` to support Cygwin/MinGW/etc. on Windows. - Dropped Python 3.4 support for `subprocess` and `*args` improvements. - **BREAKING**: Renamed config file key `dir` to `name`. -## 0.10 (2016-04-14) +# 0.10 (2016-04-14) - Added `show` command to display dependency and internal paths. -## 0.9 (2016-03-31) +# 0.9 (2016-03-31) - Added `edit` command to launch the config file. - Depth now defaults to 5 to prevent infinite recursion. - Fixed handling of source lists containing different dependencies. -## 0.8.3 (2016-03-14) +# 0.8.3 (2016-03-14) - Renamed to GitMan. -## 0.8.2 (2016-02-24) +# 0.8.2 (2016-02-24) - Updated to YORM v0.6. -## 0.8.1 (2016-01-21) +# 0.8.1 (2016-01-21) - Added an error message when attempting to lock invalid repositories. -## 0.8 (2016-01-13) +# 0.8 (2016-01-13) - Switched to using repository mirrors to speed up cloning. - Disabled automatic fetching on install. - Added `--fetch` option on `install` to always fetch. - Now displaying `git status` output when there are changes. -## 0.7 (2015-12-22) +# 0.7 (2015-12-22) - Fixed `git remote rm` command. (@hdnivara) - Now applying the `update` dependency filter to locking as well. @@ -88,12 +86,12 @@ - Added `lock` command to manually save all dependency versions. - Now requiring `--lock` option on `update` to explicitly lock dependencies. -## 0.6 (2015-11-13) +# 0.6 (2015-11-13) - Added the ability to filter the dependency list on `install` and `update`. - Added `--depth` option to limit dependency traversal on `install`, `update`, and `list`. -## 0.5 (2015-10-20) +# 0.5 (2015-10-20) - Added Git plugin support via: `git deps`. - Removed `--no-clean` option (now the default) on `install` and `update`. @@ -103,15 +101,15 @@ - Disabled warnings when running `install` without locked sources. - Added `--no-lock` option to disable version recording. -## 0.4.2 (2015-10-18) +# 0.4.2 (2015-10-18) - Fixed crash when running with some sources missing. -## 0.4.1 (2015-09-24) +# 0.4.1 (2015-09-24) - Switched to cloning for initial working tree creation. -## 0.4 (2015-09-18) +# 0.4 (2015-09-18) - Replaced `install` command with `update`. - Updated `install` command to use locked dependency versions. @@ -119,55 +117,55 @@ - Now requiring `--force` to `uninstall` with uncommitted changes. - Updated `list` command to show full shell commands. -## 0.3.1 (2015-09-09) +# 0.3.1 (2015-09-09) - Ensures files are not needlessly reloaded with newer versions of YORM. -## 0.3 (2015-06-26) +# 0.3 (2015-06-26) - Added `--no-clean` option to disable removing untracked files. - Added support for `rev-parse` dates as the dependency `rev`. -## 0.2.5 (2015-06-15) +# 0.2.5 (2015-06-15) - Added `--quiet` option to hide warnings. -## 0.2.4 (2015-05-19) +# 0.2.4 (2015-05-19) - Now hiding YORM logging bellow warnings. -## 0.2.3 (2015-05-17) +# 0.2.3 (2015-05-17) - Upgraded to YORM v0.4. -## 0.2.2 (2015-05-04) +# 0.2.2 (2015-05-04) - Specified YORM < v0.4. -## 0.2.1 (2015-03-12) +# 0.2.1 (2015-03-12) - Added automatic remote branch tracking in dependencies. - Now requiring `--force` when there are untracked files. -## 0.2 (2015-03-10) +# 0.2 (2015-03-10) - Added `list` command to display current URLs/SHAs. -## 0.1.4 (2014-02-27) +# 0.1.4 (2014-02-27) - Fixed an outdated index when checking for changes. -## 0.1.3 (2014-02-27) +# 0.1.3 (2014-02-27) - Fixed extra whitespace when logging shell output. -## 0.1.2 (2014-02-27) +# 0.1.2 (2014-02-27) - Added `--force` argument to: - overwrite uncommitted changes - create symbolic links in place of directories - Added live shell command output with `-vv` argument. -## 0.1 (2014-02-24) +# 0.1 (2014-02-24) - Initial release. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 19feb0de..94a3eb00 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,13 @@ -# For Contributors +# Setup -## Setup - -### Requirements +## Requirements * Make: * Windows: http://mingw.org/download/installer * Mac: http://developer.apple.com/xcode * Linux: http://www.gnu.org/software/make -* pipenv: http://docs.pipenv.org -* Pandoc: http://johnmacfarlane.net/pandoc/installing.html +* Python: `$ pyenv install` +* Poetry: https://poetry.eustace.io/docs/#installation * Graphviz: http://www.graphviz.org/Download.php To confirm these system dependencies are configured correctly: @@ -18,7 +16,7 @@ To confirm these system dependencies are configured correctly: $ make doctor ``` -### Installation +## Installation Install project dependencies into a virtual environment: @@ -26,44 +24,39 @@ Install project dependencies into a virtual environment: $ make install ``` -## Development Tasks +# Development Tasks -### Testing +## Manual -Manually run the tests: +Run the tests: ```sh $ make test ``` -or keep them running on change: +Run static analysis: ```sh -$ make watch +$ make check ``` -> In order to have OS X notifications, `brew install terminal-notifier`. - -### Documentation - Build the documentation: ```sh $ make docs ``` -### Static Analysis +## Automatic -Run linters and static analyzers: +Keep all of the above tasks running on change: ```sh -$ make pylint -$ make pycodestyle -$ make pydocstyle -$ make check # includes all checks +$ make watch ``` -## Continuous Integration +> In order to have OS X notifications, `brew install terminal-notifier`. + +# Continuous Integration The CI server will report overall build status: @@ -71,7 +64,7 @@ The CI server will report overall build status: $ make ci ``` -## Release Tasks +# Release Tasks Release to PyPI: diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 855deca1..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include *.rst *.txt *.md -recursive-include docs *.rst *.txt *.md -graft */files -graft */*/files diff --git a/Makefile b/Makefile index 4ecc29b1..7e9b5b8e 100644 --- a/Makefile +++ b/Makefile @@ -9,32 +9,27 @@ CONFIG := $(wildcard *.py) MODULES := $(wildcard $(PACKAGE)/*.py) # Virtual environment paths -export PIPENV_VENV_IN_PROJECT=true -export PIPENV_IGNORE_VIRTUALENVS=true -VENV := .venv +VIRTUAL_ENV ?= .venv # MAIN TASKS ################################################################## -SNIFFER := pipenv run sniffer - .PHONY: all all: install .PHONY: ci -ci: check test demo ## Run all tasks that determine CI status +ci: format check test mkdocs ## Run all tasks that determine CI status .PHONY: watch watch: install .clean-test ## Continuously run all CI tasks when files chanage - $(SNIFFER) + poetry run sniffer .PHONY: demo demo: install - pipenv run python setup.py develop - pipenv run gitman install --force # some scripts have intentional errors - pipenv run gitman update --force # some scripts have intentional errors - pipenv run gitman list - pipenv run gitman lock - pipenv run gitman uninstall + poetry run gitman install --force # some scripts have intentional errors + poetry run gitman update --force # some scripts have intentional errors + poetry run gitman list + poetry run gitman lock + poetry run gitman uninstall # SYSTEM DEPENDENCIES ######################################################### @@ -44,48 +39,44 @@ doctor: ## Confirm system dependencies are available # PROJECT DEPENDENCIES ######################################################## -DEPENDENCIES = $(VENV)/.pipenv-$(shell bin/checksum Pipfile* setup.py) +DEPENDENCIES := $(VIRTUAL_ENV)/.poetry-$(shell bin/checksum pyproject.toml poetry.lock) .PHONY: install -install: $(DEPENDENCIES) +install: $(DEPENDENCIES) .cache -$(DEPENDENCIES): - pipenv run python setup.py develop - pipenv install --dev +$(DEPENDENCIES): poetry.lock + @ poetry config settings.virtualenvs.in-project true + poetry install @ touch $@ -# CHECKS ###################################################################### - -ISORT := pipenv run isort -PYLINT := pipenv run pylint -PYCODESTYLE := pipenv run pycodestyle -PYDOCSTYLE := pipenv run pydocstyle - -.PHONY: check -check: isort pylint pycodestyle pydocstyle ## Run linters and static analysis +poetry.lock: pyproject.toml + poetry lock + @ touch $@ -.PHONY: isort -isort: install - $(ISORT) $(PACKAGES) $(CONFIG) --recursive --apply +.cache: + @ mkdir -p .cache -.PHONY: pylint -pylint: install - $(PYLINT) $(PACKAGES) $(CONFIG) --rcfile=.pylint.ini +# CHECKS ###################################################################### -.PHONY: pycodestyle -pycodestyle: install - $(PYCODESTYLE) $(PACKAGES) $(CONFIG) --config=.pycodestyle.ini +.PHONY: format +format: install + poetry run isort $(PACKAGES) --recursive --apply + # TODO: Enable after dropping Python 3.5 support + - poetry run black $(PACKAGES) + @ echo -.PHONY: pydocstyle -pydocstyle: install - $(PYDOCSTYLE) $(PACKAGES) $(CONFIG) +.PHONY: check +check: install format ## Run formaters, linters, and static analysis +ifdef CI + git diff --exit-code +endif + poetry run pylint $(PACKAGES) --rcfile=.pylint.ini + # TODO: Enable after dropping Python 3.5 support + # poetry run mypy $(PACKAGES) --config-file=.mypy.ini + poetry run pydocstyle $(PACKAGES) $(CONFIG) # TESTS ####################################################################### -PYTEST := pipenv run pytest -COVERAGE := pipenv run coverage -COVERAGE_SPACE := pipenv run coveragespace - RANDOM_SEED ?= $(shell date +%s) FAILURES := .cache/v/cache/lastfailed @@ -101,23 +92,23 @@ test: test-all ## Run unit and integration tests .PHONY: test-unit test-unit: install @ ( mv $(FAILURES) $(FAILURES).bak || true ) > /dev/null 2>&1 - $(PYTEST) $(PACKAGE) $(PYTEST_OPTIONS) + poetry run pytest $(PACKAGE) $(PYTEST_OPTIONS) @ ( mv $(FAILURES).bak $(FAILURES) || true ) > /dev/null 2>&1 - $(COVERAGE_SPACE) $(REPOSITORY) unit + poetry run coveragespace $(REPOSITORY) unit .PHONY: test-int test-int: install - @ if test -e $(FAILURES); then TEST_INTEGRATION=true $(PYTEST) tests $(PYTEST_RERUN_OPTIONS); fi + @ if test -e $(FAILURES); then TEST_INTEGRATION=true poetry run pytest tests $(PYTEST_RERUN_OPTIONS); fi @ rm -rf $(FAILURES) - TEST_INTEGRATION=true $(PYTEST) tests $(PYTEST_OPTIONS) - $(COVERAGE_SPACE) $(REPOSITORY) integration + TEST_INTEGRATION=true poetry run pytest tests $(PYTEST_OPTIONS) + poetry run coveragespace $(REPOSITORY) integration .PHONY: test-all test-all: install - @ if test -e $(FAILURES); then TEST_INTEGRATION=true $(PYTEST) $(PACKAGES) $(PYTEST_RERUN_OPTIONS); fi + @ if test -e $(FAILURES); then TEST_INTEGRATION=true poetry run pytest $(PACKAGES) $(PYTEST_RERUN_OPTIONS); fi @ rm -rf $(FAILURES) - TEST_INTEGRATION=true $(PYTEST) $(PACKAGES) $(PYTEST_OPTIONS) - $(COVERAGE_SPACE) $(REPOSITORY) overall + TEST_INTEGRATION=true poetry run pytest $(PACKAGES) $(PYTEST_OPTIONS) + poetry run coveragespace $(REPOSITORY) overall .PHONY: read-coverage read-coverage: @@ -125,82 +116,59 @@ read-coverage: # DOCUMENTATION ############################################################### -PYREVERSE := pipenv run pyreverse -MKDOCS := pipenv run mkdocs - MKDOCS_INDEX := site/index.html .PHONY: docs -docs: uml mkdocs ## Generate documentation - -.PHONY: docs/demo.gif -docs/demo.gif: - @ sleep 3; clear; sleep 1 - gitman install --force - @ sleep 3; clear; sleep 1 - gitman list - @ sleep 3; clear; sleep 1 - gitman lock - @ sleep 3; clear; sleep 1 - gitman uninstall +docs: mkdocs uml ## Generate documentation and UML + +.PHONY: mkdocs +mkdocs: install $(MKDOCS_INDEX) +$(MKDOCS_INDEX): mkdocs.yml docs/*.md + @ mkdir -p docs/about + @ cd docs && ln -sf ../README.md index.md + @ cd docs/about && ln -sf ../../CHANGELOG.md changelog.md + @ cd docs/about && ln -sf ../../CONTRIBUTING.md contributing.md + @ cd docs/about && ln -sf ../../LICENSE.md license.md + poetry run mkdocs build --clean --strict .PHONY: uml uml: install docs/*.png docs/*.png: $(MODULES) - $(PYREVERSE) $(PACKAGE) -p $(PACKAGE) -a 1 -f ALL -o png --ignore tests + poetry run pyreverse $(PACKAGE) -p $(PACKAGE) -a 1 -f ALL -o png --ignore tests - mv -f classes_$(PACKAGE).png docs/classes.png - mv -f packages_$(PACKAGE).png docs/packages.png -.PHONY: mkdocs -mkdocs: install $(MKDOCS_INDEX) -$(MKDOCS_INDEX): mkdocs.yml docs/*.md - ln -sf `realpath README.md --relative-to=docs` docs/index.md - ln -sf `realpath CHANGELOG.md --relative-to=docs/about` docs/about/changelog.md - ln -sf `realpath CONTRIBUTING.md --relative-to=docs/about` docs/about/contributing.md - ln -sf `realpath LICENSE.md --relative-to=docs/about` docs/about/license.md - $(MKDOCS) build --clean --strict - .PHONY: mkdocs-live mkdocs-live: mkdocs eval "sleep 3; bin/open http://127.0.0.1:8000" & - $(MKDOCS) serve + poetry run mkdocs serve # BUILD ####################################################################### -PYINSTALLER := pipenv run pyinstaller -PYINSTALLER_MAKESPEC := pipenv run pyi-makespec - DIST_FILES := dist/*.tar.gz dist/*.whl EXE_FILES := dist/$(PROJECT).* -.PHONY: build -build: dist - .PHONY: dist dist: install $(DIST_FILES) -$(DIST_FILES): $(MODULES) +$(DIST_FILES): $(MODULES) pyproject.toml rm -f $(DIST_FILES) - pipenv run python setup.py check --strict --metadata - pipenv run python setup.py sdist - pipenv run python setup.py bdist_wheel + poetry build .PHONY: exe exe: install $(EXE_FILES) $(EXE_FILES): $(MODULES) $(PROJECT).spec # For framework/shared support: https://github.com/yyuu/pyenv/wiki - $(PYINSTALLER) $(PROJECT).spec --noconfirm --clean + poetry run pyinstaller $(PROJECT).spec --noconfirm --clean $(PROJECT).spec: - $(PYINSTALLER_MAKESPEC) $(PACKAGE)/__main__.py --onefile --windowed --name=$(PROJECT) + poetry run pyi-makespec $(PACKAGE)/__main__.py --onefile --windowed --name=$(PROJECT) # RELEASE ##################################################################### -TWINE := pipenv run twine - .PHONY: upload upload: dist ## Upload the current version to PyPI git diff --name-only --exit-code - $(TWINE) upload dist/*.* + poetry publish bin/open https://pypi.org/project/$(PROJECT) # CLEANUP ##################################################################### @@ -210,21 +178,20 @@ clean: .clean-build .clean-docs .clean-test .clean-install ## Delete all generat .PHONY: clean-all clean-all: clean - rm -rf $(VENV) + rm -rf $(VIRTUAL_ENV) .PHONY: .clean-install .clean-install: - find $(PACKAGES) -name '*.pyc' -delete find $(PACKAGES) -name '__pycache__' -delete rm -rf *.egg-info .PHONY: .clean-test .clean-test: - rm -rf .cache .pytest .coverage htmlcov xmlreport + rm -rf .cache .pytest .coverage htmlcov .PHONY: .clean-docs .clean-docs: - rm -rf *.rst docs/apidocs *.html docs/*.png site + rm -rf docs/*.png site .PHONY: .clean-build .clean-build: diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 69819930..00000000 --- a/Pipfile +++ /dev/null @@ -1,49 +0,0 @@ -[[source]] - -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[requires] - -python_version = "3" - -[packages] - -gitman = { path = ".", editable = true } - -[dev-packages] - -# Linters -pylint = "~=2.1" -pycodestyle = "~=2.3" -pydocstyle = "~=2.0" - -# Testing -pytest = "~=3.3" -pytest-describe = "*" -pytest-expecter = "*" -pytest-random = "*" -pytest-cov = "*" -pathlib2 = "*" -freezegun = "*" - -# Reports -coveragespace = "*" - -# Documentation -mkdocs = "<1" -docutils = "*" -pygments = "*" - -# Build -wheel = "*" -pyinstaller = "*" - -# Release -twine = "*" - -# Tooling -sniffer = "*" -MacFSEvents = { version = "*", sys_platform = "== 'darwin'" } -pync = { version = "*", sys_platform = "== 'darwin'" } diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 69db1562..00000000 --- a/Pipfile.lock +++ /dev/null @@ -1,642 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "1614acf2333a1b4dc5ba33c941998436cee08ae89b051946ad13206b10e57778" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "gitman": { - "editable": true, - "path": "." - }, - "parse": { - "hashes": [ - "sha256:c3cdf6206f22aeebfa00e5b954fcfea13d1b2dc271c75806b6025b94fb490939" - ], - "version": "==1.8.4" - }, - "pyyaml": { - "hashes": [ - "sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b", - "sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf", - "sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a", - "sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3", - "sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1", - "sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1", - "sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613", - "sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04", - "sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f", - "sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537", - "sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531" - ], - "version": "==3.13" - }, - "simplejson": { - "hashes": [ - "sha256:067a7177ddfa32e1483ba5169ebea1bc2ea27f224853211ca669325648ca5642", - "sha256:2fc546e6af49fb45b93bbe878dea4c48edc34083729c0abd09981fe55bdf7f91", - "sha256:354fa32b02885e6dae925f1b5bbf842c333c1e11ea5453ddd67309dc31fdb40a", - "sha256:37e685986cf6f8144607f90340cff72d36acf654f3653a6c47b84c5c38d00df7", - "sha256:3af610ee72efbe644e19d5eaad575c73fb83026192114e5f6719f4901097fce2", - "sha256:3b919fc9cf508f13b929a9b274c40786036b31ad28657819b3b9ba44ba651f50", - "sha256:3dd289368bbd064974d9a5961101f080e939cbe051e6689a193c99fb6e9ac89b", - "sha256:6c3258ffff58712818a233b9737fe4be943d306c40cf63d14ddc82ba563f483a", - "sha256:75e3f0b12c28945c08f54350d91e624f8dd580ab74fd4f1bbea54bc6b0165610", - "sha256:b1f329139ba647a9548aa05fb95d046b4a677643070dc2afc05fa2e975d09ca5", - "sha256:ee9625fc8ee164902dfbb0ff932b26df112da9f871c32f0f9c1bcf20c350fe2a", - "sha256:fb2530b53c28f0d4d84990e945c2ebb470edb469d63e389bf02ff409012fe7c5" - ], - "version": "==3.16.0" - }, - "yorm": { - "hashes": [ - "sha256:863674ad8e1cfe5b8aa42e333039c0f54d591bb0d28ff9d4299b8109a02239f9", - "sha256:aa540ccb087a9c3a8eac385073a2da1c5362591b45dec7a9a2cb212e898d9f84" - ], - "version": "==1.6" - } - }, - "develop": { - "altgraph": { - "hashes": [ - "sha256:d6814989f242b2b43025cba7161fc1b8fb487a62cd49c49245d6fd01c18ac997", - "sha256:ddf5320017147ba7b810198e0b6619bd7b5563aa034da388cea8546b877f9b0c" - ], - "version": "==0.16.1" - }, - "astroid": { - "hashes": [ - "sha256:292fa429e69d60e4161e7612cb7cc8fa3609e2e309f80c224d93a76d5e7b58be", - "sha256:c7013d119ec95eb626f7a2011f0b63d0c9a095df9ad06d8507b37084eada1a8d" - ], - "version": "==2.0.4" - }, - "atomicwrites": { - "hashes": [ - "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", - "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee" - ], - "version": "==1.2.1" - }, - "attrs": { - "hashes": [ - "sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", - "sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb" - ], - "version": "==18.2.0" - }, - "backports.shutil-get-terminal-size": { - "hashes": [ - "sha256:0975ba55054c15e346944b38956a4c9cbee9009391e41b86c68990effb8c1f64", - "sha256:713e7a8228ae80341c70586d1cc0a8caa5207346927e23d09dcbcaf18eadec80" - ], - "version": "==1.0.0" - }, - "bleach": { - "hashes": [ - "sha256:48d39675b80a75f6d1c3bdbffec791cf0bbbab665cf01e20da701c77de278718", - "sha256:73d26f018af5d5adcdabf5c1c974add4361a9c76af215fe32fdec8a6fc5fb9b9" - ], - "version": "==3.0.2" - }, - "certifi": { - "hashes": [ - "sha256:339dc09518b07e2fa7eda5450740925974815557727d6bd35d319c1524a04a4c", - "sha256:6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a" - ], - "version": "==2018.10.15" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "click": { - "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" - ], - "version": "==7.0" - }, - "colorama": { - "hashes": [ - "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda", - "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1" - ], - "version": "==0.3.9" - }, - "coverage": { - "hashes": [ - "sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba", - "sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed", - "sha256:0bf8cbbd71adfff0ef1f3a1531e6402d13b7b01ac50a79c97ca15f030dba6306", - "sha256:10a46017fef60e16694a30627319f38a2b9b52e90182dddb6e37dcdab0f4bf95", - "sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640", - "sha256:23d341cdd4a0371820eb2b0bd6b88f5003a7438bbedb33688cd33b8eae59affd", - "sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162", - "sha256:2a5b73210bad5279ddb558d9a2bfedc7f4bf6ad7f3c988641d83c40293deaec1", - "sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508", - "sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249", - "sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694", - "sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a", - "sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287", - "sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1", - "sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000", - "sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1", - "sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e", - "sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5", - "sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062", - "sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba", - "sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc", - "sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc", - "sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99", - "sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653", - "sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c", - "sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558", - "sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f", - "sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9", - "sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd", - "sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d", - "sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", - "sha256:f05a636b4564104120111800021a92e43397bc12a5c72fed7036be8556e0029e", - "sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80" - ], - "version": "==4.5.1" - }, - "coveragespace": { - "hashes": [ - "sha256:498b54ec158a19e1f5647da681dc77fd9d17df11ecff1253d60ac7970209f6e5", - "sha256:7c5ce4641e0f995b9be0e8b53401fd7b6d17db1b8c23bfd06f0c845ad0de5b5f" - ], - "index": "pypi", - "version": "==2.1" - }, - "docopt": { - "hashes": [ - "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" - ], - "version": "==0.6.2" - }, - "docutils": { - "hashes": [ - "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", - "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", - "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" - ], - "index": "pypi", - "version": "==0.14" - }, - "freezegun": { - "hashes": [ - "sha256:6cb82b276f83f2acce67f121dc2656f4df26c71e32238334eb071170b892a278", - "sha256:e839b43bfbe8158b4d62bb97e6313d39f3586daf48e1314fb1083d2ef17700da" - ], - "index": "pypi", - "version": "==0.3.11" - }, - "future": { - "hashes": [ - "sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8" - ], - "version": "==0.17.1" - }, - "idna": { - "hashes": [ - "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", - "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" - ], - "version": "==2.7" - }, - "isort": { - "hashes": [ - "sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af", - "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", - "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" - ], - "version": "==4.3.4" - }, - "jinja2": { - "hashes": [ - "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", - "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" - ], - "version": "==2.10" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33", - "sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39", - "sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019", - "sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088", - "sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b", - "sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e", - "sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6", - "sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b", - "sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5", - "sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff", - "sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd", - "sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7", - "sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff", - "sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d", - "sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2", - "sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35", - "sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4", - "sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514", - "sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252", - "sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109", - "sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f", - "sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c", - "sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92", - "sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577", - "sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d", - "sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d", - "sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f", - "sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a", - "sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b" - ], - "version": "==1.3.1" - }, - "livereload": { - "hashes": [ - "sha256:583179dc8d49b040a9da79bd33de59e160d2a8802b939e304eb359a4419f6498", - "sha256:dd4469a8f5a6833576e9f5433f1439c306de15dbbfeceabd32479b1123380fa5" - ], - "version": "==2.5.2" - }, - "macfsevents": { - "hashes": [ - "sha256:1324b66b356051de662ba87d84f73ada062acd42b047ed1246e60a449f833e10" - ], - "index": "pypi", - "markers": "sys_platform == 'darwin'", - "version": "==0.8.1" - }, - "macholib": { - "hashes": [ - "sha256:ac02d29898cf66f27510d8f39e9112ae00590adb4a48ec57b25028d6962b1ae1", - "sha256:c4180ffc6f909bf8db6cd81cff4b6f601d575568f4d5dee148c830e9851eb9db" - ], - "version": "==1.11" - }, - "markdown": { - "hashes": [ - "sha256:c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa", - "sha256:d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c" - ], - "version": "==3.0.1" - }, - "markupsafe": { - "hashes": [ - "sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", - "sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", - "sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", - "sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", - "sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", - "sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", - "sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", - "sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", - "sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", - "sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", - "sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", - "sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", - "sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", - "sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", - "sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", - "sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", - "sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", - "sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", - "sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", - "sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", - "sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", - "sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", - "sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", - "sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", - "sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", - "sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", - "sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", - "sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1" - ], - "version": "==1.1.0" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "mkdocs": { - "hashes": [ - "sha256:1b4d46cd1cb517cd743358da96a3efc588fd86f81512fb9c28214597b6dc731f", - "sha256:cd7264ea42d76f5bc1a0bd8b0a2c6c6e6be3a8742f5e78f47104a452dbe93600" - ], - "index": "pypi", - "version": "==0.17.5" - }, - "more-itertools": { - "hashes": [ - "sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092", - "sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e", - "sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d" - ], - "version": "==4.3.0" - }, - "nose": { - "hashes": [ - "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", - "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", - "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98" - ], - "version": "==1.3.7" - }, - "pathlib2": { - "hashes": [ - "sha256:8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83", - "sha256:d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a" - ], - "index": "pypi", - "version": "==2.3.2" - }, - "pefile": { - "hashes": [ - "sha256:4c5b7e2de0c8cb6c504592167acf83115cbbde01fe4a507c16a1422850e86cd6" - ], - "version": "==2018.8.8" - }, - "pkginfo": { - "hashes": [ - "sha256:5878d542a4b3f237e359926384f1dde4e099c9f5525d236b1840cf704fa8d474", - "sha256:a39076cb3eb34c333a0dd390b568e9e1e881c7bf2cc0aee12120636816f55aee" - ], - "version": "==1.4.2" - }, - "pluggy": { - "hashes": [ - "sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095", - "sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f" - ], - "version": "==0.8.0" - }, - "py": { - "hashes": [ - "sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", - "sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6" - ], - "version": "==1.7.0" - }, - "pycodestyle": { - "hashes": [ - "sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83", - "sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a" - ], - "index": "pypi", - "version": "==2.4.0" - }, - "pydocstyle": { - "hashes": [ - "sha256:08a870edc94508264ed90510db466c6357c7192e0e866561d740624a8fc7d90c", - "sha256:4d5bcde961107873bae621f3d580c3e35a426d3687ffc6f8fb356f6628da5a97", - "sha256:af9fcccb303899b83bec82dc9a1d56c60fc369973223a5e80c3dfa9bdf984405" - ], - "index": "pypi", - "version": "==2.1.1" - }, - "pygments": { - "hashes": [ - "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d", - "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc" - ], - "index": "pypi", - "version": "==2.2.0" - }, - "pyinstaller": { - "hashes": [ - "sha256:a5a6e04a66abfcf8761e89a2ebad937919c6be33a7b8963e1a961b55cb35986b" - ], - "index": "pypi", - "version": "==3.4" - }, - "pylint": { - "hashes": [ - "sha256:1d6d3622c94b4887115fe5204982eee66fdd8a951cf98635ee5caee6ec98c3ec", - "sha256:31142f764d2a7cd41df5196f9933b12b7ee55e73ef12204b648ad7e556c119fb" - ], - "index": "pypi", - "version": "==2.1.1" - }, - "pync": { - "hashes": [ - "sha256:38b9e61735a3161f9211a5773c5f5ea698f36af4ff7f77fa03e8d1ff0caa117f" - ], - "index": "pypi", - "markers": "sys_platform == 'darwin'", - "version": "==2.0.3" - }, - "pytest": { - "hashes": [ - "sha256:630ff1dbe04f469ee78faa5660f712e58b953da7df22ea5d828c9012e134da43", - "sha256:a2b5232735dd0b736cbea9c0f09e5070d78fcaba2823a4f6f09d9a81bd19415c" - ], - "index": "pypi", - "version": "==3.10.0" - }, - "pytest-cov": { - "hashes": [ - "sha256:513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7", - "sha256:e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762" - ], - "index": "pypi", - "version": "==2.6.0" - }, - "pytest-describe": { - "hashes": [ - "sha256:bd6be131452b7822c872735ffe53ce3931b3b80cbbad1647c2b482cc9ef3d00e" - ], - "index": "pypi", - "version": "==0.11.1" - }, - "pytest-expecter": { - "hashes": [ - "sha256:1c8e9ab98ddd576436b61a7ba61ea11cfa5a3fc6b00288ce9e91e9dd770daf19", - "sha256:27c93dfe87e2f4d28c525031be68d3f89457e3315241d97ee15f7689544e0e37" - ], - "index": "pypi", - "version": "==1.3" - }, - "pytest-random": { - "hashes": [ - "sha256:92f25db8c5d9ffc20d90b51997b914372d6955cb9cf1f6ead45b90514fc0eddd" - ], - "index": "pypi", - "version": "==0.2" - }, - "python-dateutil": { - "hashes": [ - "sha256:063df5763652e21de43de7d9e00ccf239f953a832941e37be541614732cdfc93", - "sha256:88f9287c0174266bb0d8cedd395cfba9c58e87e5ad86b2ce58859bc11be3cf02" - ], - "version": "==2.7.5" - }, - "python-termstyle": { - "hashes": [ - "sha256:6faf42ba42f2826c38cf70dacb3ac51f248a418e48afc0e36593df11cf3ab1d2", - "sha256:f42a6bb16fbfc5e2c66d553e7ad46524ea833872f75ee5d827c15115fafc94e2" - ], - "version": "==0.1.10" - }, - "pyyaml": { - "hashes": [ - "sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b", - "sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf", - "sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a", - "sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3", - "sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1", - "sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1", - "sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613", - "sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04", - "sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f", - "sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537", - "sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531" - ], - "version": "==3.13" - }, - "readme-renderer": { - "hashes": [ - "sha256:bb16f55b259f27f75f640acf5e00cf897845a8b3e4731b5c1a436e4b8529202f", - "sha256:c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d" - ], - "version": "==24.0" - }, - "requests": { - "hashes": [ - "sha256:65b3a120e4329e33c9889db89c80976c5272f56ea92d3e74da8a463992e3ff54", - "sha256:ea881206e59f41dbd0bd445437d792e43906703fff75ca8ff43ccdb11f33f263" - ], - "version": "==2.20.1" - }, - "requests-toolbelt": { - "hashes": [ - "sha256:42c9c170abc2cacb78b8ab23ac957945c7716249206f90874651971a4acff237", - "sha256:f6a531936c6fa4c6cfce1b9c10d5c4f498d16528d2a54a22ca00011205a187b5" - ], - "version": "==0.8.0" - }, - "six": { - "hashes": [ - "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", - "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" - ], - "version": "==1.11.0" - }, - "sniffer": { - "hashes": [ - "sha256:e8a0daa4c51dff3d00482b45dc9b978159100a8d5a7df327c28ed96586559970", - "sha256:e90c1ad4bd3c31a5fad8e03d45dfc83377b31420aa0779f17280c817ce0c9dd8" - ], - "index": "pypi", - "version": "==0.4.0" - }, - "snowballstemmer": { - "hashes": [ - "sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", - "sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89" - ], - "version": "==1.2.1" - }, - "tornado": { - "hashes": [ - "sha256:5ef073ac6180038ccf99411fe05ae9aafb675952a2c8db60592d5daf8401f803", - "sha256:6d14e47eab0e15799cf3cdcc86b0b98279da68522caace2bd7ce644287685f0a", - "sha256:92b7ca81e18ba9ec3031a7ee73d4577ac21d41a0c9b775a9182f43301c3b5f8e", - "sha256:ab587996fe6fb9ce65abfda440f9b61e4f9f2cf921967723540679176915e4c3", - "sha256:b36298e9f63f18cad97378db2222c0e0ca6a55f6304e605515e05a25483ed51a" - ], - "version": "==4.5.3" - }, - "tqdm": { - "hashes": [ - "sha256:3c4d4a5a41ef162dd61f1edb86b0e1c7859054ab656b2e7c7b77e7fbf6d9f392", - "sha256:5b4d5549984503050883bc126280b386f5f4ca87e6c023c5d015655ad75bdebb" - ], - "version": "==4.28.1" - }, - "twine": { - "hashes": [ - "sha256:7d89bc6acafb31d124e6e5b295ef26ac77030bf098960c2a4c4e058335827c5c", - "sha256:fad6f1251195f7ddd1460cb76d6ea106c93adb4e56c41e0da79658e56e547d2c" - ], - "index": "pypi", - "version": "==1.12.1" - }, - "typed-ast": { - "hashes": [ - "sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58", - "sha256:10703d3cec8dcd9eef5a630a04056bbc898abc19bac5691612acba7d1325b66d", - "sha256:1f6c4bd0bdc0f14246fd41262df7dfc018d65bb05f6e16390b7ea26ca454a291", - "sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a", - "sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9", - "sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892", - "sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9", - "sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded", - "sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa", - "sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe", - "sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd", - "sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85", - "sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6", - "sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46", - "sha256:898f818399cafcdb93cbbe15fc83a33d05f18e29fb498ddc09b0214cdfc7cd51", - "sha256:94b091dc0f19291adcb279a108f5d38de2430411068b219f41b343c03b28fb1f", - "sha256:a26863198902cda15ab4503991e8cf1ca874219e0118cbf07c126bce7c4db129", - "sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c", - "sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea", - "sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863", - "sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559", - "sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87", - "sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6" - ], - "markers": "python_version < '3.7' and implementation_name == 'cpython'", - "version": "==1.1.0" - }, - "urllib3": { - "hashes": [ - "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", - "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" - ], - "version": "==1.24.1" - }, - "webencodings": { - "hashes": [ - "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", - "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" - ], - "version": "==0.5.1" - }, - "wheel": { - "hashes": [ - "sha256:196c9842d79262bb66fcf59faa4bd0deb27da911dbc7c6cdca931080eb1f0783", - "sha256:c93e2d711f5f9841e17f53b0e6c0ff85593f3b416b6eec7a9452041a59a42688" - ], - "index": "pypi", - "version": "==0.32.2" - }, - "wrapt": { - "hashes": [ - "sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6" - ], - "version": "==1.10.11" - } - } -} diff --git a/bin/verchew b/bin/verchew index ee946972..8ff41f5d 100755 --- a/bin/verchew +++ b/bin/verchew @@ -32,6 +32,7 @@ from __future__ import unicode_literals import argparse import logging import os +import re import sys from collections import OrderedDict from subprocess import PIPE, STDOUT, Popen @@ -42,7 +43,7 @@ try: except ImportError: import ConfigParser as configparser # Python 2 -__version__ = '1.3' +__version__ = '1.5' PY2 = sys.version_info[0] == 2 CONFIG_FILENAMES = [ @@ -65,7 +66,7 @@ version = Python 2.7 [virtualenv] cli = virtualenv -version = 15. +version = 15 message = Only required with Python 2. [Make] @@ -218,8 +219,12 @@ def check_dependencies(config): def get_version(program, argument=None): - argument = argument or '--version' - args = [program, argument] + if argument is None: + args = [program, '--version'] + elif argument: + args = [program, argument] + else: + args = [program] show("$ {0}".format(" ".join(args))) output = call(args) @@ -229,7 +234,14 @@ def get_version(program, argument=None): def match_version(pattern, output): - return output.startswith(pattern) or " " + pattern in output + regex = pattern.replace('.', r'\.') + r'\b' + + log.debug("Matching %s: %s", regex, output) + match = re.match(regex, output) + if match is None: + match = re.match(r'.*[^\d.]' + regex, output) + + return bool(match) def call(args): diff --git a/gitman/__init__.py b/gitman/__init__.py index 769c4a5c..2d266a41 100644 --- a/gitman/__init__.py +++ b/gitman/__init__.py @@ -1,29 +1,15 @@ """Package for GitMan.""" -import sys +from pkg_resources import get_distribution +from .commands import ( # pylint: disable=redefined-builtin + delete as uninstall, + display as list, + init, + install, + lock, + update, +) -__project__ = 'GitMan' -__version__ = '1.6a3' -CLI = 'gitman' -PLUGIN = 'deps' -NAME = 'Git Dependency Manager' -VERSION = __project__ + ' v' + __version__ -DESCRIPTION = 'A language-agnostic dependency manager using Git.' - -PYTHON_VERSION = 3, 5 - -if sys.version_info < PYTHON_VERSION: # pragma: no cover (manual test) - sys.exit("Python {}.{}+ is required.".format(*PYTHON_VERSION)) - -try: - # pylint: disable=wrong-import-position - from .commands import init - from .commands import install - from .commands import update - from .commands import display as list # pylint: disable=redefined-builtin - from .commands import lock - from .commands import delete as uninstall -except ImportError: # pragma: no cover (manual test) - pass +__version__ = get_distribution('gitman').version diff --git a/gitman/__main__.py b/gitman/__main__.py index cb2b5e43..f5b17de5 100644 --- a/gitman/__main__.py +++ b/gitman/__main__.py @@ -1,17 +1,20 @@ """Package entry point.""" +import importlib +import os +import sys + +from gitman.cli import main + + # Declare itself as package if needed for better debugging support # pylint: disable=multiple-imports,wrong-import-position,redefined-builtin,used-before-assignment if __name__ == '__main__' and __package__ is None: # pragma: no cover - import os, sys, importlib parent_dir = os.path.abspath(os.path.dirname(__file__)) sys.path.append(os.path.dirname(parent_dir)) __package__ = os.path.basename(parent_dir) importlib.import_module(__package__) -from gitman.cli import main - - if __name__ == '__main__': # pragma: no cover main() diff --git a/gitman/cli.py b/gitman/cli.py index 03a509d6..bf5f2b5a 100644 --- a/gitman/cli.py +++ b/gitman/cli.py @@ -6,7 +6,7 @@ import logging import sys -from . import CLI, DESCRIPTION, VERSION, commands, common, exceptions +from . import __version__, commands, common, exceptions log = logging.getLogger(__name__) @@ -17,107 +17,198 @@ def main(args=None, function=None): # pylint: disable=too-many-statements # Shared options debug = argparse.ArgumentParser(add_help=False) - debug.add_argument('-V', '--version', action='version', version=VERSION) + debug.add_argument( + '-V', '--version', action='version', version="GitMan v" + __version__ + ) debug_group = debug.add_mutually_exclusive_group() - debug_group.add_argument('-v', '--verbose', action='count', default=0, - help="enable verbose logging") - debug_group.add_argument('-q', '--quiet', action='store_const', const=-1, - dest='verbose', - help="only display errors and prompts") + debug_group.add_argument( + '-v', '--verbose', action='count', default=0, help="enable verbose logging" + ) + debug_group.add_argument( + '-q', + '--quiet', + action='store_const', + const=-1, + dest='verbose', + help="only display errors and prompts", + ) project = argparse.ArgumentParser(add_help=False) - project.add_argument('-r', '--root', metavar='PATH', - help="root directory of the project") + project.add_argument( + '-r', '--root', metavar='PATH', help="root directory of the project" + ) depth = argparse.ArgumentParser(add_help=False) - depth.add_argument('-d', '--depth', type=common.positive_int, - default=5, metavar="NUM", - help="limit the number of dependency levels") + depth.add_argument( + '-d', + '--depth', + type=common.positive_int, + default=5, + metavar="NUM", + help="limit the number of dependency levels", + ) options = argparse.ArgumentParser(add_help=False) - options.add_argument('-c', '--clean', action='store_true', - help="delete ignored files in dependencies") + options.add_argument( + '-c', + '--clean', + action='store_true', + help="delete ignored files in dependencies", + ) options_group = options.add_mutually_exclusive_group() - options_group.add_argument('-f', '--force', action='store_true', - help=("overwrite uncommitted changes " - "in dependencies")) - options_group.add_argument('-s', '--skip-changes', action='store_true', - dest='skip_changes', - help=("skip dependencies with " - "uncommitted changes")) + options_group.add_argument( + '-f', + '--force', + action='store_true', + help=("overwrite uncommitted changes " "in dependencies"), + ) + options_group.add_argument( + '-s', + '--skip-changes', + action='store_true', + dest='skip_changes', + help=("skip dependencies with " "uncommitted changes"), + ) shared = {'formatter_class': common.WideHelpFormatter} # Main parser - parser = argparse.ArgumentParser(prog=CLI, description=DESCRIPTION, - parents=[debug], **shared) + parser = argparse.ArgumentParser( + prog='gitman', + description="A language-agnostic dependency manager using Git.", + parents=[debug], + **shared, + ) subs = parser.add_subparsers(help="", dest='command', metavar="") # Init parser info = "create a new config file for the project" - sub = subs.add_parser('init', description=info.capitalize() + '.', - help=info, parents=[debug], **shared) + sub = subs.add_parser( + 'init', + description=info.capitalize() + '.', + help=info, + parents=[debug], + **shared, + ) # Install parser info = "get the specified versions of all dependencies" - sub = subs.add_parser('install', description=info.capitalize() + '.', - help=info, parents=[debug, project, depth, options], - **shared) - sub.add_argument('name', nargs='*', - help="list of dependencies names to install") - sub.add_argument('-e', '--fetch', action='store_true', - help="always fetch the latest branches") + sub = subs.add_parser( + 'install', + description=info.capitalize() + '.', + help=info, + parents=[debug, project, depth, options], + **shared, + ) + sub.add_argument('name', nargs='*', help="list of dependencies names to install") + sub.add_argument( + '-e', '--fetch', action='store_true', help="always fetch the latest branches" + ) # Update parser info = "update dependencies to the latest versions" - sub = subs.add_parser('update', description=info.capitalize() + '.', - help=info, parents=[debug, project, depth, options], - **shared) - sub.add_argument('name', nargs='*', - help="list of dependencies names to update") - sub.add_argument('-a', '--all', action='store_true', dest='recurse', - help="also update all nested dependencies") - sub.add_argument('-L', '--skip-lock', - action='store_false', dest='lock', default=None, - help="disable recording of updated versions") + sub = subs.add_parser( + 'update', + description=info.capitalize() + '.', + help=info, + parents=[debug, project, depth, options], + **shared, + ) + sub.add_argument('name', nargs='*', help="list of dependencies names to update") + sub.add_argument( + '-a', + '--all', + action='store_true', + dest='recurse', + help="also update all nested dependencies", + ) + sub.add_argument( + '-L', + '--skip-lock', + action='store_false', + dest='lock', + default=None, + help="disable recording of updated versions", + ) # List parser info = "display the current version of each dependency" - sub = subs.add_parser('list', description=info.capitalize() + '.', - help=info, parents=[debug, project, depth], **shared) - sub.add_argument('-D', '--fail-if-dirty', action='store_false', - dest='allow_dirty', - help="fail if a source has uncommitted changes") + sub = subs.add_parser( + 'list', + description=info.capitalize() + '.', + help=info, + parents=[debug, project, depth], + **shared, + ) + sub.add_argument( + '-D', + '--fail-if-dirty', + action='store_false', + dest='allow_dirty', + help="fail if a source has uncommitted changes", + ) # Lock parser info = "lock the current version of each dependency" - sub = subs.add_parser('lock', description=info.capitalize() + '.', - help=info, parents=[debug, project], **shared) - sub.add_argument('name', nargs='*', - help="list of dependency names to lock") + sub = subs.add_parser( + 'lock', + description=info.capitalize() + '.', + help=info, + parents=[debug, project], + **shared, + ) + sub.add_argument('name', nargs='*', help="list of dependency names to lock") # Uninstall parser info = "delete all installed dependencies" - sub = subs.add_parser('uninstall', description=info.capitalize() + '.', - help=info, parents=[debug, project], **shared) - sub.add_argument('-f', '--force', action='store_true', - help="delete uncommitted changes in dependencies") - sub.add_argument('-k', '--keep-location', dest='keep_location', - default=False, action='store_true', - help="keep top level folder location") + sub = subs.add_parser( + 'uninstall', + description=info.capitalize() + '.', + help=info, + parents=[debug, project], + **shared, + ) + sub.add_argument( + '-f', + '--force', + action='store_true', + help="delete uncommitted changes in dependencies", + ) + sub.add_argument( + '-k', + '--keep-location', + dest='keep_location', + default=False, + action='store_true', + help="keep top level folder location", + ) # Show parser info = "display the path of a dependency or internal file" - sub = subs.add_parser('show', description=info.capitalize() + '.', - help=info, parents=[debug, project], **shared) - sub.add_argument('name', nargs='*', - help="display the path of this dependency") - sub.add_argument('-c', '--config', action='store_true', - help="display the path of the config file") - sub.add_argument('-l', '--log', action='store_true', - help="display the path of the log file") + sub = subs.add_parser( + 'show', + description=info.capitalize() + '.', + help=info, + parents=[debug, project], + **shared, + ) + sub.add_argument('name', nargs='*', help="display the path of this dependency") + sub.add_argument( + '-c', + '--config', + action='store_true', + help="display the path of the config file", + ) + sub.add_argument( + '-l', '--log', action='store_true', help="display the path of the log file" + ) # Edit parser info = "open the config file in the default editor" - sub = subs.add_parser('edit', description=info.capitalize() + '.', - help=info, parents=[debug, project], **shared) + sub = subs.add_parser( + 'edit', + description=info.capitalize() + '.', + help=info, + parents=[debug, project], + **shared, + ) # Parse arguments namespace = parser.parse_args(args=args) @@ -144,22 +235,25 @@ def _get_command(function, namespace): # pylint: disable=too-many-statements elif namespace.command in ['install', 'update']: function = getattr(commands, namespace.command) args = namespace.name - kwargs.update(root=namespace.root, - depth=namespace.depth, - force=namespace.force, - clean=namespace.clean, - skip_changes=namespace.skip_changes) + kwargs.update( + root=namespace.root, + depth=namespace.depth, + force=namespace.force, + clean=namespace.clean, + skip_changes=namespace.skip_changes, + ) if namespace.command == 'install': kwargs.update(fetch=namespace.fetch) if namespace.command == 'update': - kwargs.update(recurse=namespace.recurse, - lock=namespace.lock) + kwargs.update(recurse=namespace.recurse, lock=namespace.lock) elif namespace.command == 'list': function = commands.display - kwargs.update(root=namespace.root, - depth=namespace.depth, - allow_dirty=namespace.allow_dirty) + kwargs.update( + root=namespace.root, + depth=namespace.depth, + allow_dirty=namespace.allow_dirty, + ) elif namespace.command == 'lock': function = getattr(commands, namespace.command) @@ -168,9 +262,11 @@ def _get_command(function, namespace): # pylint: disable=too-many-statements elif namespace.command == 'uninstall': function = commands.delete - kwargs.update(root=namespace.root, - force=namespace.force, - keep_location=namespace.keep_location) + kwargs.update( + root=namespace.root, + force=namespace.force, + keep_location=namespace.keep_location, + ) elif namespace.command == 'show': function = commands.show @@ -198,8 +294,10 @@ def _run_command(function, args, kwargs): log.debug("Command canceled") except exceptions.UncommittedChanges as exception: _show_error(exception) - exit_message = ("Run again with '--force' to discard changes " - "or '--skip-changes' to skip this dependency") + exit_message = ( + "Run again with '--force' to discard changes " + "or '--skip-changes' to skip this dependency" + ) except exceptions.ScriptFailure as exception: _show_error(exception) exit_message = "Run again with '--force' to ignore script errors" diff --git a/gitman/commands.py b/gitman/commands.py index f82c7d71..d50cad2f 100644 --- a/gitman/commands.py +++ b/gitman/commands.py @@ -19,6 +19,7 @@ def wrapped(*args, **kwargs): result = func(*args, **kwargs) os.chdir(cwd) return result + return wrapped @@ -34,9 +35,11 @@ def init(): else: config = Config() - source = Source('git', - name="sample_dependency", - repo="https://github.com/githubtraining/hellogitworld") + source = Source( + 'git', + name="sample_dependency", + repo="https://github.com/githubtraining/hellogitworld", + ) config.sources.append(source) source = source.lock(rev="ebbbf773431ba07510251bb03f9525c7bab2b13a") config.sources_locked.append(source) @@ -53,8 +56,15 @@ def init(): @restore_cwd -def install(*names, root=None, depth=None, - force=False, fetch=False, clean=True, skip_changes=False): +def install( + *names, + root=None, + depth=None, + force=False, + fetch=False, + clean=True, + skip_changes=False, +): """Install dependencies for a project. Optional arguments: @@ -69,9 +79,11 @@ def install(*names, root=None, depth=None, - `skip_changes`: indicates dependencies with uncommitted changes should be skipped """ - log.info("%sInstalling dependencies: %s", - 'force-' if force else '', - ', '.join(names) if names else '') + log.info( + "%sInstalling dependencies: %s", + 'force-' if force else '', + ', '.join(names) if names else '', + ) count = None config = load_config(root) @@ -81,8 +93,13 @@ def install(*names, root=None, depth=None, common.show("Installing dependencies...", color='message', log=False) common.newline() count = config.install_dependencies( - *names, update=False, depth=depth, - force=force, fetch=fetch, clean=clean, skip_changes=skip_changes + *names, + update=False, + depth=depth, + force=force, + fetch=fetch, + clean=clean, + skip_changes=skip_changes, ) if count: @@ -92,9 +109,16 @@ def install(*names, root=None, depth=None, @restore_cwd -def update(*names, root=None, depth=None, - recurse=False, force=False, clean=True, lock=None, # pylint: disable=redefined-outer-name - skip_changes=False): +def update( + *names, + root=None, + depth=None, + recurse=False, + force=False, + clean=True, + lock=None, # pylint: disable=redefined-outer-name + skip_changes=False, +): """Update dependencies for a project. Optional arguments: @@ -110,10 +134,12 @@ def update(*names, root=None, depth=None, - `skip_changes`: indicates dependencies with uncommitted changes should be skipped """ - log.info("%s dependencies%s: %s", - 'Force updating' if force else 'Updating', - ', recursively' if recurse else '', - ', '.join(names) if names else '') + log.info( + "%s dependencies%s: %s", + 'Force updating' if force else 'Updating', + ', recursively' if recurse else '', + ', '.join(names) if names else '', + ) count = None config = load_config(root) @@ -123,17 +149,22 @@ def update(*names, root=None, depth=None, common.show("Updating dependencies...", color='message', log=False) common.newline() count = config.install_dependencies( - *names, update=True, depth=depth, - recurse=recurse, force=force, fetch=True, clean=clean, - skip_changes=skip_changes + *names, + update=True, + depth=depth, + recurse=recurse, + force=force, + fetch=True, + clean=clean, + skip_changes=skip_changes, ) if count and lock is not False: - common.show("Recording installed versions...", - color='message', log=False) + common.show("Recording installed versions...", color='message', log=False) common.newline() - config.lock_dependencies(*names, obey_existing=lock is None, - skip_changes=skip_changes) + config.lock_dependencies( + *names, obey_existing=lock is None, skip_changes=skip_changes + ) if count: _run_scripts(*names, depth=depth, force=force, _config=config) @@ -176,13 +207,13 @@ def display(*, root=None, depth=None, allow_dirty=True): if config: common.newline() - common.show("Displaying current dependency versions...", - color='message', log=False) + common.show( + "Displaying current dependency versions...", color='message', log=False + ) common.newline() config.log(datetime.datetime.now().strftime("%F %T")) count = 0 - for identity in config.get_dependencies(depth=depth, - allow_dirty=allow_dirty): + for identity in config.get_dependencies(depth=depth, allow_dirty=allow_dirty): count += 1 config.log("{}: {} @ {}", *identity) config.log() @@ -233,8 +264,7 @@ def delete(*, root=None, force=False, keep_location=False): if config: common.newline() - common.show("Checking for uncommitted changes...", - color='message', log=False) + common.show("Checking for uncommitted changes...", color='message', log=False) common.newline() count = len(list(config.get_dependencies(allow_dirty=force))) common.dedent(level=0) diff --git a/gitman/common.py b/gitman/common.py index b84eb43e..e7554d5a 100644 --- a/gitman/common.py +++ b/gitman/common.py @@ -15,7 +15,8 @@ class WideHelpFormatter(argparse.HelpFormatter): """Command-line help text formatter with wider help text.""" def __init__(self, *args, **kwargs): - super().__init__(*args, max_help_position=40, **kwargs) + kwargs['max_help_position'] = 40 + super().__init__(*args, **kwargs) class WarningFormatter(logging.Formatter): @@ -81,8 +82,9 @@ def configure_logging(count=0): # Set a custom formatter logging.basicConfig(level=level) logging.captureWarnings(True) - formatter = WarningFormatter(default_format, verbose_format, - datefmt=settings.LOGGING_DATEFMT) + formatter = WarningFormatter( + default_format, verbose_format, datefmt=settings.LOGGING_DATEFMT + ) logging.root.handlers[0].setFormatter(formatter) logging.getLogger('yorm').setLevel(max(level, settings.YORM_LOGGING_LEVEL)) @@ -165,14 +167,13 @@ def style(msg, name=None, *, _color_support=False): return msg if name == 'shell': - return msg.replace("$ ", COLORS.get(name) + "$ " + RESET) + return msg.replace("$ ", COLORS[name] + "$ " + RESET) color = COLORS.get(name) if color: return color + msg + RESET if msg: - assert color is not None, \ - "Unknown style name requested: {!r}".format(name) + assert color is not None, "Unknown style name requested: {!r}".format(name) return msg diff --git a/gitman/git.py b/gitman/git.py index 76792dad..01f7395f 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -22,8 +22,7 @@ def gitsvn(*args, **kwargs): return call('git', 'svn', *args, **kwargs) -def clone(type, repo, path, *, - cache=settings.CACHE, sparse_paths=None, rev=None): +def clone(type, repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None): """Clone a new Git repository.""" log.debug("Creating a new repository...") @@ -52,11 +51,13 @@ def clone(type, repo, path, *, git('-C', normpath, 'config', 'core.sparseCheckout', 'true') git('-C', normpath, 'remote', 'add', '-f', 'origin', sparse_paths_repo) - with open("%s/%s/.git/info/sparse-checkout" % - (os.getcwd(), normpath), 'w') as fd: + with open( + "%s/%s/.git/info/sparse-checkout" % (os.getcwd(), normpath), 'w' + ) as fd: fd.writelines(sparse_paths) - with open("%s/%s/.git/objects/info/alternates" % - (os.getcwd(), normpath), 'w') as fd: + with open( + "%s/%s/.git/objects/info/alternates" % (os.getcwd(), normpath), 'w' + ) as fd: fd.write("%s/objects" % sparse_paths_repo) # We use directly the revision requested here in order to respect, @@ -145,7 +146,9 @@ def changes(type, include_untracked=False, display_status=True, _show=False): return status -def update(type, repo, path, *, clean=True, fetch=False, rev=None): # pylint: disable=redefined-outer-name,unused-argument +def update( + type, repo, path, *, clean=True, fetch=False, rev=None +): # pylint: disable=redefined-outer-name,unused-argument if type == 'git-svn': # make deep clone here for simplification of sources.py @@ -202,8 +205,7 @@ def get_hash(type, _show=False): def get_tag(): """Get the current working tree's tag (if on a tag).""" - return git('describe', '--tags', '--exact-match', - _show=False, _ignore=True)[0] + return git('describe', '--tags', '--exact-match', _show=False, _ignore=True)[0] def is_fetch_required(type, rev): @@ -212,9 +214,7 @@ def is_fetch_required(type, rev): assert type == 'git' - return rev not in (get_branch(), - get_hash(type), - get_tag()) + return rev not in (get_branch(), get_hash(type), get_tag()) def get_branch(): @@ -229,6 +229,7 @@ def _get_sha_from_rev(rev): branch = parts[0] date = parts[1].strip("{}") git('checkout', '--force', branch, _show=False) - rev = git('rev-list', '-n', '1', '--before={!r}'.format(date), - branch, _show=False)[0] + rev = git( + 'rev-list', '-n', '1', '--before={!r}'.format(date), branch, _show=False + )[0] return rev diff --git a/gitman/models/config.py b/gitman/models/config.py index 4c2d1879..c5d4a380 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -20,8 +20,7 @@ class Config(yorm.ModelMixin): LOG = "gitman.log" - def __init__(self, root=None, - filename="gitman.yml", location="gitman_sources"): + def __init__(self, root=None, filename="gitman.yml", location="gitman_sources"): super().__init__() self.root = root or os.getcwd() self.filename = filename @@ -39,6 +38,7 @@ def _on_post_load(self): def config_path(self): """Get the full path to the config file.""" return os.path.normpath(os.path.join(self.root, self.filename)) + path = config_path @property @@ -62,10 +62,17 @@ def get_path(self, name=None): return os.path.normpath(os.path.join(base, name)) return base - def install_dependencies(self, *names, depth=None, - update=True, recurse=False, - force=False, fetch=False, clean=True, - skip_changes=False): + def install_dependencies( + self, + *names, + depth=None, + update=True, + recurse=False, + force=False, + fetch=False, + clean=True, + skip_changes=False, + ): """Download or update the specified dependencies.""" if depth == 0: log.info("Skipped directory: %s", self.location_path) @@ -88,8 +95,9 @@ def install_dependencies(self, *names, depth=None, log.info("Skipped dependency: %s", source.name) continue - source.update_files(force=force, fetch=fetch, clean=clean, - skip_changes=skip_changes) + source.update_files( + force=force, fetch=fetch, clean=clean, skip_changes=skip_changes + ) source.create_link(self.root, force=force) common.newline() count += 1 @@ -104,7 +112,7 @@ def install_dependencies(self, *names, depth=None, force=force, fetch=fetch, clean=clean, - skip_changes=skip_changes + skip_changes=skip_changes, ) common.dedent() @@ -140,8 +148,7 @@ def run_scripts(self, *names, depth=None, force=False): if config: common.indent() count += config.run_scripts( - depth=None if depth is None else max(0, depth - 1), - force=force, + depth=None if depth is None else max(0, depth - 1), force=force ) common.dedent() @@ -151,8 +158,7 @@ def run_scripts(self, *names, depth=None, force=False): return count - def lock_dependencies(self, *names, obey_existing=True, - skip_changes=False): + def lock_dependencies(self, *names, obey_existing=True, skip_changes=False): """Lock down the immediate dependency versions.""" sources = self._get_sources(use_locked=obey_existing).copy() sources_filter = list(names) if names else [s.name for s in sources] @@ -278,8 +284,7 @@ def _get_sources(self, *, use_locked=None): extras = [] for source in self.sources + self.sources_locked: if source not in sources: - log.info("Source %r missing from selected section", - source.name) + log.info("Source %r missing from selected section", source.name) extras.append(source) return sources + extras diff --git a/gitman/models/source.py b/gitman/models/source.py index 03a22e3c..b3770cd3 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -24,8 +24,16 @@ class Source(AttributeDictionary): DIRTY = '' UNKNOWN = '' - def __init__(self, type, repo, name=None, rev='master', - link=None, scripts=None, sparse_paths=None): + def __init__( + self, + type, + repo, + name=None, + rev='master', + link=None, + scripts=None, + sparse_paths=None, + ): super().__init__() self.type = type or 'git' @@ -51,8 +59,9 @@ def __str__(self): pattern = "['{t}'] '{r}' @ '{v}' in '{d}'" if self.link: pattern += " <- '{s}'" - return pattern.format(t=self.type, r=self.repo, - v=self.rev, d=self.name, s=self.link) + return pattern.format( + t=self.type, r=self.repo, v=self.rev, d=self.name, s=self.link + ) def __eq__(self, other): return self.name == other.name @@ -63,15 +72,19 @@ def __ne__(self, other): def __lt__(self, other): return self.name < other.name - def update_files(self, force=False, fetch=False, clean=True, - skip_changes=False): + def update_files(self, force=False, fetch=False, clean=True, skip_changes=False): """Ensure the source matches the specified revision.""" log.info("Updating source files...") # Clone the repository if needed if not os.path.exists(self.name): - git.clone(self.type, self.repo, self.name, - sparse_paths=self.sparse_paths, rev=self.rev) + git.clone( + self.type, + self.repo, + self.name, + sparse_paths=self.sparse_paths, + rev=self.rev, + ) # Enter the working tree shell.cd(self.name) @@ -82,10 +95,12 @@ def update_files(self, force=False, fetch=False, clean=True, if not force: log.debug("Confirming there are no uncommitted changes...") if skip_changes: - if git.changes(self.type, include_untracked=clean, - display_status=False): - msg = ("Skipped update due to uncommitted changes " - "in {}").format(os.getcwd()) + if git.changes( + self.type, include_untracked=clean, display_status=False + ): + msg = ("Skipped update due to uncommitted changes " "in {}").format( + os.getcwd() + ) common.show(msg, color='git_changes') return else: @@ -98,8 +113,9 @@ def update_files(self, force=False, fetch=False, clean=True, git.fetch(self.type, self.repo, self.name, rev=self.rev) # Update the working tree to the desired revision - git.update(self.type, self.repo, self.name, - fetch=fetch, clean=clean, rev=self.rev) + git.update( + self.type, self.repo, self.name, fetch=fetch, clean=clean, rev=self.rev + ) def create_link(self, root, force=False): """Create a link from the target name to the current directory.""" @@ -156,8 +172,7 @@ def run_scripts(self, force=False): common.show(*lines, color='shell_output') common.newline() - def identify(self, allow_dirty=True, allow_missing=True, - skip_changes=False): + def identify(self, allow_dirty=True, allow_missing=True, skip_changes=False): """Get the path and current repository URL and hash.""" if os.path.isdir(self.name): @@ -167,9 +182,11 @@ def identify(self, allow_dirty=True, allow_missing=True, path = os.getcwd() url = git.get_url(self.type) - if git.changes(self.type, - display_status=not allow_dirty and not skip_changes, - _show=not skip_changes): + if git.changes( + self.type, + display_status=not allow_dirty and not skip_changes, + _show=not skip_changes, + ): if allow_dirty: common.show(self.DIRTY, color='git_dirty', log=False) @@ -177,8 +194,9 @@ def identify(self, allow_dirty=True, allow_missing=True, return path, url, self.DIRTY if skip_changes: - msg = ("Skipped lock due to uncommitted changes " - "in {}").format(os.getcwd()) + msg = ("Skipped lock due to uncommitted changes " "in {}").format( + os.getcwd() + ) common.show(msg, color='git_changes') common.newline() return path, url, self.DIRTY @@ -204,17 +222,22 @@ def lock(self, rev=None, allow_dirty=False, skip_changes=False): """ if rev is None: - _, _, rev = self.identify(allow_dirty=allow_dirty, - allow_missing=False, - skip_changes=skip_changes) + _, _, rev = self.identify( + allow_dirty=allow_dirty, allow_missing=False, skip_changes=skip_changes + ) if rev == self.DIRTY: return None - source = self.__class__(self.type, self.repo, - self.name, rev, - self.link, self.scripts, - self.sparse_paths) + source = self.__class__( + self.type, + self.repo, + self.name, + rev, + self.link, + self.scripts, + self.sparse_paths, + ) return source @property diff --git a/gitman/plugin.py b/gitman/plugin.py index 41d3a97e..05883620 100644 --- a/gitman/plugin.py +++ b/gitman/plugin.py @@ -5,12 +5,12 @@ import argparse import logging -from . import NAME, PLUGIN, __version__, common +from . import __version__, common from .cli import _get_command, _run_command -PROG = 'git ' + PLUGIN -DESCRIPTION = "Use {} (v{}) to install repostories.".format(NAME, __version__) +PROG = 'git deps' +DESCRIPTION = "Use GitMan (v{}) to install repositories.".format(__version__) log = logging.getLogger(__name__) @@ -21,15 +21,22 @@ def main(args=None): # Main parser parser = argparse.ArgumentParser(prog=PROG, description=DESCRIPTION) parser.add_argument( - '-f', '--force', action='store_true', + '-f', + '--force', + action='store_true', help="overwrite uncommitted changes in dependencies", ) parser.add_argument( - '-s', '--skip-changes', action='store_true', dest='skip_changes', - help="skip dependencies with uncommitted changes" + '-s', + '--skip-changes', + action='store_true', + dest='skip_changes', + help="skip dependencies with uncommitted changes", ) parser.add_argument( - '-c', '--clean', action='store_true', + '-c', + '--clean', + action='store_true', help="delete ignored files when updating dependencies", ) @@ -39,29 +46,53 @@ def main(args=None): # Update option group.add_argument( - '-u', '--update', const='update', - help="update dependencies to the latest versions", **shared + '-u', + '--update', + const='update', + help="update dependencies to the latest versions", + **shared, + ) + parser.add_argument( + '-a', + '--all', + action='store_true', + dest='recurse', + help="include nested dependencies when updating", + ) + parser.add_argument( + '-L', + '--skip-lock', + action='store_false', + dest='lock', + default=True, + help="disable recording of updated versions", ) - parser.add_argument('-a', '--all', action='store_true', dest='recurse', - help="include nested dependencies when updating") - parser.add_argument('-L', '--skip-lock', - action='store_false', dest='lock', default=True, - help="disable recording of updated versions") # Display option group.add_argument( - '-l', '--list', const='list', - help="display the current version of each dependency", **shared + '-l', + '--list', + const='list', + help="display the current version of each dependency", + **shared, ) # Uninstall option group.add_argument( - '-x', '--uninstall', const='uninstall', - help="delete all installed dependencies", **shared + '-x', + '--uninstall', + const='uninstall', + help="delete all installed dependencies", + **shared, + ) + parser.add_argument( + '-k', + '--keep-location', + action='store_true', + dest='keep_location', + default=False, + help='keep top level folder location', ) - parser.add_argument('-k', '--keep-location', action='store_true', - dest='keep_location', default=False, - help='keep top level folder location') # Parse arguments namespace = parser.parse_args(args=args) diff --git a/gitman/settings.py b/gitman/settings.py index 52f58a6f..7b302377 100644 --- a/gitman/settings.py +++ b/gitman/settings.py @@ -12,7 +12,7 @@ DEFAULT_LOGGING_FORMAT = "%(message)s" LEVELED_LOGGING_FORMAT = "%(levelname)s: %(message)s" VERBOSE_LOGGING_FORMAT = "[%(levelname)-8s] %(message)s" -VERBOSE2_LOGGING_FORMAT = "[%(levelname)-8s] (%(name)s @%(lineno)4d) %(message)s" # pylint: disable=C0301 +VERBOSE2_LOGGING_FORMAT = "[%(levelname)-8s] (%(name)s @%(lineno)4d) %(message)s" QUIET_LOGGING_LEVEL = logging.ERROR DEFAULT_LOGGING_LEVEL = logging.WARNING VERBOSE_LOGGING_LEVEL = logging.INFO diff --git a/gitman/shell.py b/gitman/shell.py index 6a1cce18..12c2ade5 100644 --- a/gitman/shell.py +++ b/gitman/shell.py @@ -28,9 +28,11 @@ def call(name, *args, _show=True, _shell=False, _ignore=False): program = show(name, *args, stdout=_show) command = subprocess.run( - name if _shell else [name, *args], universal_newlines=True, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - shell=_shell + name if _shell else [name, *args], + universal_newlines=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + shell=_shell, ) output = [line.strip() for line in command.stdout.splitlines()] @@ -47,9 +49,12 @@ def call(name, *args, _show=True, _shell=False, _ignore=False): message = ( "An external program call failed." + "\n\n" "In working directory: " + os.getcwd() + "\n\n" - "The following command produced a non-zero return code:" + "\n\n" + - CMD_PREFIX + program + "\n" + - command.stdout.strip() + "The following command produced a non-zero return code:" + + "\n\n" + + CMD_PREFIX + + program + + "\n" + + command.stdout.strip() ) raise ShellError(message, program=program, output=output) diff --git a/gitman/system.py b/gitman/system.py index a22599bb..8eadc419 100644 --- a/gitman/system.py +++ b/gitman/system.py @@ -26,7 +26,8 @@ def launch(path): def _launch_windows(path): # pragma: no cover (manual test) - os.startfile(path) # pylint: disable=no-member + # pylint: disable=no-member + os.startfile(path) # type: ignore return True diff --git a/gitman/tests/conftest.py b/gitman/tests/conftest.py index 9d32d556..eae41e30 100644 --- a/gitman/tests/conftest.py +++ b/gitman/tests/conftest.py @@ -24,8 +24,7 @@ def pytest_configure(config): terminal = config.pluginmanager.getplugin('terminal') - class QuietReporter(terminal.TerminalReporter): - + class QuietReporter(terminal.TerminalReporter): # type: ignore def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.verbosity = 0 diff --git a/gitman/tests/test_cli.py b/gitman/tests/test_cli.py index d202beaa..2edb3130 100644 --- a/gitman/tests/test_cli.py +++ b/gitman/tests/test_cli.py @@ -70,8 +70,13 @@ def test_install(self, mock_install): cli.main(['install']) mock_install.assert_called_once_with( - root=None, depth=5, force=False, fetch=False, clean=False, - skip_changes=False) + root=None, + depth=5, + force=False, + fetch=False, + clean=False, + skip_changes=False, + ) @patch('gitman.commands.install') def test_install_root(self, mock_install): @@ -79,9 +84,13 @@ def test_install_root(self, mock_install): cli.main(['install', '--root', 'mock/path/to/root']) mock_install.assert_called_once_with( - root='mock/path/to/root', depth=5, - force=False, fetch=False, clean=False, - skip_changes=False) + root='mock/path/to/root', + depth=5, + force=False, + fetch=False, + clean=False, + skip_changes=False, + ) @patch('gitman.commands.install') def test_install_force(self, mock_install): @@ -89,8 +98,8 @@ def test_install_force(self, mock_install): cli.main(['install', '--force']) mock_install.assert_called_once_with( - root=None, depth=5, force=True, fetch=False, clean=False, - skip_changes=False) + root=None, depth=5, force=True, fetch=False, clean=False, skip_changes=False + ) @patch('gitman.commands.install') def test_install_fetch(self, mock_install): @@ -98,8 +107,8 @@ def test_install_fetch(self, mock_install): cli.main(['install', '--fetch']) mock_install.assert_called_once_with( - root=None, depth=5, force=False, fetch=True, clean=False, - skip_changes=False) + root=None, depth=5, force=False, fetch=True, clean=False, skip_changes=False + ) @patch('gitman.commands.install') def test_install_clean(self, mock_install): @@ -107,8 +116,8 @@ def test_install_clean(self, mock_install): cli.main(['install', '--clean']) mock_install.assert_called_once_with( - root=None, depth=5, force=False, fetch=False, clean=True, - skip_changes=False) + root=None, depth=5, force=False, fetch=False, clean=True, skip_changes=False + ) @patch('gitman.commands.install') def test_install_specific_sources(self, mock_install): @@ -116,9 +125,15 @@ def test_install_specific_sources(self, mock_install): cli.main(['install', 'foo', 'bar']) mock_install.assert_called_once_with( - 'foo', 'bar', root=None, depth=5, - force=False, fetch=False, clean=False, - skip_changes=False) + 'foo', + 'bar', + root=None, + depth=5, + force=False, + fetch=False, + clean=False, + skip_changes=False, + ) @patch('gitman.commands.install') def test_install_with_depth(self, mock_update): @@ -126,8 +141,13 @@ def test_install_with_depth(self, mock_update): cli.main(['install', '--depth', '10']) mock_update.assert_called_once_with( - root=None, depth=10, force=False, fetch=False, clean=False, - skip_changes=False) + root=None, + depth=10, + force=False, + fetch=False, + clean=False, + skip_changes=False, + ) @patch('gitman.commands.install', Mock()) def test_install_with_depth_invalid(self): @@ -147,9 +167,14 @@ def test_update(self, mock_update): cli.main(['update']) mock_update.assert_called_once_with( - root=None, depth=5, - force=False, clean=False, recurse=False, lock=None, - skip_changes=False) + root=None, + depth=5, + force=False, + clean=False, + recurse=False, + lock=None, + skip_changes=False, + ) @patch('gitman.commands.update') def test_update_recursive(self, mock_update): @@ -157,9 +182,14 @@ def test_update_recursive(self, mock_update): cli.main(['update', '--all']) mock_update.assert_called_once_with( - root=None, depth=5, - force=False, clean=False, recurse=True, lock=None, - skip_changes=False) + root=None, + depth=5, + force=False, + clean=False, + recurse=True, + lock=None, + skip_changes=False, + ) @patch('gitman.commands.update') def test_update_no_lock(self, mock_update): @@ -167,9 +197,14 @@ def test_update_no_lock(self, mock_update): cli.main(['update', '--skip-lock']) mock_update.assert_called_once_with( - root=None, depth=5, - force=False, clean=False, recurse=False, lock=False, - skip_changes=False) + root=None, + depth=5, + force=False, + clean=False, + recurse=False, + lock=False, + skip_changes=False, + ) @patch('gitman.commands.update') def test_update_skip_changes(self, mock_update): @@ -177,9 +212,14 @@ def test_update_skip_changes(self, mock_update): cli.main(['update', '--skip-changes']) mock_update.assert_called_once_with( - root=None, depth=5, - force=False, clean=False, recurse=False, lock=None, - skip_changes=True) + root=None, + depth=5, + force=False, + clean=False, + recurse=False, + lock=None, + skip_changes=True, + ) @patch('gitman.commands.update') def test_update_specific_sources(self, mock_install): @@ -187,9 +227,16 @@ def test_update_specific_sources(self, mock_install): cli.main(['update', 'foo', 'bar']) mock_install.assert_called_once_with( - 'foo', 'bar', root=None, depth=5, - force=False, clean=False, recurse=False, lock=None, - skip_changes=False) + 'foo', + 'bar', + root=None, + depth=5, + force=False, + clean=False, + recurse=False, + lock=None, + skip_changes=False, + ) @patch('gitman.commands.update') def test_update_with_depth(self, mock_update): @@ -197,9 +244,14 @@ def test_update_with_depth(self, mock_update): cli.main(['update', '--depth', '10']) mock_update.assert_called_once_with( - root=None, depth=10, - force=False, clean=False, recurse=False, lock=None, - skip_changes=False) + root=None, + depth=10, + force=False, + clean=False, + recurse=False, + lock=None, + skip_changes=False, + ) class TestList: @@ -210,8 +262,7 @@ def test_list(self, mock_display): """Verify the 'list' command can be run.""" cli.main(['list']) - mock_display.assert_called_once_with( - root=None, depth=5, allow_dirty=True) + mock_display.assert_called_once_with(root=None, depth=5, allow_dirty=True) @patch('gitman.commands.display') def test_list_root(self, mock_display): @@ -219,27 +270,25 @@ def test_list_root(self, mock_display): cli.main(['list', '--root', 'mock/path/to/root']) mock_display.assert_called_once_with( - root='mock/path/to/root', depth=5, allow_dirty=True) + root='mock/path/to/root', depth=5, allow_dirty=True + ) @patch('gitman.commands.display') def test_list_no_dirty(self, mock_display): """Verify the 'list' command can be set to fail when dirty.""" cli.main(['list', '--fail-if-dirty']) - mock_display.assert_called_once_with( - root=None, depth=5, allow_dirty=False) + mock_display.assert_called_once_with(root=None, depth=5, allow_dirty=False) @patch('gitman.commands.display') def test_update_with_depth(self, mock_update): """Verify the 'list' command can be limited by depth.""" cli.main(['list', '--depth', '10']) - mock_update.assert_called_once_with( - root=None, depth=10, allow_dirty=True) + mock_update.assert_called_once_with(root=None, depth=10, allow_dirty=True) def describe_lock(): - @patch('gitman.commands.lock') def with_no_arguments(lock): cli.main(['lock']) @@ -260,7 +309,8 @@ def test_uninstall(self, mock_uninstall): cli.main(['uninstall']) mock_uninstall.assert_called_once_with( - root=None, force=False, keep_location=False) + root=None, force=False, keep_location=False + ) @patch('gitman.commands.delete') def test_uninstall_root(self, mock_uninstall): @@ -268,7 +318,8 @@ def test_uninstall_root(self, mock_uninstall): cli.main(['uninstall', '--root', 'mock/path/to/root']) mock_uninstall.assert_called_once_with( - root='mock/path/to/root', force=False, keep_location=False) + root='mock/path/to/root', force=False, keep_location=False + ) @patch('gitman.commands.delete') def test_uninstall_force(self, mock_uninstall): @@ -276,7 +327,8 @@ def test_uninstall_force(self, mock_uninstall): cli.main(['uninstall', '--force']) mock_uninstall.assert_called_once_with( - root=None, force=True, keep_location=False) + root=None, force=True, keep_location=False + ) @patch('gitman.commands.delete') def test_uninstall_keep_location(self, mock_uninstall): @@ -284,11 +336,11 @@ def test_uninstall_keep_location(self, mock_uninstall): cli.main(['uninstall', '--keep-location']) mock_uninstall.assert_called_once_with( - root=None, force=False, keep_location=True) + root=None, force=False, keep_location=True + ) def describe_show(): - @patch('gitman.commands.show') def with_no_arguments(show): cli.main(['show']) @@ -316,7 +368,6 @@ def with_log(show): def describe_edit(): - @patch('gitman.commands.edit') def with_no_arguments(edit): cli.main(['edit']) @@ -342,7 +393,6 @@ def describe_logging(): @pytest.mark.parametrize("argument,verbosity", argument_verbosity) def at_each_level(argument, verbosity): - def function(*args, **kwargs): logging.debug(args) logging.debug(kwargs) diff --git a/gitman/tests/test_commands.py b/gitman/tests/test_commands.py index ef9b078a..b98cf809 100644 --- a/gitman/tests/test_commands.py +++ b/gitman/tests/test_commands.py @@ -6,7 +6,6 @@ def describe_install(): - def can_be_run_without_project(tmpdir): tmpdir.chdir() @@ -14,7 +13,6 @@ def can_be_run_without_project(tmpdir): def describe_update(): - def can_be_run_without_project(tmpdir): tmpdir.chdir() @@ -22,7 +20,6 @@ def can_be_run_without_project(tmpdir): def describe_display(): - def can_be_run_without_project(tmpdir): tmpdir.chdir() @@ -30,7 +27,6 @@ def can_be_run_without_project(tmpdir): def describe_lock(): - def can_be_run_without_project(tmpdir): tmpdir.chdir() @@ -38,7 +34,6 @@ def can_be_run_without_project(tmpdir): def describe_delete(): - def can_be_run_without_project(tmpdir): tmpdir.chdir() @@ -46,7 +41,6 @@ def can_be_run_without_project(tmpdir): def describe_show(): - def can_be_run_without_project(tmpdir): tmpdir.chdir() @@ -54,7 +48,6 @@ def can_be_run_without_project(tmpdir): def describe_edit(): - def can_be_run_without_project(tmpdir): tmpdir.chdir() diff --git a/gitman/tests/test_common.py b/gitman/tests/test_common.py index 324c51d2..b0f11bbc 100644 --- a/gitman/tests/test_common.py +++ b/gitman/tests/test_common.py @@ -10,7 +10,6 @@ class TestShowConsole: - def setup_method(self, _): _Config.indent_level = 0 _Config.verbosity = 0 @@ -19,19 +18,13 @@ def setup_method(self, _): def test_show(self): common.show("Hello, world!", file=self.file, color=None) - assert [ - call.write("Hello, world!"), - call.write("\n"), - ] == self.file.mock_calls + assert [call.write("Hello, world!"), call.write("\n")] == self.file.mock_calls def test_show_after_indent(self): common.indent() common.show("|\n", file=self.file, color=None) - assert [ - call.write(" |\n"), - call.write("\n"), - ] == self.file.mock_calls + assert [call.write(" |\n"), call.write("\n")] == self.file.mock_calls def test_show_after_1_indent_2_dedent(self): common.indent() @@ -39,14 +32,10 @@ def test_show_after_1_indent_2_dedent(self): common.dedent() common.show("|\n", file=self.file, color=None) - assert [ - call.write("|\n"), - call.write("\n"), - ] == self.file.mock_calls + assert [call.write("|\n"), call.write("\n")] == self.file.mock_calls class TestShowLog: - def setup_method(self, _): _Config.indent_level = 0 _Config.verbosity = 1 @@ -55,24 +44,18 @@ def setup_method(self, _): def test_show(self): common.show("Hello, world!", log=self.log, color=None) - assert [ - call.info("Hello, world!"), - ] == self.log.mock_calls + assert [call.info("Hello, world!")] == self.log.mock_calls def test_show_errors(self): common.show("Oops", color='error', log=self.log) - expect(self.log.mock_calls) == [ - call.error("Oops"), - ] + expect(self.log.mock_calls) == [call.error("Oops")] def test_show_after_indent(self): common.indent() common.show("|\n", log=self.log, color=None) - assert [ - call.info("|"), - ] == self.log.mock_calls + assert [call.info("|")] == self.log.mock_calls def test_show_after_1_indent_2_dedent(self): common.indent() @@ -80,13 +63,10 @@ def test_show_after_1_indent_2_dedent(self): common.dedent() common.show("|\n", log=self.log, color=None) - assert [ - call.info("|"), - ] == self.log.mock_calls + assert [call.info("|")] == self.log.mock_calls class TestShowQuiet: - def setup_method(self, _): _Config.indent_level = 0 _Config.verbosity = -1 @@ -101,14 +81,12 @@ def test_show(self): def describe_show(): - def it_requries_color_with_messages(): with expect.raises(AssertionError): common.show("Hello, world!", 'foobar') def describe_style(): - def when_no_color_support(): msg = common.style("_foo_") diff --git a/gitman/tests/test_git.py b/gitman/tests/test_git.py index d04b2b97..cf9767a2 100644 --- a/gitman/tests/test_git.py +++ b/gitman/tests/test_git.py @@ -17,14 +17,17 @@ class TestGit: def test_clone(self, mock_call): """Verify the commands to set up a new reference repository.""" git.clone('git', 'mock.git', 'mock/path', cache='cache') - check_calls(mock_call, [ - "git clone --mirror mock.git " + - os.path.normpath("cache/mock.reference"), - "git clone --reference " + - os.path.normpath("cache/mock.reference") + - " mock.git " + - os.path.normpath("mock/path") - ]) + check_calls( + mock_call, + [ + "git clone --mirror mock.git " + + os.path.normpath("cache/mock.reference"), + "git clone --reference " + + os.path.normpath("cache/mock.reference") + + " mock.git " + + os.path.normpath("mock/path"), + ], + ) @patch('os.path.isdir', Mock(return_value=False)) def test_clone_without_cache(self, mock_call): @@ -32,9 +35,9 @@ def test_clone_without_cache(self, mock_call): settings.CACHE_DISABLE = True try: git.clone('git', 'mock.git', 'mock/path', cache='cache') - check_calls(mock_call, [ - "git clone mock.git " + os.path.normpath("mock/path") - ]) + check_calls( + mock_call, ["git clone mock.git " + os.path.normpath("mock/path")] + ) finally: settings.CACHE_DISABLE = False @@ -42,63 +45,78 @@ def test_clone_without_cache(self, mock_call): def test_clone_from_reference(self, mock_call): """Verify the commands to clone a Git repository from a reference.""" git.clone('git', 'mock.git', 'mock/path', cache='cache') - check_calls(mock_call, [ - "git clone --reference " + - os.path.normpath("cache/mock.reference") + - " mock.git " + - os.path.normpath("mock/path") - ]) + check_calls( + mock_call, + [ + "git clone --reference " + + os.path.normpath("cache/mock.reference") + + " mock.git " + + os.path.normpath("mock/path") + ], + ) def test_fetch(self, mock_call): """Verify the commands to fetch from a Git repository.""" git.fetch('git', 'mock.git', 'mock/path') - check_calls(mock_call, [ - "git remote set-url origin mock.git", - "git fetch --tags --force --prune origin", - ]) + check_calls( + mock_call, + [ + "git remote set-url origin mock.git", + "git fetch --tags --force --prune origin", + ], + ) def test_fetch_rev(self, mock_call): """Verify the commands to fetch from a Git repository w/ rev.""" git.fetch('git', 'mock.git', 'mock/path', 'mock-rev') - check_calls(mock_call, [ - "git remote set-url origin mock.git", - "git fetch --tags --force --prune origin mock-rev", - ]) + check_calls( + mock_call, + [ + "git remote set-url origin mock.git", + "git fetch --tags --force --prune origin mock-rev", + ], + ) def test_fetch_rev_sha(self, mock_call): """Verify the commands to fetch from a Git repository w/ SHA.""" git.fetch('git', 'mock.git', 'mock/path', 'abcdef1234' * 4) - check_calls(mock_call, [ - "git remote set-url origin mock.git", - "git fetch --tags --force --prune origin", - ]) + check_calls( + mock_call, + [ + "git remote set-url origin mock.git", + "git fetch --tags --force --prune origin", + ], + ) def test_fetch_rev_revparse(self, mock_call): """Verify the commands to fetch from a Git repository w/ rev-parse.""" - git.fetch('git', 'mock.git', 'mock/path', - 'master@{2015-02-12 18:30:00}') - check_calls(mock_call, [ - "git remote set-url origin mock.git", - "git fetch --tags --force --prune origin", - ]) + git.fetch('git', 'mock.git', 'mock/path', 'master@{2015-02-12 18:30:00}') + check_calls( + mock_call, + [ + "git remote set-url origin mock.git", + "git fetch --tags --force --prune origin", + ], + ) def test_valid(self, mock_call): """Verify the commands to check for a working tree.""" git.valid() - check_calls(mock_call, [ - "git rev-parse --is-inside-work-tree", - ]) + check_calls(mock_call, ["git rev-parse --is-inside-work-tree"]) def test_changes(self, mock_call): """Verify the commands to check for uncommitted changes.""" git.changes('git', include_untracked=True) - check_calls(mock_call, [ - # based on: http://stackoverflow.com/questions/3878624 - "git update-index -q --refresh", - "git diff-index --quiet HEAD", - "git ls-files --others --exclude-standard", - "git status", # used for displaying the overall status - ]) + check_calls( + mock_call, + [ + # based on: http://stackoverflow.com/questions/3878624 + "git update-index -q --refresh", + "git diff-index --quiet HEAD", + "git ls-files --others --exclude-standard", + "git status", # used for displaying the overall status + ], + ) def test_changes_false(self, _): """Verify the absence of changes can be detected.""" @@ -123,46 +141,58 @@ def test_changes_true_when_uncommitted(self, _): def test_update(self, mock_call): """Verify the commands to update a working tree to a revision.""" git.update('git', 'mock.git', 'mock/path', rev='mock_rev') - check_calls(mock_call, [ - "git stash", - "git clean --force -d -x", - "git checkout --force mock_rev", - "git branch --set-upstream-to origin/mock_rev", - ]) + check_calls( + mock_call, + [ + "git stash", + "git clean --force -d -x", + "git checkout --force mock_rev", + "git branch --set-upstream-to origin/mock_rev", + ], + ) def test_update_branch(self, mock_call): """Verify the commands to update a working tree to a branch.""" - git.update('git', 'mock.git', 'mock/path', - fetch=True, rev='mock_branch') - check_calls(mock_call, [ - "git stash", - "git clean --force -d -x", - "git checkout --force mock_branch", - "git branch --set-upstream-to origin/mock_branch", - "git pull --ff-only --no-rebase", - ]) + git.update('git', 'mock.git', 'mock/path', fetch=True, rev='mock_branch') + check_calls( + mock_call, + [ + "git stash", + "git clean --force -d -x", + "git checkout --force mock_branch", + "git branch --set-upstream-to origin/mock_branch", + "git pull --ff-only --no-rebase", + ], + ) def test_update_no_clean(self, mock_call): git.update('git', 'mock.git', 'mock/path', clean=False, rev='mock_rev') - check_calls(mock_call, [ - "git stash", - "git checkout --force mock_rev", - "git branch --set-upstream-to origin/mock_rev", - ]) + check_calls( + mock_call, + [ + "git stash", + "git checkout --force mock_rev", + "git branch --set-upstream-to origin/mock_rev", + ], + ) def test_update_revparse(self, mock_call): """Verify the commands to update a working tree to a rev-parse.""" mock_call.return_value = ["abc123"] - git.update('git', 'mock.git', 'mock/path', - rev='mock_branch@{2015-02-12 18:30:00}') - check_calls(mock_call, [ - "git stash", - "git clean --force -d -x", - "git checkout --force mock_branch", - "git rev-list -n 1 --before='2015-02-12 18:30:00' mock_branch", - "git checkout --force abc123", - "git branch --set-upstream-to origin/abc123", - ]) + git.update( + 'git', 'mock.git', 'mock/path', rev='mock_branch@{2015-02-12 18:30:00}' + ) + check_calls( + mock_call, + [ + "git stash", + "git clean --force -d -x", + "git checkout --force mock_branch", + "git rev-list -n 1 --before='2015-02-12 18:30:00' mock_branch", + "git checkout --force abc123", + "git branch --set-upstream-to origin/abc123", + ], + ) def test_get_url(self, mock_call): """Verify the commands to get the current repository's URL.""" diff --git a/gitman/tests/test_models_config.py b/gitman/tests/test_models_config.py index 61ef8671..4abdfef2 100644 --- a/gitman/tests/test_models_config.py +++ b/gitman/tests/test_models_config.py @@ -11,7 +11,6 @@ class TestConfig: - def test_init_defaults(self): """Verify a config has a default filename and location.""" config = Config('mock/root') @@ -105,32 +104,29 @@ def test_install_with_depth_2(self): def describe_config(): - @pytest.fixture def config(): return Config('m/root', 'm.ext', 'm/location') def describe_get_path(): - def it_defaults_to_sources_location(config): - expect(config.get_path()) == \ - os.path.normpath("m/root/m/location") + expect(config.get_path()) == os.path.normpath("m/root/m/location") def it_can_get_the_config_path(config): - expect(config.get_path('__config__')) == \ - os.path.normpath("m/root/m.ext") + expect(config.get_path('__config__')) == os.path.normpath("m/root/m.ext") def it_can_get_log_path(config): - expect(config.get_path('__log__')) == \ - os.path.normpath("m/root/m/location/gitman.log") + expect(config.get_path('__log__')) == os.path.normpath( + "m/root/m/location/gitman.log" + ) def it_can_get_dependency_path(config): - expect(config.get_path('foobar')) == \ - os.path.normpath("m/root/m/location/foobar") + expect(config.get_path('foobar')) == os.path.normpath( + "m/root/m/location/foobar" + ) class TestLoad: - def test_load_from_directory_with_config_file(self): config = load_config(FILES) diff --git a/gitman/tests/test_models_source.py b/gitman/tests/test_models_source.py index 1f5d42dc..1a88c621 100644 --- a/gitman/tests/test_models_source.py +++ b/gitman/tests/test_models_source.py @@ -14,7 +14,6 @@ def source(): class TestSource: - def test_init_defaults(self): """Verify a source has a default revision.""" source = Source('git', 'http://example.com/foo/bar.git') @@ -47,8 +46,7 @@ def test_init_error(self): def test_repr(self, source): """Verify sources can be represented.""" - assert "" == \ - repr(source) + assert "" == repr(source) def test_repr_no_link(self, source): """Verify sources can be represented.""" diff --git a/gitman/tests/test_plugin.py b/gitman/tests/test_plugin.py index 87342dd2..45ca3579 100644 --- a/gitman/tests/test_plugin.py +++ b/gitman/tests/test_plugin.py @@ -17,9 +17,14 @@ def test_install(self, mock_commands): plugin.main([]) assert [ - call.install(root=None, depth=None, - clean=False, fetch=True, force=False, - skip_changes=False), + call.install( + root=None, + depth=None, + clean=False, + fetch=True, + force=False, + skip_changes=False, + ), call.install().__bool__(), # command status check ] == mock_commands.mock_calls @@ -31,9 +36,15 @@ def test_update(self, mock_commands): plugin.main(['--update', '--clean']) assert [ - call.update(root=None, depth=None, - clean=True, force=False, recurse=False, lock=True, - skip_changes=False), + call.update( + root=None, + depth=None, + clean=True, + force=False, + recurse=False, + lock=True, + skip_changes=False, + ), call.update().__bool__(), # command status check ] == mock_commands.mock_calls @@ -45,9 +56,15 @@ def test_update_recursive(self, mock_commands): plugin.main(['--update', '--all']) assert [ - call.update(root=None, depth=None, - clean=False, force=False, recurse=True, lock=True, - skip_changes=False), + call.update( + root=None, + depth=None, + clean=False, + force=False, + recurse=True, + lock=True, + skip_changes=False, + ), call.update().__bool__(), # command status check ] == mock_commands.mock_calls @@ -59,9 +76,15 @@ def test_update_no_lock(self, mock_commands): plugin.main(['--update', '--skip-lock']) assert [ - call.update(root=None, depth=None, - clean=False, force=False, recurse=False, lock=False, - skip_changes=False), + call.update( + root=None, + depth=None, + clean=False, + force=False, + recurse=False, + lock=False, + skip_changes=False, + ), call.update().__bool__(), # command status check ] == mock_commands.mock_calls @@ -73,9 +96,15 @@ def test_update_skip_changes(self, mock_commands): plugin.main(['--update', '--skip-changes']) assert [ - call.update(root=None, depth=None, - clean=False, force=False, recurse=False, lock=True, - skip_changes=True), + call.update( + root=None, + depth=None, + clean=False, + force=False, + recurse=False, + lock=True, + skip_changes=True, + ), call.update().__bool__(), # command status check ] == mock_commands.mock_calls @@ -87,8 +116,7 @@ def test_list(self, mock_commands): plugin.main(['--list']) assert [ - call.display(root=None, depth=None, - allow_dirty=True), + call.display(root=None, depth=None, allow_dirty=True), call.display().__bool__(), # command status check ] == mock_commands.mock_calls diff --git a/gitman/tests/test_shell.py b/gitman/tests/test_shell.py index 4c2acfd8..1214c387 100644 --- a/gitman/tests/test_shell.py +++ b/gitman/tests/test_shell.py @@ -70,10 +70,7 @@ def test_ln_missing_parent(self, mock_call): if os.name == 'nt': check_calls(mock_call, []) else: - check_calls(mock_call, [ - "mkdir -p mock", - "ln -s mock/target mock/source", - ]) + check_calls(mock_call, ["mkdir -p mock", "ln -s mock/target mock/source"]) @patch('os.path.isfile', Mock(return_value=True)) def test_rm_file(self, mock_call): diff --git a/gitman/tests/test_system.py b/gitman/tests/test_system.py index 53f23b9f..44d9e131 100644 --- a/gitman/tests/test_system.py +++ b/gitman/tests/test_system.py @@ -8,7 +8,6 @@ def describe_launch(): - @patch('platform.system', Mock(return_value="Windows")) @patch('gitman.system._launch_windows') def it_opens_files(startfile): diff --git a/mkdocs.yml b/mkdocs.yml index be7d0d4d..568530a6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,7 +5,7 @@ repo_url: https://github.com/jacebrowning/gitman theme: readthedocs -pages: +nav: - Home: index.md - Setup: - Git: setup/git.md diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..f3a258a2 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,673 @@ +[[package]] +category = "dev" +description = "Python graph (network) package" +name = "altgraph" +optional = false +python-versions = "*" +version = "0.16.1" + +[[package]] +category = "dev" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +marker = "python_version >= \"3.6\" and python_version < \"4.0\"" +name = "appdirs" +optional = false +python-versions = "*" +version = "1.4.3" + +[[package]] +category = "dev" +description = "An abstract syntax tree for Python with inference support." +name = "astroid" +optional = false +python-versions = ">=3.4.*" +version = "2.1.0" + +[package.dependencies] +lazy-object-proxy = "*" +six = "*" +wrapt = "*" + +[package.dependencies.typed-ast] +python = "<3.7" +version = "*" + +[[package]] +category = "dev" +description = "Atomic file writes." +name = "atomicwrites" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.2.1" + +[[package]] +category = "dev" +description = "Classes Without Boilerplate" +name = "attrs" +optional = false +python-versions = "*" +version = "18.2.0" + +[[package]] +category = "dev" +description = "A backport of the get_terminal_size function from Python 3.3's shutil." +name = "backports.shutil-get-terminal-size" +optional = false +python-versions = "*" +version = "1.0.0" + +[[package]] +category = "dev" +description = "The uncompromising code formatter." +marker = "python_version >= \"3.6\" and python_version < \"4.0\"" +name = "black" +optional = false +python-versions = ">=3.6" +version = "18.9b0" + +[package.dependencies] +appdirs = "*" +attrs = ">=17.4.0" +click = ">=6.5" +toml = ">=0.9.4" + +[[package]] +category = "dev" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi" +optional = false +python-versions = "*" +version = "2018.11.29" + +[[package]] +category = "dev" +description = "Universal encoding detector for Python 2 and 3" +name = "chardet" +optional = false +python-versions = "*" +version = "3.0.4" + +[[package]] +category = "dev" +description = "Composable command line interface toolkit" +name = "click" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "7.0" + +[[package]] +category = "dev" +description = "Cross-platform colored terminal text." +name = "colorama" +optional = false +python-versions = "*" +version = "0.3.9" + +[[package]] +category = "dev" +description = "Code coverage measurement for Python" +name = "coverage" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4" +version = "4.5.2" + +[[package]] +category = "dev" +description = "A place to track your code coverage metrics." +name = "coveragespace" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "2.1" + +[package.dependencies] +"backports.shutil-get-terminal-size" = ">=1.0,<2.0" +colorama = ">=0.3,<0.4" +coverage = ">=4.0,<5.0" +docopt = ">=0.6,<0.7" +requests = ">=2.0,<3.0" + +[[package]] +category = "dev" +description = "Pythonic argument parser, that will make you smile" +name = "docopt" +optional = false +python-versions = "*" +version = "0.6.2" + +[[package]] +category = "dev" +description = "Let your Python tests travel through time" +name = "freezegun" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.3.11" + +[package.dependencies] +python-dateutil = ">=1.0,<2.0 || >2.0" +six = "*" + +[[package]] +category = "dev" +description = "Clean single-source support for Python 3 and 2" +name = "future" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "0.17.1" + +[[package]] +category = "dev" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.8" + +[[package]] +category = "dev" +description = "A Python utility / library to sort Python imports." +name = "isort" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "4.3.4" + +[[package]] +category = "dev" +description = "A small but fast and easy to use stand-alone template engine written in pure python." +name = "jinja2" +optional = false +python-versions = "*" +version = "2.10" + +[package.dependencies] +MarkupSafe = ">=0.23" + +[[package]] +category = "dev" +description = "A fast and thorough lazy object proxy." +name = "lazy-object-proxy" +optional = false +python-versions = "*" +version = "1.3.1" + +[[package]] +category = "dev" +description = "Python LiveReload is an awesome tool for web developers" +name = "livereload" +optional = false +python-versions = "*" +version = "2.6.0" + +[package.dependencies] +six = "*" +tornado = "*" + +[[package]] +category = "dev" +description = "Thread-based interface to file system observation primitives." +marker = "sys_platform == \"darwin\"" +name = "macfsevents" +optional = false +python-versions = "*" +version = "0.8.1" + +[[package]] +category = "dev" +description = "Mach-O header analysis and editing" +name = "macholib" +optional = false +python-versions = "*" +version = "1.11" + +[package.dependencies] +altgraph = ">=0.15" + +[[package]] +category = "dev" +description = "Python implementation of Markdown." +name = "markdown" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "3.0.1" + +[[package]] +category = "dev" +description = "Safely add untrusted strings to HTML/XML markup." +name = "markupsafe" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.1.0" + +[[package]] +category = "dev" +description = "McCabe checker, plugin for flake8" +name = "mccabe" +optional = false +python-versions = "*" +version = "0.6.1" + +[[package]] +category = "dev" +description = "Project documentation with Markdown." +name = "mkdocs" +optional = false +python-versions = ">=2.7.9,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.0.4" + +[package.dependencies] +Jinja2 = ">=2.7.1" +Markdown = ">=2.3.1" +PyYAML = ">=3.10" +click = ">=3.3" +livereload = ">=2.5.1" +tornado = ">=5.0" + +[[package]] +category = "dev" +description = "More routines for operating on iterables, beyond itertools" +name = "more-itertools" +optional = false +python-versions = "*" +version = "4.3.0" + +[package.dependencies] +six = ">=1.0.0,<2.0.0" + +[[package]] +category = "dev" +description = "Optional static typing for Python" +name = "mypy" +optional = false +python-versions = "*" +version = "0.650" + +[package.dependencies] +mypy-extensions = ">=0.4.0,<0.5.0" +typed-ast = ">=1.1.0,<1.2.0" + +[[package]] +category = "dev" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +name = "mypy-extensions" +optional = false +python-versions = "*" +version = "0.4.1" + +[[package]] +category = "dev" +description = "nose extends unittest to make testing easier" +name = "nose" +optional = false +python-versions = "*" +version = "1.3.7" + +[[package]] +category = "main" +description = "parse() is the opposite of format()" +name = "parse" +optional = false +python-versions = "*" +version = "1.8.4" + +[[package]] +category = "dev" +description = "Object-oriented filesystem paths" +marker = "python_version < \"3.6\"" +name = "pathlib2" +optional = false +python-versions = "*" +version = "2.3.3" + +[package.dependencies] +six = "*" + +[[package]] +category = "dev" +description = "Python PE parsing module" +name = "pefile" +optional = false +python-versions = "*" +version = "2018.8.8" + +[package.dependencies] +future = "*" + +[[package]] +category = "dev" +description = "plugin and hook calling mechanisms for python" +name = "pluggy" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.8.0" + +[[package]] +category = "dev" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +name = "py" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.7.0" + +[[package]] +category = "dev" +description = "Python docstring style checker" +name = "pydocstyle" +optional = false +python-versions = "*" +version = "3.0.0" + +[package.dependencies] +six = "*" +snowballstemmer = "*" + +[[package]] +category = "dev" +description = "Pygments is a syntax highlighting package written in Python." +name = "pygments" +optional = false +python-versions = "*" +version = "2.3.1" + +[[package]] +category = "dev" +description = "PyInstaller bundles a Python application and all its dependencies into a single package." +name = "pyinstaller" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.4" + +[package.dependencies] +altgraph = "*" +macholib = ">=1.8" +pefile = ">=2017.8.1" +setuptools = "*" + +[[package]] +category = "dev" +description = "python code static checker" +name = "pylint" +optional = false +python-versions = ">=3.4.*" +version = "2.2.2" + +[package.dependencies] +astroid = ">=2.0.0" +colorama = "*" +isort = ">=4.2.5" +mccabe = "*" + +[[package]] +category = "dev" +description = "Python Wrapper for Mac OS 10.10 Notification Center" +marker = "sys_platform == \"darwin\"" +name = "pync" +optional = false +python-versions = "*" +version = "2.0.3" + +[package.dependencies] +python-dateutil = ">=2.0" + +[[package]] +category = "dev" +description = "pytest: simple powerful testing with Python" +name = "pytest" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.10.1" + +[package.dependencies] +atomicwrites = ">=1.0" +attrs = ">=17.4.0" +colorama = "*" +more-itertools = ">=4.0.0" +pluggy = ">=0.7" +py = ">=1.5.0" +setuptools = "*" +six = ">=1.10.0" + +[package.dependencies.pathlib2] +python = "<3.6" +version = ">=2.2.0" + +[[package]] +category = "dev" +description = "Pytest plugin for measuring coverage." +name = "pytest-cov" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.6.0" + +[package.dependencies] +coverage = ">=4.4" +pytest = ">=2.9" + +[[package]] +category = "dev" +description = "Describe-style plugin for pytest" +name = "pytest-describe" +optional = false +python-versions = "*" +version = "0.11.1" + +[package.dependencies] +pytest = ">=2.6.0" + +[[package]] +category = "dev" +description = "Better testing with expecter and pytest." +name = "pytest-expecter" +optional = false +python-versions = "*" +version = "1.3" + +[[package]] +category = "dev" +description = "py.test plugin to randomize tests" +name = "pytest-random" +optional = false +python-versions = "*" +version = "0.02" + +[package.dependencies] +pytest = ">=2.2.3" + +[[package]] +category = "dev" +description = "Extensions to the standard Python datetime module" +name = "python-dateutil" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "2.7.5" + +[package.dependencies] +six = ">=1.5" + +[[package]] +category = "dev" +description = "console colouring for python" +name = "python-termstyle" +optional = false +python-versions = "*" +version = "0.1.10" + +[package.dependencies] +setuptools = "*" + +[[package]] +category = "main" +description = "YAML parser and emitter for Python" +name = "pyyaml" +optional = false +python-versions = "*" +version = "3.13" + +[[package]] +category = "dev" +description = "Python HTTP for Humans." +name = "requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.21.0" + +[package.dependencies] +certifi = ">=2017.4.17" +chardet = ">=3.0.2,<3.1.0" +idna = ">=2.5,<2.9" +urllib3 = ">=1.21.1,<1.25" + +[[package]] +category = "main" +description = "Simple, fast, extensible JSON encoder/decoder for Python" +name = "simplejson" +optional = false +python-versions = "*" +version = "3.16.0" + +[[package]] +category = "dev" +description = "Python 2 and 3 compatibility utilities" +name = "six" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" +version = "1.12.0" + +[[package]] +category = "dev" +description = "An automatic test runner. Supports nose out of the box." +name = "sniffer" +optional = false +python-versions = "*" +version = "0.4.0" + +[package.dependencies] +colorama = "*" +nose = "*" +python-termstyle = "*" + +[[package]] +category = "dev" +description = "This package provides 16 stemmer algorithms (15 + Poerter English stemmer) generated from Snowball algorithms." +name = "snowballstemmer" +optional = false +python-versions = "*" +version = "1.2.1" + +[[package]] +category = "dev" +description = "Python Library for Tom's Obvious, Minimal Language" +marker = "python_version >= \"3.6\" and python_version < \"4.0\"" +name = "toml" +optional = false +python-versions = "*" +version = "0.10.0" + +[[package]] +category = "dev" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +name = "tornado" +optional = false +python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, != 3.3.*" +version = "5.1.1" + +[[package]] +category = "dev" +description = "a fork of Python 2 and 3 ast modules with type comment support" +name = "typed-ast" +optional = false +python-versions = "*" +version = "1.1.1" + +[[package]] +category = "dev" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" +version = "1.24.1" + +[[package]] +category = "dev" +description = "Module for decorators, wrappers and monkey patching." +name = "wrapt" +optional = false +python-versions = "*" +version = "1.10.11" + +[[package]] +category = "main" +description = "Automatic object-YAML mapping for Python." +name = "yorm" +optional = false +python-versions = "*" +version = "1.6" + +[package.dependencies] +PyYAML = ">=3.13,<4" +parse = ">=1.8.0,<1.9.0" +simplejson = ">=3.8,<4.0" + +[metadata] +content-hash = "5a1cd6ba7436357f8255485e60a3ced4c5ee881ee836815c125e86aacddb6057" +python-versions = "^3.5" + +[metadata.hashes] +altgraph = ["d6814989f242b2b43025cba7161fc1b8fb487a62cd49c49245d6fd01c18ac997", "ddf5320017147ba7b810198e0b6619bd7b5563aa034da388cea8546b877f9b0c"] +appdirs = ["9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", "d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"] +astroid = ["35b032003d6a863f5dcd7ec11abd5cd5893428beaa31ab164982403bcb311f22", "6a5d668d7dc69110de01cdf7aeec69a679ef486862a0850cc0fd5571505b6b7e"] +atomicwrites = ["0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", "ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"] +attrs = ["10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", "ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb"] +"backports.shutil-get-terminal-size" = ["0975ba55054c15e346944b38956a4c9cbee9009391e41b86c68990effb8c1f64", "713e7a8228ae80341c70586d1cc0a8caa5207346927e23d09dcbcaf18eadec80"] +black = ["817243426042db1d36617910df579a54f1afd659adb96fc5032fcf4b36209739", "e030a9a28f542debc08acceb273f228ac422798e5215ba2a791a6ddeaaca22a5"] +certifi = ["47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", "993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"] +chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"] +click = ["2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"] +colorama = ["463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda", "48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1"] +coverage = ["06123b58a1410873e22134ca2d88bd36680479fe354955b3579fb8ff150e4d27", "09e47c529ff77bf042ecfe858fb55c3e3eb97aac2c87f0349ab5a7efd6b3939f", "0a1f9b0eb3aa15c990c328535655847b3420231af299386cfe5efc98f9c250fe", "0cc941b37b8c2ececfed341444a456912e740ecf515d560de58b9a76562d966d", "0d34245f824cc3140150ab7848d08b7e2ba67ada959d77619c986f2062e1f0e8", "10e8af18d1315de936d67775d3a814cc81d0747a1a0312d84e27ae5610e313b0", "1b4276550b86caa60606bd3572b52769860a81a70754a54acc8ba789ce74d607", "1e8a2627c48266c7b813975335cfdea58c706fe36f607c97d9392e61502dc79d", "258b21c5cafb0c3768861a6df3ab0cfb4d8b495eee5ec660e16f928bf7385390", "2b224052bfd801beb7478b03e8a66f3f25ea56ea488922e98903914ac9ac930b", "3ad59c84c502cd134b0088ca9038d100e8fb5081bbd5ccca4863f3804d81f61d", "447c450a093766744ab53bf1e7063ec82866f27bcb4f4c907da25ad293bba7e3", "46101fc20c6f6568561cdd15a54018bb42980954b79aa46da8ae6f008066a30e", "4710dc676bb4b779c4361b54eb308bc84d64a2fa3d78e5f7228921eccce5d815", "510986f9a280cd05189b42eee2b69fecdf5bf9651d4cd315ea21d24a964a3c36", "5535dda5739257effef56e49a1c51c71f1d37a6e5607bb25a5eee507c59580d1", "5a7524042014642b39b1fcae85fb37556c200e64ec90824ae9ecf7b667ccfc14", "5f55028169ef85e1fa8e4b8b1b91c0b3b0fa3297c4fb22990d46ff01d22c2d6c", "6694d5573e7790a0e8d3d177d7a416ca5f5c150742ee703f3c18df76260de794", "6831e1ac20ac52634da606b658b0b2712d26984999c9d93f0c6e59fe62ca741b", "71afc1f5cd72ab97330126b566bbf4e8661aab7449f08895d21a5d08c6b051ff", "7349c27128334f787ae63ab49d90bf6d47c7288c63a0a5dfaa319d4b4541dd2c", "77f0d9fa5e10d03aa4528436e33423bfa3718b86c646615f04616294c935f840", "828ad813c7cdc2e71dcf141912c685bfe4b548c0e6d9540db6418b807c345ddd", "859714036274a75e6e57c7bab0c47a4602d2a8cfaaa33bbdb68c8359b2ed4f5c", "85a06c61598b14b015d4df233d249cd5abfa61084ef5b9f64a48e997fd829a82", "869ef4a19f6e4c6987e18b315721b8b971f7048e6eaea29c066854242b4e98d9", "8cb4febad0f0b26c6f62e1628f2053954ad2c555d67660f28dfb1b0496711952", "977e2d9a646773cc7428cdd9a34b069d6ee254fadfb4d09b3f430e95472f3cf3", "99bd767c49c775b79fdcd2eabff405f1063d9d959039c0bdd720527a7738748a", "a5c58664b23b248b16b96253880b2868fb34358911400a7ba39d7f6399935389", "aaa0f296e503cda4bc07566f592cd7a28779d433f3a23c48082af425d6d5a78f", "ab235d9fe64833f12d1334d29b558aacedfbca2356dfb9691f2d0d38a8a7bfb4", "b3b0c8f660fae65eac74fbf003f3103769b90012ae7a460863010539bb7a80da", "bab8e6d510d2ea0f1d14f12642e3f35cefa47a9b2e4c7cea1852b52bc9c49647", "c45297bbdbc8bb79b02cf41417d63352b70bcb76f1bbb1ee7d47b3e89e42f95d", "d19bca47c8a01b92640c614a9147b081a1974f69168ecd494687c827109e8f42", "d64b4340a0c488a9e79b66ec9f9d77d02b99b772c8b8afd46c1294c1d39ca478", "da969da069a82bbb5300b59161d8d7c8d423bc4ccd3b410a9b4d8932aeefc14b", "ed02c7539705696ecb7dc9d476d861f3904a8d2b7e894bd418994920935d36bb", "ee5b8abc35b549012e03a7b1e86c09491457dba6c94112a2482b18589cc2bdb9"] +coveragespace = ["498b54ec158a19e1f5647da681dc77fd9d17df11ecff1253d60ac7970209f6e5", "7c5ce4641e0f995b9be0e8b53401fd7b6d17db1b8c23bfd06f0c845ad0de5b5f"] +docopt = ["49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"] +freezegun = ["6cb82b276f83f2acce67f121dc2656f4df26c71e32238334eb071170b892a278", "e839b43bfbe8158b4d62bb97e6313d39f3586daf48e1314fb1083d2ef17700da"] +future = ["67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8"] +idna = ["c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"] +isort = ["1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af", "b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497"] +jinja2 = ["74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", "f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"] +lazy-object-proxy = ["0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33", "1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39", "209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019", "27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088", "27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b", "2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e", "2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6", "320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b", "50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5", "5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff", "61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd", "6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7", "7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff", "7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d", "7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2", "7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35", "81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4", "933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514", "94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252", "ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109", "bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f", "cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c", "d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92", "ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577", "e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d", "e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d", "e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f", "eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a", "f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b"] +livereload = ["29cadfabcedd12eed792e0131991235b9d4764d4474bed75cf525f57109ec0a2", "e632a6cd1d349155c1d7f13a65be873b38f43ef02961804a1bba8d817fa649a7"] +macfsevents = ["1324b66b356051de662ba87d84f73ada062acd42b047ed1246e60a449f833e10"] +macholib = ["ac02d29898cf66f27510d8f39e9112ae00590adb4a48ec57b25028d6962b1ae1", "c4180ffc6f909bf8db6cd81cff4b6f601d575568f4d5dee148c830e9851eb9db"] +markdown = ["c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa", "d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c"] +markupsafe = ["048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", "130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", "19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", "1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", "1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", "1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", "1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", "31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", "3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", "4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", "525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", "52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", "52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", "5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", "5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", "5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", "7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", "83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", "857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", "98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", "bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", "d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", "e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", "edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", "efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", "f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", "f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", "fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1"] +mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"] +mkdocs = ["17d34329aad75d5de604b9ed4e31df3a4d235afefdc46ce7b1964fddb2e1e939", "8cc8b38325456b9e942c981a209eaeb1e9f3f77b493ad755bfef889b9c8d356a"] +more-itertools = ["c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092", "c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e", "fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d"] +mypy = ["12d965c9c4e8a625673aec493162cf390e66de12ef176b1f4821ac00d55f3ab3", "38d5b5f835a81817dcc0af8d155bce4e9aefa03794fe32ed154d6612e83feafa"] +mypy-extensions = ["37e0e956f41369209a3d5f34580150bcacfabaa57b33a15c0b25f4b5725e0812", "b16cabe759f55e3409a7d231ebd2841378fb0c27a5d1994719e340e4f429ac3e"] +nose = ["9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", "dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", "f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"] +parse = ["c3cdf6206f22aeebfa00e5b954fcfea13d1b2dc271c75806b6025b94fb490939"] +pathlib2 = ["25199318e8cc3c25dcb45cbe084cc061051336d5a9ea2a12448d3d8cb748f742", "5887121d7f7df3603bca2f710e7219f3eca0eb69e0b7cc6e0a022e155ac931a7"] +pefile = ["4c5b7e2de0c8cb6c504592167acf83115cbbde01fe4a507c16a1422850e86cd6"] +pluggy = ["447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095", "bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f"] +py = ["bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", "e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6"] +pydocstyle = ["2258f9b0df68b97bf3a6c29003edc5238ff8879f1efb6f1999988d934e432bd8", "5741c85e408f9e0ddf873611085e819b809fca90b619f5fd7f34bd4959da3dd4", "ed79d4ec5e92655eccc21eb0c6cf512e69512b4a97d215ace46d17e4990f2039"] +pygments = ["5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", "e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"] +pyinstaller = ["a5a6e04a66abfcf8761e89a2ebad937919c6be33a7b8963e1a961b55cb35986b"] +pylint = ["689de29ae747642ab230c6d37be2b969bf75663176658851f456619aacf27492", "771467c434d0d9f081741fec1d64dfb011ed26e65e12a28fe06ca2f61c4d556c"] +pync = ["38b9e61735a3161f9211a5773c5f5ea698f36af4ff7f77fa03e8d1ff0caa117f"] +pytest = ["3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec", "e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"] +pytest-cov = ["513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7", "e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762"] +pytest-describe = ["bd6be131452b7822c872735ffe53ce3931b3b80cbbad1647c2b482cc9ef3d00e"] +pytest-expecter = ["1c8e9ab98ddd576436b61a7ba61ea11cfa5a3fc6b00288ce9e91e9dd770daf19", "27c93dfe87e2f4d28c525031be68d3f89457e3315241d97ee15f7689544e0e37"] +pytest-random = ["92f25db8c5d9ffc20d90b51997b914372d6955cb9cf1f6ead45b90514fc0eddd"] +python-dateutil = ["063df5763652e21de43de7d9e00ccf239f953a832941e37be541614732cdfc93", "88f9287c0174266bb0d8cedd395cfba9c58e87e5ad86b2ce58859bc11be3cf02"] +python-termstyle = ["6faf42ba42f2826c38cf70dacb3ac51f248a418e48afc0e36593df11cf3ab1d2", "f42a6bb16fbfc5e2c66d553e7ad46524ea833872f75ee5d827c15115fafc94e2"] +pyyaml = ["3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b", "3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf", "40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a", "558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3", "a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1", "aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1", "bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613", "d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04", "d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f", "e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537", "e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531"] +requests = ["502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", "7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"] +simplejson = ["067a7177ddfa32e1483ba5169ebea1bc2ea27f224853211ca669325648ca5642", "2b8cb601d9ba0381499db719ccc9dfbb2fbd16013f5ff096b1a68a4775576a04", "2c139daf167b96f21542248f8e0a06596c9b9a7a41c162cc5c9ee9f3833c93cd", "2fc546e6af49fb45b93bbe878dea4c48edc34083729c0abd09981fe55bdf7f91", "354fa32b02885e6dae925f1b5bbf842c333c1e11ea5453ddd67309dc31fdb40a", "37e685986cf6f8144607f90340cff72d36acf654f3653a6c47b84c5c38d00df7", "3af610ee72efbe644e19d5eaad575c73fb83026192114e5f6719f4901097fce2", "3b919fc9cf508f13b929a9b274c40786036b31ad28657819b3b9ba44ba651f50", "3dd289368bbd064974d9a5961101f080e939cbe051e6689a193c99fb6e9ac89b", "491de7acc423e871a814500eb2dcea8aa66c4a4b1b4825d18f756cdf58e370cb", "495511fe5f10ccf4e3ed4fc0c48318f533654db6c47ecbc970b4ed215c791968", "65b41a5cda006cfa7c66eabbcf96aa704a6be2a5856095b9e2fd8c293bad2b46", "6c3258ffff58712818a233b9737fe4be943d306c40cf63d14ddc82ba563f483a", "75e3f0b12c28945c08f54350d91e624f8dd580ab74fd4f1bbea54bc6b0165610", "79b129fe65fdf3765440f7a73edaffc89ae9e7885d4e2adafe6aa37913a00fbb", "b1f329139ba647a9548aa05fb95d046b4a677643070dc2afc05fa2e975d09ca5", "c206f47cbf9f32b573c9885f0ec813d2622976cf5effcf7e472344bc2e020ac1", "d8e238f20bcf70063ee8691d4a72162bcec1f4c38f83c93e6851e72ad545dabb", "ee9625fc8ee164902dfbb0ff932b26df112da9f871c32f0f9c1bcf20c350fe2a", "fb2530b53c28f0d4d84990e945c2ebb470edb469d63e389bf02ff409012fe7c5", "feadb95170e45f439455354904768608e356c5b174ca30b3d11b0e3f24b5c0df"] +six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] +sniffer = ["e8a0daa4c51dff3d00482b45dc9b978159100a8d5a7df327c28ed96586559970", "e90c1ad4bd3c31a5fad8e03d45dfc83377b31420aa0779f17280c817ce0c9dd8"] +snowballstemmer = ["919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", "9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89"] +toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] +tornado = ["0662d28b1ca9f67108c7e3b77afabfb9c7e87bde174fbda78186ecedc2499a9d", "4e5158d97583502a7e2739951553cbd88a72076f152b4b11b64b9a10c4c49409", "732e836008c708de2e89a31cb2fa6c0e5a70cb60492bee6f1ea1047500feaf7f", "8154ec22c450df4e06b35f131adc4f2f3a12ec85981a203301d310abf580500f", "8e9d728c4579682e837c92fdd98036bd5cdefa1da2aaf6acf26947e6dd0c01c5", "d4b3e5329f572f055b587efc57d29bd051589fb5a43ec8898c77a47ec2fa2bbb", "e5f2585afccbff22390cddac29849df463b252b711aa2ce7c5f3f342a5b3b444"] +typed-ast = ["0555eca1671ebe09eb5f2176723826f6f44cca5060502fea259de9b0e893ab53", "0ca96128ea66163aea13911c9b4b661cb345eb729a20be15c034271360fc7474", "16ccd06d614cf81b96de42a37679af12526ea25a208bce3da2d9226f44563868", "1e21ae7b49a3f744958ffad1737dfbdb43e1137503ccc59f4e32c4ac33b0bd1c", "37670c6fd857b5eb68aa5d193e14098354783b5138de482afa401cc2644f5a7f", "46d84c8e3806619ece595aaf4f37743083f9454c9ea68a517f1daa05126daf1d", "5b972bbb3819ece283a67358103cc6671da3646397b06e7acea558444daf54b2", "6306ffa64922a7b58ee2e8d6f207813460ca5a90213b4a400c2e730375049246", "6cb25dc95078931ecbd6cbcc4178d1b8ae8f2b513ae9c3bd0b7f81c2191db4c6", "7e19d439fee23620dea6468d85bfe529b873dace39b7e5b0c82c7099681f8a22", "7f5cd83af6b3ca9757e1127d852f497d11c7b09b4716c355acfbebf783d028da", "81e885a713e06faeef37223a5b1167615db87f947ecc73f815b9d1bbd6b585be", "94af325c9fe354019a29f9016277c547ad5d8a2d98a02806f27a7436b2da6735", "b1e5445c6075f509d5764b84ce641a1535748801253b97f3b7ea9d948a22853a", "cb061a959fec9a514d243831c514b51ccb940b58a5ce572a4e209810f2507dcf", "cc8d0b703d573cbabe0d51c9d68ab68df42a81409e4ed6af45a04a95484b96a5", "da0afa955865920edb146926455ec49da20965389982f91e926389666f5cf86a", "dc76738331d61818ce0b90647aedde17bbba3d3f9e969d83c1d9087b4f978862", "e7ec9a1445d27dbd0446568035f7106fa899a36f55e52ade28020f7b3845180d", "f741ba03feb480061ab91a465d1a3ed2d40b52822ada5b4017770dfcb88f839f", "fe800a58547dd424cd286b7270b967b5b3316b993d86453ede184a17b5a6b17d"] +urllib3 = ["61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", "de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"] +wrapt = ["d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"] +yorm = ["863674ad8e1cfe5b8aa42e333039c0f54d591bb0d28ff9d4299b8109a02239f9", "aa540ccb087a9c3a8eac385073a2da1c5362591b45dec7a9a2cb212e898d9f84"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..3287964b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,95 @@ +[tool.poetry] + +name = "gitman" +version = "1.6a4" +description = "A language-agnostic dependency manager using Git." + +license = "MIT" + +authors = ["Jace Browning "] + +readme = "README.md" + +homepage = "https://pypi.org/project/gitman" +documentation = "https://gitman.readthedocs.io" +repository = "https://github.com/jacebrowning/gitman" + +keywords = [ + "git", + "version control", + "build systems", + "dependency management", + "submodules", +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Topic :: Software Development", + "Topic :: Software Development :: Build Tools", + "Topic :: Software Development :: Version Control", + "Topic :: System :: Software Distribution", +] + +[tool.poetry.dependencies] + +python = "^3.5" + +YORM = "^1.3" + +[tool.poetry.dev-dependencies] + +# Formatters +black = { version = "=18.9b0", python = "^3.6" } +isort = "=4.3.4" + +# Linters +mypy = "*" +pydocstyle = "*" +pylint = "^2.0" + +# Testing +pytest = "^3.3" +pytest-cov = "*" +pytest-describe = "*" +pytest-expecter = "*" +pytest-random = "*" +freezegun = "*" + +# Reports +coveragespace = "*" + +# Documentation +mkdocs = "^1.0" +pygments = "*" + +# Tooling +pyinstaller = "*" +sniffer = "*" +MacFSEvents = { version = "*", platform = "darwin" } +pync = { version = "*", platform = "darwin" } + +[tool.poetry.scripts] + +gitman = "gitman.cli:main" +git-deps = "gitman.plugin:main" + +gdm = "gitman.cli:main" # legacy entry point + +[tool.black] + +py36 = true +skip-string-normalization = true + +[build-system] + +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" diff --git a/scent.py b/scent.py index ab6b337b..f003eebf 100644 --- a/scent.py +++ b/scent.py @@ -1,12 +1,9 @@ """Configuration file for sniffer.""" -# pylint: disable=superfluous-parens,bad-continuation,unpacking-non-sequence -import subprocess import time +import subprocess -from sniffer.api import file_validator, runnable, select_runnable - - +from sniffer.api import select_runnable, file_validator, runnable try: from pync import Notifier except ImportError: diff --git a/setup.py b/setup.py deleted file mode 100644 index 8b996779..00000000 --- a/setup.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python - -import os -import sys - -import setuptools - - -PACKAGE_NAME = 'gitman' -MINIMUM_PYTHON_VERSION = '3.5' - - -def check_python_version(): - """Exit when the Python version is too low.""" - if sys.version < MINIMUM_PYTHON_VERSION: - sys.exit("Python {0}+ is required.".format(MINIMUM_PYTHON_VERSION)) - - -def read_package_variable(key, filename='__init__.py'): - """Read the value of a variable from the package without importing.""" - module_path = os.path.join(PACKAGE_NAME, filename) - with open(module_path) as module: - for line in module: - parts = line.strip().split(' ', 2) - if parts[:-1] == [key, '=']: - return parts[-1].strip("'") - sys.exit("'%s' not found in '%s'", key, module_path) - - -def build_description(): - """Build a description for the project from documentation files.""" - readme = open("README.md").read() - changelog = open("CHANGELOG.md").read() - return readme + '\n' + changelog - - -check_python_version() - -setuptools.setup( - name=read_package_variable('__project__'), - version=read_package_variable('__version__'), - - description=read_package_variable('DESCRIPTION'), - url='https://github.com/jacebrowning/gitman', - author='Jace Browning', - author_email='jacebrowning@gmail.com', - - packages=setuptools.find_packages(), - - entry_points={'console_scripts': [ - read_package_variable('CLI') + ' = gitman.cli:main', - 'git-' + read_package_variable('PLUGIN') + ' = gitman.plugin:main', - # Legacy entry points: - 'gdm = gitman.cli:main', - ]}, - - long_description=build_description(), - long_description_content_type='text/markdown', - license='MIT', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Topic :: Software Development', - 'Topic :: Software Development :: Build Tools', - 'Topic :: Software Development :: Version Control', - 'Topic :: System :: Software Distribution', - ], - - install_requires=[ - 'YORM~=1.3', - ], -) diff --git a/tests/__init__.py b/tests/__init__.py index 96f579f0..250ed9e4 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -3,4 +3,4 @@ try: from IPython.terminal.debugger import TerminalPdb as Debugger except ImportError: - from pdb import Pdb as Debugger + from pdb import Pdb as Debugger # type: ignore diff --git a/tests/test_api.py b/tests/test_api.py index 64aa78a1..ae2dffed 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -77,13 +77,13 @@ def config(): def describe_init(): - def it_creates_a_new_config_file(tmpdir): tmpdir.chdir() expect(gitman.init()) == True - expect(Config().__mapper__.text) == strip(""" + expect(Config().__mapper__.text) == strip( + """ location: gitman_sources sources: - name: sample_dependency @@ -105,7 +105,8 @@ def it_creates_a_new_config_file(tmpdir): link: scripts: - - """) + """ + ) def it_does_not_modify_existing_config_file(config): expect(gitman.init()) == False @@ -114,7 +115,6 @@ def it_does_not_modify_existing_config_file(config): def describe_install(): - def it_creates_missing_directories(config): shell.rm(config.location) @@ -128,7 +128,8 @@ def it_should_not_modify_config(config): expect(config.__mapper__.text) == CONFIG def it_merges_sources(config): - config.__mapper__.text = strip(""" + config.__mapper__.text = strip( + """ location: deps sources: - name: gitman_1 @@ -153,14 +154,16 @@ def it_merges_sources(config): link: scripts: - - """) + """ + ) expect(gitman.install(depth=1)) == True expect(len(os.listdir(config.location))) == 3 def it_can_handle_missing_locked_sources(config): - config.__mapper__.text = strip(""" + config.__mapper__.text = strip( + """ location: deps sources: - name: gitman_1 @@ -177,7 +180,8 @@ def it_can_handle_missing_locked_sources(config): link: scripts: - - """) + """ + ) expect(gitman.install('gitman_1', depth=1)) == True @@ -195,10 +199,10 @@ def it_detects_invalid_repositories(config): shell.rm(os.path.join("deps", "gitman_1")) def describe_links(): - @pytest.fixture def config_with_link(config): - config.__mapper__.text = strip(""" + config.__mapper__.text = strip( + """ location: deps sources: - name: gitman_1 @@ -207,7 +211,8 @@ def config_with_link(config): link: my_link scripts: - - """) + """ + ) return config @@ -231,10 +236,10 @@ def it_overwrites_files_with_force(config_with_link): expect(gitman.install(depth=1, force=True)) == True def describe_scripts(): - @pytest.fixture def config_with_scripts(config): - config.__mapper__.text = strip(""" + config.__mapper__.text = strip( + """ location: deps sources: - name: gitman_1 @@ -244,7 +249,8 @@ def config_with_scripts(config): link: scripts: - make foobar - """) + """ + ) return config @@ -258,7 +264,8 @@ def script_failures_can_be_ignored(config_with_scripts): def describe_sparse_paths(): @pytest.fixture def config_with_scripts(config): - config.__mapper__.text = strip(""" + config.__mapper__.text = strip( + """ location: deps sources: - name: gitman_1 @@ -270,7 +277,8 @@ def config_with_scripts(config): link: scripts: - - """) + """ + ) return config @@ -287,7 +295,6 @@ def it_contains_only_the_sparse_paths(config): def describe_uninstall(): - def it_deletes_dependencies_when_they_exist(config): gitman.install('gitman_1', depth=1) expect(os.path.isdir(config.location)) == True @@ -311,7 +318,6 @@ def it_deletes_the_log_file(config): def describe_keep_location(): - def it_deletes_dependencies_when_they_exist(config): gitman.install('gitman_1', depth=1) expect(os.path.isdir(config.location)) == True @@ -344,14 +350,14 @@ def it_deletes_the_log_file(config): def describe_update(): - def it_should_not_modify_config(config): gitman.update('gitman_1', depth=1) expect(config.__mapper__.text) == CONFIG def it_locks_previously_locked_dependnecies(config): - config.__mapper__.text = strip(""" + config.__mapper__.text = strip( + """ location: deps sources: - name: gitman_1 @@ -382,11 +388,13 @@ def it_locks_previously_locked_dependnecies(config): link: scripts: - - """) + """ + ) gitman.update(depth=1) - expect(config.__mapper__.text) == strip(""" + expect(config.__mapper__.text) == strip( + """ location: deps sources: - name: gitman_1 @@ -417,10 +425,12 @@ def it_locks_previously_locked_dependnecies(config): link: scripts: - - """) + """ + ) def it_should_not_lock_dependnecies_when_disabled(config): - config.__mapper__.text = strip(""" + config.__mapper__.text = strip( + """ location: deps sources: - name: gitman_1 @@ -451,11 +461,13 @@ def it_should_not_lock_dependnecies_when_disabled(config): link: scripts: - - """) + """ + ) gitman.update(depth=1, lock=False) - expect(config.__mapper__.text) == strip(""" + expect(config.__mapper__.text) == strip( + """ location: deps sources: - name: gitman_1 @@ -486,12 +498,14 @@ def it_should_not_lock_dependnecies_when_disabled(config): link: scripts: - - """) + """ + ) def it_should_lock_all_dependencies_when_enabled(config): gitman.update(depth=1, lock=True) - expect(config.__mapper__.text) == CONFIG + strip(""" + expect(config.__mapper__.text) == CONFIG + strip( + """ sources_locked: - name: gitman_1 type: git @@ -520,11 +534,11 @@ def it_should_lock_all_dependencies_when_enabled(config): link: scripts: - - """) + """ + ) def describe_list(): - @freeze_time("2012-01-14 12:00:01") def it_updates_the_log(config): gitman.install() @@ -532,7 +546,8 @@ def it_updates_the_log(config): with open(config.log_path) as stream: contents = stream.read().replace(TMP, "tmp").replace('\\', '/') - expect(contents) == strip(""" + expect(contents) == strip( + """ 2012-01-14 12:00:01 tmp/deps/gitman_1: https://github.com/jacebrowning/gitman-demo @ 1de84ca1d315f81b035cd7b0ecf87ca2025cdacd tmp/deps/gitman_1/gitman_sources/gdm_3: https://github.com/jacebrowning/gdm-demo @ 050290bca3f14e13fd616604202b579853e7bfb0 @@ -541,16 +556,18 @@ def it_updates_the_log(config): tmp/deps/gitman_1/gitman_sources/gdm_4: https://github.com/jacebrowning/gdm-demo @ 63ddfd82d308ddae72d31b61cb8942c898fa05b5 tmp/deps/gitman_2: https://github.com/jacebrowning/gitman-demo @ 7bd138fe7359561a8c2ff9d195dff238794ccc04 tmp/deps/gitman_3: https://github.com/jacebrowning/gitman-demo @ 9bf18e16b956041f0267c21baad555a23237b52e - """, end='\n\n') + """, + end='\n\n', + ) def describe_lock(): - def it_records_all_versions_when_no_arguments(config): expect(gitman.update(depth=1, lock=False)) == True expect(gitman.lock()) == True - expect(config.__mapper__.text) == CONFIG + strip(""" + expect(config.__mapper__.text) == CONFIG + strip( + """ sources_locked: - name: gitman_1 type: git @@ -579,13 +596,15 @@ def it_records_all_versions_when_no_arguments(config): link: scripts: - - """) == config.__mapper__.text + """ + ) == config.__mapper__.text def it_records_specified_dependencies(config): expect(gitman.update(depth=1, lock=False)) == True expect(gitman.lock('gitman_1', 'gitman_3')) == True - expect(config.__mapper__.text) == CONFIG + strip(""" + expect(config.__mapper__.text) == CONFIG + strip( + """ sources_locked: - name: gitman_1 type: git @@ -605,7 +624,8 @@ def it_records_specified_dependencies(config): link: scripts: - - """) == config.__mapper__.text + """ + ) == config.__mapper__.text def it_should_fail_on_dirty_repositories(config): expect(gitman.update(depth=1, lock=False)) == True diff --git a/tests/test_cli.py b/tests/test_cli.py index 64c20ee4..b7efd81f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -27,7 +27,6 @@ def location(tmpdir): def describe_show(): - @patch('gitman.common.show') def it_prints_location_by_default(show, location): cli.main(['show']) @@ -38,9 +37,7 @@ def it_prints_location_by_default(show, location): def it_can_print_a_depenendcy_path(show, location): cli.main(['show', 'bar']) - expect(show.mock_calls) == [ - call(os.path.join(location, "bar"), color='path'), - ] + expect(show.mock_calls) == [call(os.path.join(location, "bar"), color='path')] def it_exits_when_no_config_found(tmpdir): tmpdir.chdir() @@ -50,7 +47,6 @@ def it_exits_when_no_config_found(tmpdir): def describe_edit(): - @patch('gitman.system.launch') def it_launches_the_config(launch, config): cli.main(['edit']) diff --git a/tests/test_main.py b/tests/test_main.py index a8624a84..67df336b 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -7,7 +7,6 @@ def describe_main(): - def it_displays_version(): code = subprocess.call([sys.executable, "-m", "gitman", "--version"]) expect(code) == 0 From 99d071761e247b9524c2f7c78b77510c8baf69a8 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Tue, 25 Dec 2018 12:55:02 -0500 Subject: [PATCH 37/49] Update badges --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ef76a1ff..eaca5e74 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,16 @@ -Unix: [![Build Status](https://travis-ci.org/jacebrowning/gitman.svg?branch=develop)](https://travis-ci.org/jacebrowning/gitman) Windows: [![Windows Build Status](https://img.shields.io/appveyor/ci/jacebrowning/gitman/develop.svg)](https://ci.appveyor.com/project/jacebrowning/gitman)
Metrics: [![Coverage Status](https://img.shields.io/coveralls/jacebrowning/gitman/develop.svg)](https://coveralls.io/r/jacebrowning/gitman) [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/jacebrowning/gitman.svg)](https://scrutinizer-ci.com/g/jacebrowning/gitman/?branch=develop)
Usage: [![PyPI Version](https://img.shields.io/pypi/v/GitMan.svg)](https://pypi.org/project/GitMan) - # Overview GitMan is a language-agnostic dependency manager using Git. It aims to serve as a submodules replacement and provides advanced options for managing versions of nested Git repositories. ![demo](https://raw.githubusercontent.com/jacebrowning/gitman/develop/docs/demo.gif) +[![Unix Build Status](https://img.shields.io/travis/jacebrowning/gitman/master.svg?label=unix)](https://travis-ci.org/jacebrowning/gitman) +[![Windows Build Status](https://img.shields.io/appveyor/ci/jacebrowning/gitman/master.svg?label=window)](https://ci.appveyor.com/project/jacebrowning/gitman) +[![Coverage Status](https://img.shields.io/coveralls/jacebrowning/gitman/master.svg)](https://coveralls.io/r/jacebrowning/gitman) +[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/jacebrowning/gitman.svg)](https://scrutinizer-ci.com/g/jacebrowning/gitman/?branch=master) +[![PyPI Version](https://img.shields.io/pypi/v/GitMan.svg)](https://pypi.org/project/GitMan) +[![PyPI License](https://img.shields.io/pypi/l/GitMan.svg)](https://pypi.org/project/GitMan) + # Setup ## Requirements From 46610238c11ae9abfe3f0a06acada53063d70281 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Tue, 25 Dec 2018 13:06:07 -0500 Subject: [PATCH 38/49] Fix cyclic import --- gitman/models/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitman/models/config.py b/gitman/models/config.py index c5d4a380..781820f0 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -4,8 +4,8 @@ import yorm from yorm.types import SortedList, String -from . import Source from .. import common, shell +from .source import Source log = logging.getLogger(__name__) From ca63e7bec1dd3cc741bfab5f6000dce034bd78bc Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Tue, 25 Dec 2018 21:08:33 -0500 Subject: [PATCH 39/49] Enable type checking --- .appveyor.yml | 2 -- .travis.yml | 1 - CHANGELOG.md | 1 + Makefile | 6 ++---- gitman/cli.py | 29 ++++++++++++++--------------- gitman/models/config.py | 7 ++++--- gitman/models/source.py | 11 ++++++----- gitman/plugin.py | 10 ++++++---- poetry.lock | 24 ++---------------------- pyproject.toml | 5 ++--- 10 files changed, 37 insertions(+), 59 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index e25255be..cc1c35a9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,8 +2,6 @@ environment: global: RANDOM_SEED: 0 matrix: - - PYTHON_MAJOR: 3 - PYTHON_MINOR: 5 - PYTHON_MAJOR: 3 PYTHON_MINOR: 6 - PYTHON_MAJOR: 3 diff --git a/.travis.yml b/.travis.yml index 058b695c..8a080b1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: python python: - - 3.5 - 3.6 matrix: include: diff --git a/CHANGELOG.md b/CHANGELOG.md index c601b9c6..7bc21f5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Added `git svn` support. (@daniel-brosche) - Added `$GITMAN_CACHE_DISABLE` to disable repository mirrors. (@daniel-brosche) +- **BREAKING**: Dropped support for Python 3.5. # 1.5 (2018-09-08) diff --git a/Makefile b/Makefile index 7e9b5b8e..aa87433f 100644 --- a/Makefile +++ b/Makefile @@ -61,8 +61,7 @@ poetry.lock: pyproject.toml .PHONY: format format: install poetry run isort $(PACKAGES) --recursive --apply - # TODO: Enable after dropping Python 3.5 support - - poetry run black $(PACKAGES) + poetry run black $(PACKAGES) @ echo .PHONY: check @@ -71,8 +70,7 @@ ifdef CI git diff --exit-code endif poetry run pylint $(PACKAGES) --rcfile=.pylint.ini - # TODO: Enable after dropping Python 3.5 support - # poetry run mypy $(PACKAGES) --config-file=.mypy.ini + poetry run mypy $(PACKAGES) --config-file=.mypy.ini poetry run pydocstyle $(PACKAGES) $(CONFIG) # TESTS ####################################################################### diff --git a/gitman/cli.py b/gitman/cli.py index bf5f2b5a..63a5ace6 100644 --- a/gitman/cli.py +++ b/gitman/cli.py @@ -5,6 +5,7 @@ import argparse import logging import sys +from typing import Dict, List from . import __version__, commands, common, exceptions @@ -57,24 +58,22 @@ def main(args=None, function=None): # pylint: disable=too-many-statements '-f', '--force', action='store_true', - help=("overwrite uncommitted changes " "in dependencies"), + help="overwrite uncommitted changes in dependencies", ) options_group.add_argument( '-s', '--skip-changes', action='store_true', dest='skip_changes', - help=("skip dependencies with " "uncommitted changes"), + help="skip dependencies with uncommitted changes", ) - shared = {'formatter_class': common.WideHelpFormatter} - # Main parser parser = argparse.ArgumentParser( prog='gitman', description="A language-agnostic dependency manager using Git.", parents=[debug], - **shared, + formatter_class=common.WideHelpFormatter, ) subs = parser.add_subparsers(help="", dest='command', metavar="") @@ -85,7 +84,7 @@ def main(args=None, function=None): # pylint: disable=too-many-statements description=info.capitalize() + '.', help=info, parents=[debug], - **shared, + formatter_class=common.WideHelpFormatter, ) # Install parser @@ -95,7 +94,7 @@ def main(args=None, function=None): # pylint: disable=too-many-statements description=info.capitalize() + '.', help=info, parents=[debug, project, depth, options], - **shared, + formatter_class=common.WideHelpFormatter, ) sub.add_argument('name', nargs='*', help="list of dependencies names to install") sub.add_argument( @@ -109,7 +108,7 @@ def main(args=None, function=None): # pylint: disable=too-many-statements description=info.capitalize() + '.', help=info, parents=[debug, project, depth, options], - **shared, + formatter_class=common.WideHelpFormatter, ) sub.add_argument('name', nargs='*', help="list of dependencies names to update") sub.add_argument( @@ -135,7 +134,7 @@ def main(args=None, function=None): # pylint: disable=too-many-statements description=info.capitalize() + '.', help=info, parents=[debug, project, depth], - **shared, + formatter_class=common.WideHelpFormatter, ) sub.add_argument( '-D', @@ -152,7 +151,7 @@ def main(args=None, function=None): # pylint: disable=too-many-statements description=info.capitalize() + '.', help=info, parents=[debug, project], - **shared, + formatter_class=common.WideHelpFormatter, ) sub.add_argument('name', nargs='*', help="list of dependency names to lock") @@ -163,7 +162,7 @@ def main(args=None, function=None): # pylint: disable=too-many-statements description=info.capitalize() + '.', help=info, parents=[debug, project], - **shared, + formatter_class=common.WideHelpFormatter, ) sub.add_argument( '-f', @@ -187,7 +186,7 @@ def main(args=None, function=None): # pylint: disable=too-many-statements description=info.capitalize() + '.', help=info, parents=[debug, project], - **shared, + formatter_class=common.WideHelpFormatter, ) sub.add_argument('name', nargs='*', help="display the path of this dependency") sub.add_argument( @@ -207,7 +206,7 @@ def main(args=None, function=None): # pylint: disable=too-many-statements description=info.capitalize() + '.', help=info, parents=[debug, project], - **shared, + formatter_class=common.WideHelpFormatter, ) # Parse arguments @@ -226,8 +225,8 @@ def main(args=None, function=None): # pylint: disable=too-many-statements def _get_command(function, namespace): # pylint: disable=too-many-statements - args = [] - kwargs = {} + args: List = [] + kwargs: Dict = {} if namespace.command == 'init': function = commands.init diff --git a/gitman/models/config.py b/gitman/models/config.py index 781820f0..93b384f6 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -1,5 +1,6 @@ import logging import os +from typing import List import yorm from yorm.types import SortedList, String @@ -25,8 +26,8 @@ def __init__(self, root=None, filename="gitman.yml", location="gitman_sources"): self.root = root or os.getcwd() self.filename = filename self.location = location - self.sources = [] - self.sources_locked = [] + self.sources: List[Source] = [] + self.sources_locked: List[Source] = [] def _on_post_load(self): for source in self.sources: @@ -270,7 +271,7 @@ def _get_sources(self, *, use_locked=None): log.info("No locked sources, defaulting to none...") return [] - sources = [] + sources: List[Source] = [] if use_locked is False: sources = self.sources else: diff --git a/gitman/models/source.py b/gitman/models/source.py index b3770cd3..cd42e0d7 100644 --- a/gitman/models/source.py +++ b/gitman/models/source.py @@ -98,15 +98,16 @@ def update_files(self, force=False, fetch=False, clean=True, skip_changes=False) if git.changes( self.type, include_untracked=clean, display_status=False ): - msg = ("Skipped update due to uncommitted changes " "in {}").format( - os.getcwd() + common.show( + f'Skipped update due to uncommitted changes in {os.getcwd()}', + color='git_changes', ) - common.show(msg, color='git_changes') return else: if git.changes(self.type, include_untracked=clean): - msg = "Uncommitted changes in {}".format(os.getcwd()) - raise exceptions.UncommittedChanges(msg) + raise exceptions.UncommittedChanges( + f'Uncommitted changes in {os.getcwd()}' + ) # Fetch the desired revision if fetch or git.is_fetch_required(self.type, self.rev): diff --git a/gitman/plugin.py b/gitman/plugin.py index 05883620..bfa3c10c 100644 --- a/gitman/plugin.py +++ b/gitman/plugin.py @@ -42,7 +42,6 @@ def main(args=None): # Options group group = parser.add_mutually_exclusive_group() - shared = dict(action='store_const', dest='command') # Update option group.add_argument( @@ -50,7 +49,8 @@ def main(args=None): '--update', const='update', help="update dependencies to the latest versions", - **shared, + action='store_const', + dest='command', ) parser.add_argument( '-a', @@ -74,7 +74,8 @@ def main(args=None): '--list', const='list', help="display the current version of each dependency", - **shared, + action='store_const', + dest='command', ) # Uninstall option @@ -83,7 +84,8 @@ def main(args=None): '--uninstall', const='uninstall', help="delete all installed dependencies", - **shared, + action='store_const', + dest='command', ) parser.add_argument( '-k', diff --git a/poetry.lock b/poetry.lock index f3a258a2..8739c887 100644 --- a/poetry.lock +++ b/poetry.lock @@ -9,7 +9,6 @@ version = "0.16.1" [[package]] category = "dev" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -marker = "python_version >= \"3.6\" and python_version < \"4.0\"" name = "appdirs" optional = false python-versions = "*" @@ -59,7 +58,6 @@ version = "1.0.0" [[package]] category = "dev" description = "The uncompromising code formatter." -marker = "python_version >= \"3.6\" and python_version < \"4.0\"" name = "black" optional = false python-versions = ">=3.6" @@ -308,18 +306,6 @@ optional = false python-versions = "*" version = "1.8.4" -[[package]] -category = "dev" -description = "Object-oriented filesystem paths" -marker = "python_version < \"3.6\"" -name = "pathlib2" -optional = false -python-versions = "*" -version = "2.3.3" - -[package.dependencies] -six = "*" - [[package]] category = "dev" description = "Python PE parsing module" @@ -425,10 +411,6 @@ py = ">=1.5.0" setuptools = "*" six = ">=1.10.0" -[package.dependencies.pathlib2] -python = "<3.6" -version = ">=2.2.0" - [[package]] category = "dev" description = "Pytest plugin for measuring coverage." @@ -555,7 +537,6 @@ version = "1.2.1" [[package]] category = "dev" description = "Python Library for Tom's Obvious, Minimal Language" -marker = "python_version >= \"3.6\" and python_version < \"4.0\"" name = "toml" optional = false python-versions = "*" @@ -607,8 +588,8 @@ parse = ">=1.8.0,<1.9.0" simplejson = ">=3.8,<4.0" [metadata] -content-hash = "5a1cd6ba7436357f8255485e60a3ced4c5ee881ee836815c125e86aacddb6057" -python-versions = "^3.5" +content-hash = "3e412bc2d9a2e99db9290c27f3977f3eec75e8cbb89eefd7d8498c5b89b2c898" +python-versions = "^3.6" [metadata.hashes] altgraph = ["d6814989f242b2b43025cba7161fc1b8fb487a62cd49c49245d6fd01c18ac997", "ddf5320017147ba7b810198e0b6619bd7b5563aa034da388cea8546b877f9b0c"] @@ -643,7 +624,6 @@ mypy = ["12d965c9c4e8a625673aec493162cf390e66de12ef176b1f4821ac00d55f3ab3", "38d mypy-extensions = ["37e0e956f41369209a3d5f34580150bcacfabaa57b33a15c0b25f4b5725e0812", "b16cabe759f55e3409a7d231ebd2841378fb0c27a5d1994719e340e4f429ac3e"] nose = ["9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", "dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", "f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"] parse = ["c3cdf6206f22aeebfa00e5b954fcfea13d1b2dc271c75806b6025b94fb490939"] -pathlib2 = ["25199318e8cc3c25dcb45cbe084cc061051336d5a9ea2a12448d3d8cb748f742", "5887121d7f7df3603bca2f710e7219f3eca0eb69e0b7cc6e0a022e155ac931a7"] pefile = ["4c5b7e2de0c8cb6c504592167acf83115cbbde01fe4a507c16a1422850e86cd6"] pluggy = ["447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095", "bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f"] py = ["bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", "e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6"] diff --git a/pyproject.toml b/pyproject.toml index 3287964b..cb37d13b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,6 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development", @@ -41,14 +40,14 @@ classifiers = [ [tool.poetry.dependencies] -python = "^3.5" +python = "^3.6" YORM = "^1.3" [tool.poetry.dev-dependencies] # Formatters -black = { version = "=18.9b0", python = "^3.6" } +black = "=18.9b0" isort = "=4.3.4" # Linters From 98a412d322a6a1c78ead98adc44cb0ee075b0165 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Tue, 25 Dec 2018 21:48:29 -0500 Subject: [PATCH 40/49] Require Python 3.6+ --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eaca5e74..9d34b2d0 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ GitMan is a language-agnostic dependency manager using Git. It aims to serve as ## Requirements -* Python 3.5+ +* Python 3.6+ * Git 2.8+ (with [stored credentials](http://gitman.readthedocs.io/en/latest/setup/git/)) ## Installation From e7d2661b975de9c308b34849cbea285fe7dabacd Mon Sep 17 00:00:00 2001 From: Daniel Brosche Date: Fri, 11 Jan 2019 19:38:33 +0100 Subject: [PATCH 41/49] Added skip-changes note to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bc21f5d..dadfb837 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Added `git svn` support. (@daniel-brosche) - Added `$GITMAN_CACHE_DISABLE` to disable repository mirrors. (@daniel-brosche) +- Added `--skip-changes` option to skip changed dependencies on install or update command - **BREAKING**: Dropped support for Python 3.5. # 1.5 (2018-09-08) From aa3a536f75ec79e5bb465b147e30eb9a862d8592 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Sun, 20 Jan 2019 11:40:19 -0600 Subject: [PATCH 42/49] Remove reference to source install Closes #190 --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9d34b2d0..e6b890be 100644 --- a/README.md +++ b/README.md @@ -20,18 +20,16 @@ GitMan is a language-agnostic dependency manager using Git. It aims to serve as ## Installation -Install GitMan with pip: +Install this tool globally: -```sh +``` $ pip install gitman ``` -or directly from the source code: +or add it to your [Poetry](https://poetry.eustace.io/) project: -```sh -$ git clone https://github.com/jacebrowning/gitman.git -$ cd gitman -$ python setup.py install +``` +$ poetry add gitman ``` ## Configuration From 389d8a72064af219bcceded2931652d8d8e59386 Mon Sep 17 00:00:00 2001 From: Daniel B Date: Mon, 21 Jan 2019 22:53:40 +0100 Subject: [PATCH 43/49] Create reproducible rev-parse dates --- gitman/git.py | 8 +++++++- gitman/tests/test_git.py | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/gitman/git.py b/gitman/git.py index 01f7395f..38e9a6b5 100644 --- a/gitman/git.py +++ b/gitman/git.py @@ -230,6 +230,12 @@ def _get_sha_from_rev(rev): date = parts[1].strip("{}") git('checkout', '--force', branch, _show=False) rev = git( - 'rev-list', '-n', '1', '--before={!r}'.format(date), branch, _show=False + 'rev-list', + '-n', + '1', + '--before={!r}'.format(date), + '--first-parent', + branch, + _show=False, )[0] return rev diff --git a/gitman/tests/test_git.py b/gitman/tests/test_git.py index cf9767a2..8dc34751 100644 --- a/gitman/tests/test_git.py +++ b/gitman/tests/test_git.py @@ -188,7 +188,10 @@ def test_update_revparse(self, mock_call): "git stash", "git clean --force -d -x", "git checkout --force mock_branch", - "git rev-list -n 1 --before='2015-02-12 18:30:00' mock_branch", + ( + "git rev-list -n 1 --before='2015-02-12 18:30:00' " + "--first-parent mock_branch" + ), "git checkout --force abc123", "git branch --set-upstream-to origin/abc123", ], From 2bb97acdf0a0ab6cd7a550b7f7f70f47bf7f5c9f Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Mon, 21 Jan 2019 17:03:41 -0500 Subject: [PATCH 44/49] Bust AppVeyor cache via poetry lock --- .appveyor.yml | 2 +- gitman/exceptions.py | 2 +- poetry.lock | 30 +++++++++++++++--------------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index cc1c35a9..808c2365 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -8,7 +8,7 @@ environment: PYTHON_MINOR: 7 cache: - - .venv -> Makefile + - .venv -> poetry.lock install: # Add Make and Python to the PATH diff --git a/gitman/exceptions.py b/gitman/exceptions.py index dbf6c4a5..a4305fdd 100644 --- a/gitman/exceptions.py +++ b/gitman/exceptions.py @@ -11,7 +11,7 @@ class ShellError(RuntimeError): def __init__(self, *args, **kwargs): self.program = kwargs.pop('program', None) self.output = kwargs.pop('output', None) - super().__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # type: ignore class InvalidRepository(RuntimeError): diff --git a/poetry.lock b/poetry.lock index 8739c887..e21e9745 100644 --- a/poetry.lock +++ b/poetry.lock @@ -265,7 +265,7 @@ description = "More routines for operating on iterables, beyond itertools" name = "more-itertools" optional = false python-versions = "*" -version = "4.3.0" +version = "5.0.0" [package.dependencies] six = ">=1.0.0,<2.0.0" @@ -276,11 +276,11 @@ description = "Optional static typing for Python" name = "mypy" optional = false python-versions = "*" -version = "0.650" +version = "0.660" [package.dependencies] -mypy-extensions = ">=0.4.0,<0.5.0" -typed-ast = ">=1.1.0,<1.2.0" +mypy_extensions = ">=0.4.0,<0.5.0" +typed-ast = ">=1.2.0,<1.3.0" [[package]] category = "dev" @@ -323,7 +323,7 @@ description = "plugin and hook calling mechanisms for python" name = "pluggy" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.8.0" +version = "0.8.1" [[package]] category = "dev" @@ -417,11 +417,11 @@ description = "Pytest plugin for measuring coverage." name = "pytest-cov" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.6.0" +version = "2.6.1" [package.dependencies] coverage = ">=4.4" -pytest = ">=2.9" +pytest = ">=3.6" [[package]] category = "dev" @@ -556,7 +556,7 @@ description = "a fork of Python 2 and 3 ast modules with type comment support" name = "typed-ast" optional = false python-versions = "*" -version = "1.1.1" +version = "1.2.0" [[package]] category = "dev" @@ -572,7 +572,7 @@ description = "Module for decorators, wrappers and monkey patching." name = "wrapt" optional = false python-versions = "*" -version = "1.10.11" +version = "1.11.1" [[package]] category = "main" @@ -619,13 +619,13 @@ markdown = ["c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa", markupsafe = ["048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", "130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", "19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", "1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", "1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", "1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", "1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", "31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", "3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", "4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", "525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", "52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", "52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", "5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", "5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", "5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", "7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", "83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", "857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", "98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", "bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", "d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", "e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", "edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", "efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", "f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", "f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", "fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1"] mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"] mkdocs = ["17d34329aad75d5de604b9ed4e31df3a4d235afefdc46ce7b1964fddb2e1e939", "8cc8b38325456b9e942c981a209eaeb1e9f3f77b493ad755bfef889b9c8d356a"] -more-itertools = ["c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092", "c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e", "fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d"] -mypy = ["12d965c9c4e8a625673aec493162cf390e66de12ef176b1f4821ac00d55f3ab3", "38d5b5f835a81817dcc0af8d155bce4e9aefa03794fe32ed154d6612e83feafa"] +more-itertools = ["38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4", "c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc", "fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"] +mypy = ["986a7f97808a865405c5fd98fae5ebfa963c31520a56c783df159e9a81e41b3e", "cc5df73cc11d35655a8c364f45d07b13c8db82c000def4bd7721be13356533b4"] mypy-extensions = ["37e0e956f41369209a3d5f34580150bcacfabaa57b33a15c0b25f4b5725e0812", "b16cabe759f55e3409a7d231ebd2841378fb0c27a5d1994719e340e4f429ac3e"] nose = ["9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", "dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", "f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"] parse = ["c3cdf6206f22aeebfa00e5b954fcfea13d1b2dc271c75806b6025b94fb490939"] pefile = ["4c5b7e2de0c8cb6c504592167acf83115cbbde01fe4a507c16a1422850e86cd6"] -pluggy = ["447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095", "bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f"] +pluggy = ["8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616", "980710797ff6a041e9a73a5787804f848996ecaa6f8a1b1e08224a5894f2074a"] py = ["bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", "e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6"] pydocstyle = ["2258f9b0df68b97bf3a6c29003edc5238ff8879f1efb6f1999988d934e432bd8", "5741c85e408f9e0ddf873611085e819b809fca90b619f5fd7f34bd4959da3dd4", "ed79d4ec5e92655eccc21eb0c6cf512e69512b4a97d215ace46d17e4990f2039"] pygments = ["5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", "e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"] @@ -633,7 +633,7 @@ pyinstaller = ["a5a6e04a66abfcf8761e89a2ebad937919c6be33a7b8963e1a961b55cb35986b pylint = ["689de29ae747642ab230c6d37be2b969bf75663176658851f456619aacf27492", "771467c434d0d9f081741fec1d64dfb011ed26e65e12a28fe06ca2f61c4d556c"] pync = ["38b9e61735a3161f9211a5773c5f5ea698f36af4ff7f77fa03e8d1ff0caa117f"] pytest = ["3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec", "e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"] -pytest-cov = ["513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7", "e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762"] +pytest-cov = ["0ab664b25c6aa9716cbf203b17ddb301932383046082c081b9848a0edf5add33", "230ef817450ab0699c6cc3c9c8f7a829c34674456f2ed8df1fe1d39780f7c87f"] pytest-describe = ["bd6be131452b7822c872735ffe53ce3931b3b80cbbad1647c2b482cc9ef3d00e"] pytest-expecter = ["1c8e9ab98ddd576436b61a7ba61ea11cfa5a3fc6b00288ce9e91e9dd770daf19", "27c93dfe87e2f4d28c525031be68d3f89457e3315241d97ee15f7689544e0e37"] pytest-random = ["92f25db8c5d9ffc20d90b51997b914372d6955cb9cf1f6ead45b90514fc0eddd"] @@ -647,7 +647,7 @@ sniffer = ["e8a0daa4c51dff3d00482b45dc9b978159100a8d5a7df327c28ed96586559970", " snowballstemmer = ["919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", "9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89"] toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] tornado = ["0662d28b1ca9f67108c7e3b77afabfb9c7e87bde174fbda78186ecedc2499a9d", "4e5158d97583502a7e2739951553cbd88a72076f152b4b11b64b9a10c4c49409", "732e836008c708de2e89a31cb2fa6c0e5a70cb60492bee6f1ea1047500feaf7f", "8154ec22c450df4e06b35f131adc4f2f3a12ec85981a203301d310abf580500f", "8e9d728c4579682e837c92fdd98036bd5cdefa1da2aaf6acf26947e6dd0c01c5", "d4b3e5329f572f055b587efc57d29bd051589fb5a43ec8898c77a47ec2fa2bbb", "e5f2585afccbff22390cddac29849df463b252b711aa2ce7c5f3f342a5b3b444"] -typed-ast = ["0555eca1671ebe09eb5f2176723826f6f44cca5060502fea259de9b0e893ab53", "0ca96128ea66163aea13911c9b4b661cb345eb729a20be15c034271360fc7474", "16ccd06d614cf81b96de42a37679af12526ea25a208bce3da2d9226f44563868", "1e21ae7b49a3f744958ffad1737dfbdb43e1137503ccc59f4e32c4ac33b0bd1c", "37670c6fd857b5eb68aa5d193e14098354783b5138de482afa401cc2644f5a7f", "46d84c8e3806619ece595aaf4f37743083f9454c9ea68a517f1daa05126daf1d", "5b972bbb3819ece283a67358103cc6671da3646397b06e7acea558444daf54b2", "6306ffa64922a7b58ee2e8d6f207813460ca5a90213b4a400c2e730375049246", "6cb25dc95078931ecbd6cbcc4178d1b8ae8f2b513ae9c3bd0b7f81c2191db4c6", "7e19d439fee23620dea6468d85bfe529b873dace39b7e5b0c82c7099681f8a22", "7f5cd83af6b3ca9757e1127d852f497d11c7b09b4716c355acfbebf783d028da", "81e885a713e06faeef37223a5b1167615db87f947ecc73f815b9d1bbd6b585be", "94af325c9fe354019a29f9016277c547ad5d8a2d98a02806f27a7436b2da6735", "b1e5445c6075f509d5764b84ce641a1535748801253b97f3b7ea9d948a22853a", "cb061a959fec9a514d243831c514b51ccb940b58a5ce572a4e209810f2507dcf", "cc8d0b703d573cbabe0d51c9d68ab68df42a81409e4ed6af45a04a95484b96a5", "da0afa955865920edb146926455ec49da20965389982f91e926389666f5cf86a", "dc76738331d61818ce0b90647aedde17bbba3d3f9e969d83c1d9087b4f978862", "e7ec9a1445d27dbd0446568035f7106fa899a36f55e52ade28020f7b3845180d", "f741ba03feb480061ab91a465d1a3ed2d40b52822ada5b4017770dfcb88f839f", "fe800a58547dd424cd286b7270b967b5b3316b993d86453ede184a17b5a6b17d"] +typed-ast = ["023625bfa9359e29bd6e24cac2a4503495b49761d48a5f1e38333fc4ac4d93fe", "07591f7a5fdff50e2e566c4c1e9df545c75d21e27d98d18cb405727ed0ef329c", "153e526b0f4ffbfada72d0bb5ffe8574ba02803d2f3a9c605c8cf99dfedd72a2", "3ad2bdcd46a4a1518d7376e9f5016d17718a9ed3c6a3f09203d832f6c165de4a", "3ea98c84df53ada97ee1c5159bb3bc784bd734231235a1ede14c8ae0775049f7", "51a7141ccd076fa561af107cfb7a8b6d06a008d92451a1ac7e73149d18e9a827", "52c93cd10e6c24e7ac97e8615da9f224fd75c61770515cb323316c30830ddb33", "6344c84baeda3d7b33e157f0b292e4dd53d05ddb57a63f738178c01cac4635c9", "64699ca1b3bd5070bdeb043e6d43bc1d0cebe08008548f4a6bee782b0ecce032", "74903f2e56bbffe29282ef8a5487d207d10be0f8513b41aff787d954a4cf91c9", "7891710dba83c29ee2bd51ecaa82f60f6bede40271af781110c08be134207bf2", "91976c56224e26c256a0de0f76d2004ab885a29423737684b4f7ebdd2f46dde2", "9bad678a576ecc71f25eba9f1e3fd8d01c28c12a2834850b458428b3e855f062", "b4726339a4c180a8b6ad9d8b50d2b6dc247e1b79b38fe2290549c98e82e4fd15", "ba36f6aa3f8933edf94ea35826daf92cbb3ec248b89eccdc053d4a815d285357", "bbc96bde544fd19e9ef168e4dfa5c3dfe704bfa78128fa76f361d64d6b0f731a", "c0c927f1e44469056f7f2dada266c79b577da378bbde3f6d2ada726d131e4824", "c0f9a3708008aa59f560fa1bd22385e05b79b8e38e0721a15a8402b089243442", "f0bf6f36ff9c5643004171f11d2fdc745aa3953c5aacf2536a0685db9ceb3fb1", "f5be39a0146be663cbf210a4d95c3c58b2d7df7b043c9047c5448e358f0550a2", "fcd198bf19d9213e5cbf2cde2b9ef20a9856e716f76f9476157f90ae6de06cc6"] urllib3 = ["61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", "de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"] -wrapt = ["d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"] +wrapt = ["4aea003270831cceb8a90ff27c4031da6ead7ec1886023b80ce0dfe0adf61533"] yorm = ["863674ad8e1cfe5b8aa42e333039c0f54d591bb0d28ff9d4299b8109a02239f9", "aa540ccb087a9c3a8eac385073a2da1c5362591b45dec7a9a2cb212e898d9f84"] From 23335655d59aeeebae77e3582ceb134acf47cfe5 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Tue, 22 Jan 2019 10:40:03 -0500 Subject: [PATCH 45/49] Update mkdocs edit link --- README.md | 18 +++++++++--------- mkdocs.yml | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e6b890be..89e6cd90 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Overview +## Overview GitMan is a language-agnostic dependency manager using Git. It aims to serve as a submodules replacement and provides advanced options for managing versions of nested Git repositories. @@ -11,14 +11,14 @@ GitMan is a language-agnostic dependency manager using Git. It aims to serve as [![PyPI Version](https://img.shields.io/pypi/v/GitMan.svg)](https://pypi.org/project/GitMan) [![PyPI License](https://img.shields.io/pypi/l/GitMan.svg)](https://pypi.org/project/GitMan) -# Setup +## Setup -## Requirements +### Requirements * Python 3.6+ * Git 2.8+ (with [stored credentials](http://gitman.readthedocs.io/en/latest/setup/git/)) -## Installation +### Installation Install this tool globally: @@ -32,7 +32,7 @@ or add it to your [Poetry](https://poetry.eustace.io/) project: $ poetry add gitman ``` -## Configuration +### Configuration Generate a sample config file: @@ -70,7 +70,7 @@ Ignore the dependency storage location: $ echo vendor/gitman >> .gitignore ``` -# Usage +## Usage See the available commands: @@ -78,7 +78,7 @@ See the available commands: $ gitman --help ``` -## Updating Dependencies +### Updating Dependencies Get the latest versions of all dependencies: @@ -102,7 +102,7 @@ where `rev` can be: * a branch: `master` * a `rev-parse` date: `'develop@{2015-06-18 10:30:59}'` -## Restoring Previous Versions +### Restoring Previous Versions Display the specific revisions that are currently installed: @@ -116,7 +116,7 @@ Reinstall these specific versions at a later time: $ gitman install ``` -## Deleting Dependencies +### Deleting Dependencies Remove all installed dependencies: diff --git a/mkdocs.yml b/mkdocs.yml index 568530a6..81dab417 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,7 +1,9 @@ site_name: GitMan site_description: A language-agnostic dependency manager using Git. site_author: Jace Browning + repo_url: https://github.com/jacebrowning/gitman +edit_uri: https://github.com/jacebrowning/datafiles/edit/develop/docs theme: readthedocs From 192a333f57c79071c9d500cdc6ba83d9bf24cc03 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Tue, 22 Jan 2019 10:57:00 -0500 Subject: [PATCH 46/49] Fix typo --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 81dab417..66eb0775 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,7 +3,7 @@ site_description: A language-agnostic dependency manager using Git. site_author: Jace Browning repo_url: https://github.com/jacebrowning/gitman -edit_uri: https://github.com/jacebrowning/datafiles/edit/develop/docs +edit_uri: https://github.com/jacebrowning/gitman/edit/develop/docs theme: readthedocs From 08579c2805a70344d67b4c6fda66914a2982e091 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Sat, 26 Jan 2019 15:56:55 -0500 Subject: [PATCH 47/49] Fix indentation after locking --- gitman/models/config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gitman/models/config.py b/gitman/models/config.py index 93b384f6..945e07fe 100644 --- a/gitman/models/config.py +++ b/gitman/models/config.py @@ -190,6 +190,8 @@ def lock_dependencies(self, *names, obey_existing=True, skip_changes=False): if count: self.save() + common.dedent() + return count def uninstall_dependencies(self): From f250d811f9695dade9ff8b380d5969c05d8bb3a0 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Sat, 26 Jan 2019 15:58:27 -0500 Subject: [PATCH 48/49] Bump version to 1.6 --- CHANGELOG.md | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dadfb837..17b32c65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ -# 1.6 (unreleased) +# 1.6 (2019-01-26) - Added `git svn` support. (@daniel-brosche) - Added `$GITMAN_CACHE_DISABLE` to disable repository mirrors. (@daniel-brosche) -- Added `--skip-changes` option to skip changed dependencies on install or update command +- Added `--skip-changes` option to skip changed dependencies on install or update command. (@daniel-brosche) - **BREAKING**: Dropped support for Python 3.5. # 1.5 (2018-09-08) diff --git a/pyproject.toml b/pyproject.toml index cb37d13b..967d0242 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "gitman" -version = "1.6a4" +version = "1.6" description = "A language-agnostic dependency manager using Git." license = "MIT" From 1a492cdc9ee88cd99e843e22eadef2cefc99529c Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Sat, 26 Jan 2019 16:02:01 -0500 Subject: [PATCH 49/49] Add workaround for https://github.com/rtfd/readthedocs.org/issues/5090 --- Makefile | 6 +++++- docs/requirements.txt | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 docs/requirements.txt diff --git a/Makefile b/Makefile index aa87433f..cd9953bd 100644 --- a/Makefile +++ b/Makefile @@ -121,7 +121,7 @@ docs: mkdocs uml ## Generate documentation and UML .PHONY: mkdocs mkdocs: install $(MKDOCS_INDEX) -$(MKDOCS_INDEX): mkdocs.yml docs/*.md +$(MKDOCS_INDEX): docs/requirements.txt mkdocs.yml docs/*.md @ mkdir -p docs/about @ cd docs && ln -sf ../README.md index.md @ cd docs/about && ln -sf ../../CHANGELOG.md changelog.md @@ -129,6 +129,10 @@ $(MKDOCS_INDEX): mkdocs.yml docs/*.md @ cd docs/about && ln -sf ../../LICENSE.md license.md poetry run mkdocs build --clean --strict +# Workaround: https://github.com/rtfd/readthedocs.org/issues/5090 +docs/requirements.txt: poetry.lock + poetry run pip freeze | grep mkdocs > $@ + .PHONY: uml uml: install docs/*.png docs/*.png: $(MODULES) diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..591f7c09 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +mkdocs==1.0.4