diff options
-rw-r--r-- | morphlib/branchmanager_tests.py | 38 | ||||
-rw-r--r-- | morphlib/cachedrepo.py | 22 | ||||
-rw-r--r-- | morphlib/git.py | 71 | ||||
-rw-r--r-- | morphlib/gitdir.py | 93 | ||||
-rw-r--r-- | morphlib/gitdir_tests.py | 42 | ||||
-rw-r--r-- | morphlib/gitindex.py | 5 | ||||
-rw-r--r-- | morphlib/gitindex_tests.py | 9 | ||||
-rw-r--r-- | morphlib/localrepocache.py | 4 | ||||
-rw-r--r-- | morphlib/morphologyfinder_tests.py | 7 | ||||
-rw-r--r-- | morphlib/sysbranchdir.py | 6 | ||||
-rw-r--r-- | morphlib/sysbranchdir_tests.py | 13 |
11 files changed, 171 insertions, 139 deletions
diff --git a/morphlib/branchmanager_tests.py b/morphlib/branchmanager_tests.py index a7988c96..cf3be73c 100644 --- a/morphlib/branchmanager_tests.py +++ b/morphlib/branchmanager_tests.py @@ -1,4 +1,4 @@ -# Copyright (C) 2013 Codethink Limited +# Copyright (C) 2013-2014 Codethink Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -35,13 +35,13 @@ class LocalRefManagerTests(unittest.TestCase): gd = morphlib.gitdir.init(dirname) with open(os.path.join(dirname, 'foo'), 'w') as f: f.write('dummy text\n') - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Initial commit']) - gd._runcmd(['git', 'checkout', '-b', 'dev-branch']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Initial commit') + morphlib.git.gitcmd(gd._runcmd, 'checkout', '-b', 'dev-branch') with open(os.path.join(dirname, 'foo'), 'w') as f: f.write('updated text\n') - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Second commit']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Second commit') self.repos.append(gd) def tearDown(self): @@ -245,18 +245,19 @@ class RemoteRefManagerTests(unittest.TestCase): self.sgd = morphlib.gitdir.init(self.source) with open(os.path.join(self.source, 'foo'), 'w') as f: f.write('dummy text\n') - self.sgd._runcmd(['git', 'add', '.']) - self.sgd._runcmd(['git', 'commit', '-m', 'Initial commit']) - self.sgd._runcmd(['git', 'checkout', '-b', 'dev-branch']) + morphlib.git.gitcmd(self.sgd._runcmd, 'add', '.') + morphlib.git.gitcmd(self.sgd._runcmd, 'commit', '-m', 'Initial commit') + morphlib.git.gitcmd(self.sgd._runcmd, 'checkout', '-b', 'dev-branch') with open(os.path.join(self.source, 'foo'), 'w') as f: f.write('updated text\n') - self.sgd._runcmd(['git', 'add', '.']) - self.sgd._runcmd(['git', 'commit', '-m', 'Second commit']) - self.sgd._runcmd(['git', 'checkout', '--orphan', 'no-ff']) + morphlib.git.gitcmd(self.sgd._runcmd, 'add', '.') + morphlib.git.gitcmd(self.sgd._runcmd, 'commit', '-m', 'Second commit') + morphlib.git.gitcmd(self.sgd._runcmd, 'checkout', '--orphan', 'no-ff') with open(os.path.join(self.source, 'foo'), 'w') as f: f.write('parallel dimension text\n') - self.sgd._runcmd(['git', 'add', '.']) - self.sgd._runcmd(['git', 'commit', '-m', 'Non-fast-forward commit']) + morphlib.git.gitcmd(self.sgd._runcmd, 'add', '.') + morphlib.git.gitcmd(self.sgd._runcmd, 'commit', '-m', + 'Non-fast-forward commit') self.remotes = [] for i in xrange(self.TARGET_COUNT): @@ -264,11 +265,12 @@ class RemoteRefManagerTests(unittest.TestCase): dirname = os.path.join(self.tempdir, name) # Allow deleting HEAD - cliapp.runcmd(['git', 'init', '--bare', dirname]) + morphlib.git.gitcmd(cliapp.runcmd, 'init', '--bare', dirname) gd = morphlib.gitdir.GitDirectory(dirname) gd.set_config('receive.denyDeleteCurrent', 'warn') - self.sgd._runcmd(['git', 'remote', 'add', name, dirname]) + morphlib.git.gitcmd(self.sgd._runcmd, 'remote', 'add', + name, dirname) self.remotes.append((name, dirname, gd)) def tearDown(self): @@ -276,8 +278,8 @@ class RemoteRefManagerTests(unittest.TestCase): @staticmethod def list_refs(gd): - out = gd._runcmd(['git', 'for-each-ref', - '--format=%(refname)%00%(objectname)%00']) + out = morphlib.git.gitcmd(gd._runcmd, 'for-each-ref', + '--format=%(refname)%00%(objectname)%00') return dict(line.split('\0') for line in out.strip('\0\n').split('\0\n') if line) diff --git a/morphlib/cachedrepo.py b/morphlib/cachedrepo.py index 88ceed48..2fc7cfa5 100644 --- a/morphlib/cachedrepo.py +++ b/morphlib/cachedrepo.py @@ -260,20 +260,21 @@ class CachedRepo(object): return self.app.runcmd(*args, **kwargs) def _rev_parse(self, ref): # pragma: no cover - return self._runcmd( - ['git', 'rev-parse', '--verify', '%s^{commit}' % ref])[0:40] + return morphlib.git.gitcmd(self._runcmd, 'rev-parse', '--verify', + '%s^{commit}' % ref)[0:40] def _show_tree_hash(self, absref): # pragma: no cover - return self._runcmd( - ['git', 'rev-parse', '--verify', '%s^{tree}' % absref]).strip() + return morphlib.git.gitcmd(self._runcmd, 'rev-parse', '--verify', + '%s^{tree}' % absref).strip() def _ls_tree(self, ref): # pragma: no cover - result = self._runcmd(['git', 'ls-tree', '--name-only', ref]) + result = morphlib.git.gitcmd(self._runcmd, 'ls-tree', + '--name-only', ref) return result.split('\n') def _cat_file(self, ref, filename): # pragma: no cover - return self._runcmd(['git', 'cat-file', 'blob', - '%s:%s' % (ref, filename)]) + return morphlib.git.gitcmd(self._runcmd, 'cat-file', 'blob', + '%s:%s' % (ref, filename)) def _clone_into(self, target_dir, ref): #pragma: no cover '''Actually perform the clone''' @@ -297,10 +298,11 @@ class CachedRepo(object): def _update(self): # pragma: no cover try: - self._runcmd(['git', 'remote', 'update', 'origin', '--prune']) + morphlib.git.gitcmd(self._runcmd, 'remote', 'update', + 'origin', '--prune') except cliapp.AppException, ae: - self._runcmd(['git', 'remote', 'prune', 'origin']) - self._runcmd(['git', 'remote', 'update', 'origin']) + morphlib.git.gitcmd(self._runcmd, 'remote', 'prune', 'origin') + morphlib.git.gitcmd(self._runcmd, 'remote', 'update', 'origin') def __str__(self): # pragma: no cover return self.url diff --git a/morphlib/git.py b/morphlib/git.py index ccd06323..deb72eb6 100644 --- a/morphlib/git.py +++ b/morphlib/git.py @@ -81,9 +81,9 @@ class Submodules(object): def _read_gitmodules_file(self): try: # try to read the .gitmodules file from the repo/ref - content = self.app.runcmd( - ['git', 'cat-file', 'blob', '%s:.gitmodules' % self.ref], - cwd=self.repo, ignore_fail=True) + content = gitcmd(self.app.runcmd, 'cat-file', 'blob', + '%s:.gitmodules' % self.ref, cwd=self.repo, + ignore_fail=True) # drop indentation in sections, as RawConfigParser cannot handle it return '\n'.join([line.strip() for line in content.splitlines()]) @@ -105,8 +105,8 @@ class Submodules(object): try: # list objects in the parent repo tree to find the commit # object that corresponds to the submodule - commit = self.app.runcmd(['git', 'ls-tree', self.ref, - submodule.name], cwd=self.repo) + commit = gitcmd(self.app.runcmd, 'ls-tree', self.ref, + submodule.name, cwd=self.repo) # read the commit hash from the output fields = commit.split() @@ -149,15 +149,13 @@ def update_submodules(app, repo_dir): # pragma: no cover if os.path.exists(os.path.join(repo_dir, '.gitmodules')): resolver = morphlib.repoaliasresolver.RepoAliasResolver( app.settings['repo-alias']) - app.runcmd(['git', 'submodule', 'init'], cwd=repo_dir) + gitcmd(app.runcmd, 'submodule', 'init', cwd=repo_dir) submodules = Submodules(app, repo_dir, 'HEAD') submodules.load() for submodule in submodules: - app.runcmd(['git', 'config', - 'submodule.%s.url' % submodule.name, - resolver.pull_url(submodule.url)], - cwd=repo_dir) - app.runcmd(['git', 'submodule', 'update'], cwd=repo_dir) + gitcmd(app.runcmd, 'config', 'submodule.%s.url' % submodule.name, + resolver.pull_url(submodule.url), cwd=repo_dir) + gitcmd(app.runcmd, 'submodule', 'update', cwd=repo_dir) class ConfigNotSetException(cliapp.AppException): @@ -217,7 +215,7 @@ def check_config_set(runcmd, keys, cwd='.'): found = {} for key in keys: try: - value = runcmd(['git', 'config', key], cwd=cwd, + value = gitcmd(runcmd, 'config', key, cwd=cwd, print_command=False).strip() found[key] = value except cliapp.AppException: @@ -229,7 +227,7 @@ def check_config_set(runcmd, keys, cwd='.'): def set_remote(runcmd, gitdir, name, url): '''Set remote with name 'name' use a given url at gitdir''' - return runcmd(['git', 'remote', 'set-url', name, url], cwd=gitdir) + return gitcmd(runcmd, 'remote', 'set-url', name, url, cwd=gitdir) def copy_repository(runcmd, repo, destdir, is_mirror=True): @@ -246,16 +244,16 @@ def copy_repository(runcmd, repo, destdir, is_mirror=True): runcmd(['cp', '-a', repo, os.path.join(destdir, '.git')]) # core.bare should be false so that git believes work trees are possible - runcmd(['git', 'config', 'core.bare', 'false'], cwd=destdir) + gitcmd(runcmd, 'config', 'core.bare', 'false', cwd=destdir) # we do not want the origin remote to behave as a mirror for pulls - runcmd(['git', 'config', '--unset', 'remote.origin.mirror'], cwd=destdir) + gitcmd(runcmd, 'config', '--unset', 'remote.origin.mirror', cwd=destdir) # we want a traditional refs/heads -> refs/remotes/origin ref mapping - runcmd(['git', 'config', 'remote.origin.fetch', - '+refs/heads/*:refs/remotes/origin/*'], cwd=destdir) + gitcmd(runcmd, 'config', 'remote.origin.fetch', + '+refs/heads/*:refs/remotes/origin/*', cwd=destdir) # set the origin url to the cached repo so that we can quickly clean up - runcmd(['git', 'config', 'remote.origin.url', repo], cwd=destdir) + gitcmd(runcmd, 'config', 'remote.origin.url', repo, cwd=destdir) # by packing the refs, we can then edit then en-masse easily - runcmd(['git', 'pack-refs', '--all', '--prune'], cwd=destdir) + gitcmd(runcmd, 'pack-refs', '--all', '--prune', cwd=destdir) # turn refs/heads/* into refs/remotes/origin/* in the packed refs # so that the new copy behaves more like a traditional clone. logging.debug("Adjusting packed refs for %s" % destdir) @@ -273,12 +271,12 @@ def copy_repository(runcmd, repo, destdir, is_mirror=True): refline = "%s %s" % (sha, ref) ref_fh.write("%s\n" % (refline)) # Finally run a remote update to clear up the refs ready for use. - runcmd(['git', 'remote', 'update', 'origin', '--prune'], cwd=destdir) + gitcmd(runcmd, 'remote', 'update', 'origin', '--prune', cwd=destdir) def checkout_ref(runcmd, gitdir, ref): '''Checks out a specific ref/SHA1 in a git working tree.''' - runcmd(['git', 'checkout', ref], cwd=gitdir) + gitcmd(runcmd, 'checkout', ref, cwd=gitdir) gd = morphlib.gitdir.GitDirectory(gitdir) if gd.has_fat(): gd.fat_init() @@ -288,8 +286,8 @@ def checkout_ref(runcmd, gitdir, ref): def index_has_changes(runcmd, gitdir): '''Returns True if there are no staged changes to commit''' try: - runcmd(['git', 'diff-index', '--cached', '--quiet', - '--ignore-submodules', 'HEAD'], cwd=gitdir) + gitcmd(runcmd, 'diff-index', '--cached', '--quiet', + '--ignore-submodules', 'HEAD', cwd=gitdir) except cliapp.AppException: return True return False @@ -298,20 +296,20 @@ def index_has_changes(runcmd, gitdir): def reset_workdir(runcmd, gitdir): '''Removes any differences between the current commit ''' '''and the status of the working directory''' - runcmd(['git', 'clean', '-fxd'], cwd=gitdir) - runcmd(['git', 'reset', '--hard', 'HEAD'], cwd=gitdir) + gitcmd(runcmd, 'clean', '-fxd', cwd=gitdir) + gitcmd(runcmd, 'reset', '--hard', 'HEAD', cwd=gitdir) def clone_into(runcmd, srcpath, targetpath, ref=None): '''Clones a repo in srcpath into targetpath, optionally directly at ref.''' if ref is None: - runcmd(['git', 'clone', srcpath, targetpath]) + gitcmd(runcmd, 'clone', srcpath, targetpath) elif is_valid_sha1(ref): - runcmd(['git', 'clone', srcpath, targetpath]) - runcmd(['git', 'checkout', ref], cwd=targetpath) + gitcmd(runcmd, 'clone', srcpath, targetpath) + gitcmd(runcmd, 'checkout', ref) else: - runcmd(['git', 'clone', '-b', ref, srcpath, targetpath]) + gitcmd(runcmd, 'clone', '-b', ref, srcpath, targetpath) gd = morphlib.gitdir.GitDirectory(targetpath) if gd.has_fat(): gd.fat_init() @@ -324,4 +322,17 @@ def is_valid_sha1(ref): def rev_parse(runcmd, gitdir, ref): '''Find the sha1 for the given ref''' - return runcmd(['git', 'rev-parse', '--verify', ref], cwd=gitdir)[0:40] + return gitcmd(runcmd, 'rev-parse', '--verify', ref, cwd=gitdir)[0:40] + + +def gitcmd(runcmd, *args, **kwargs): + '''Run git commands safely''' + if 'env' not in kwargs: + kwargs['env'] = dict(os.environ) + # git replace means we can't trust that just the sha1 of the branch + # is enough to say what it contains, so we turn it off by setting + # the right flag in an environment variable. + kwargs['env']['GIT_NO_REPLACE_OBJECTS'] = '1' + cmdline = ['git'] + cmdline.extend(args) + return runcmd(cmdline, **kwargs) diff --git a/morphlib/gitdir.py b/morphlib/gitdir.py index 6b04b773..40ac643f 100644 --- a/morphlib/gitdir.py +++ b/morphlib/gitdir.py @@ -240,13 +240,14 @@ class Remote(object): def set_fetch_url(self, url): self.fetch_url = url if self.name is not None: - self.gd._runcmd(['git', 'remote', 'set-url', self.name, url]) + morphlib.git.gitcmd(self.gd._runcmd, 'remote', 'set-url', + self.name, url) def set_push_url(self, url): self.push_url = url if self.name is not None: - self.gd._runcmd(['git', 'remote', 'set-url', '--push', - self.name, url]) + morphlib.git.gitcmd(self.gd._runcmd, 'remote', 'set-url', + '--push', self.name, url) def _get_remote_url(self, remote_name, kind): # As distasteful as it is to parse the output of porcelain @@ -261,7 +262,7 @@ class Remote(object): # It is only possible to use git to get the push url by parsing # `git remote -v` or `git remote show -n <remote>`, and `git # remote -v` is easier to parse. - output = self.gd._runcmd(['git', 'remote', '-v']) + output = morphlib.git.gitcmd(self.gd._runcmd, 'remote', '-v') for line in output.splitlines(): words = line.split() if (len(words) == 3 and @@ -288,7 +289,8 @@ class Remote(object): yield sha1, refname def ls(self): # pragma: no cover - out = self.gd._runcmd(['git', 'ls-remote', self.get_fetch_url()]) + out = morphlib.git.gitcmd(self.gd._runcmd, 'ls-remote', + self.get_fetch_url()) return self._parse_ls_remote_output(out) @staticmethod @@ -320,10 +322,11 @@ class Remote(object): if not refspecs: raise NoRefspecsError(self) push_name = self.name or self.get_push_url() - cmdline = ['git', 'push', '--porcelain', push_name] + cmdline = ['push', '--porcelain', push_name] cmdline.extend(itertools.chain.from_iterable( rs.push_args for rs in refspecs)) - exit, out, err = self.gd._runcmd_unchecked(cmdline) + exit, out, err = morphlib.git.gitcmd(self.gd._runcmd_unchecked, + *cmdline) if exit != 0: raise PushFailureError(self, refspecs, exit, self._parse_push_output(out), err) @@ -332,9 +335,9 @@ class Remote(object): def pull(self, branch=None): # pragma: no cover if branch: repo = self.get_fetch_url() - ret = self.gd._runcmd(['git', 'pull', repo, branch]) + ret = morphlib.git.gitcmd(self.gd._runcmd, 'pull', repo, branch) else: - ret = self.gd._runcmd(['git', 'pull']) + ret = morphlib.git.gitcmd(self.gd._runcmd, 'pull') return ret @@ -374,7 +377,7 @@ class GitDirectory(object): def checkout(self, branch_name): # pragma: no cover '''Check out a git branch.''' - self._runcmd(['git', 'checkout', branch_name]) + morphlib.git.gitcmd(self._runcmd, 'checkout', branch_name) if self.has_fat(): self.fat_init() self.fat_pull() @@ -388,10 +391,10 @@ class GitDirectory(object): ''' - argv = ['git', 'branch', new_branch_name] + argv = ['branch', new_branch_name] if base_ref is not None: argv.append(base_ref) - self._runcmd(argv) + morphlib.git.gitcmd(self._runcmd, *argv) def is_currently_checked_out(self, ref): # pragma: no cover '''Is ref currently checked out?''' @@ -399,12 +402,12 @@ class GitDirectory(object): # Try the ref name directly first. If that fails, prepend origin/ # to it. (FIXME: That's a kludge, and should be fixed.) try: - parsed_ref = self._runcmd(['git', 'rev-parse', ref]).strip() + parsed_ref = morphlib.git.gitcmd(self._runcmd, 'rev-parse', ref) except cliapp.AppException: - parsed_ref = self._runcmd( - ['git', 'rev-parse', 'origin/%s' % ref]).strip() - parsed_head = self._runcmd(['git', 'rev-parse', 'HEAD']).strip() - return parsed_ref == parsed_head + parsed_ref = morphlib.git.gitcmd(self._runcmd, 'rev-parse', + 'origin/%s' % ref) + parsed_head = morphlib.git.gitcmd(self._runcmd, 'rev-parse', 'HEAD') + return parsed_ref.strip() == parsed_head.strip() def get_file_from_ref(self, ref, filename): # pragma: no cover '''Get file contents from git by ref and filename. @@ -426,13 +429,13 @@ class GitDirectory(object): def get_blob_contents(self, blob_id): # pragma: no cover '''Get file contents from git by ID''' - return self._runcmd( - ['git', 'cat-file', 'blob', blob_id]) + return morphlib.git.gitcmd(self._runcmd, 'cat-file', 'blob', + blob_id) def get_commit_contents(self, commit_id): # pragma: no cover '''Get commit contents from git by ID''' - return self._runcmd( - ['git', 'cat-file', 'commit', commit_id]) + return morphlib.git.gitcmd(self._runcmd, 'cat-file', 'commit', + commit_id) def update_submodules(self, app): # pragma: no cover '''Change .gitmodules URLs, and checkout submodules.''' @@ -447,14 +450,14 @@ class GitDirectory(object): ''' - self._runcmd(['git', 'config', key, value]) + morphlib.git.gitcmd(self._runcmd, 'config', key, value) self._config[key] = value def get_config(self, key): '''Return value for a git repository configuration variable.''' if key not in self._config: - value = self._runcmd(['git', 'config', '-z', key]) + value = morphlib.git.gitcmd(self._runcmd, 'config', '-z', key) self._config[key] = value.rstrip('\0') return self._config[key] @@ -469,7 +472,7 @@ class GitDirectory(object): def update_remotes(self): # pragma: no cover '''Run "git remote update --prune".''' - self._runcmd(['git', 'remote', 'update', '--prune']) + morphlib.git.gitcmd(self._runcmd, 'remote', 'update', '--prune') def is_bare(self): '''Determine whether the repository has no work tree (is bare)''' @@ -494,14 +497,15 @@ class GitDirectory(object): def _rev_parse(self, ref): try: - return self._runcmd(['git', 'rev-parse', '--verify', ref]).strip() + return morphlib.git.gitcmd(self._runcmd, 'rev-parse', + '--verify', ref).strip() except cliapp.AppException as e: raise InvalidRefError(self, ref) def disambiguate_ref(self, ref): # pragma: no cover try: - out = self._runcmd(['git', 'rev-parse', '--symbolic-full-name', - ref]) + out = morphlib.git.gitcmd(self._runcmd, 'rev-parse', + '--symbolic-full-name', ref) return out.strip() except cliapp.AppException: # ref not found if ref.startswith('refs/heads/'): @@ -527,7 +531,8 @@ class GitDirectory(object): def _list_files_in_ref(self, ref): tree = self.resolve_ref_to_tree(ref) - output = self._runcmd(['git', 'ls-tree', '--name-only', '-rz', tree]) + output = morphlib.git.gitcmd(self._runcmd, 'ls-tree', + '--name-only', '-rz', tree) # ls-tree appends \0 instead of interspersing, so we need to # strip the trailing \0 before splitting paths = output.strip('\0').split('\0') @@ -548,13 +553,15 @@ class GitDirectory(object): if ref is None: filepath = os.path.join(self.dirname, filename.lstrip('/')) return os.path.islink(filepath) - tree_entry = self._runcmd(['git', 'ls-tree', ref, filename]) + tree_entry = morphlib.git.gitcmd(self._runcmd, 'ls-tree', ref, + filename) file_mode = tree_entry.split(' ', 1)[0] return file_mode == '120000' @property def HEAD(self): - output = self._runcmd(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) + output = morphlib.git.gitcmd(self._runcmd, 'rev-parse', + '--abbrev-ref', 'HEAD') return output.strip() def get_index(self, index_file=None): @@ -572,8 +579,8 @@ class GitDirectory(object): kwargs = {'feed_stdin': blob_contents} else: kwargs = {'stdin': blob_contents} - return self._runcmd(['git', 'hash-object', '-t', 'blob', - '-w', '--stdin'], **kwargs).strip() + return morphlib.git.gitcmd(self._runcmd, 'hash-object', '-t', 'blob', + '-w', '--stdin', **kwargs).strip() def commit_tree(self, tree, parent, message, **kwargs): '''Create a commit''' @@ -590,9 +597,9 @@ class GitDirectory(object): envname = 'GIT_%s_DATE' % who.upper() if argname in kwargs: env[envname] = kwargs[argname].isoformat() - return self._runcmd(['git', 'commit-tree', tree, - '-p', parent, '-m', message], - env=env).strip() + return morphlib.git.gitcmd(self._runcmd, 'commit-tree', tree, + '-p', parent, '-m', message, + env=env).strip() @staticmethod def _check_is_sha1(string): @@ -600,14 +607,14 @@ class GitDirectory(object): raise ExpectedSha1Error(string) def _update_ref(self, ref_args, message): - args = ['git', 'update-ref'] + args = ['update-ref'] # No test coverage, since while this functionality is useful, # morph does not need an API for inspecting the reflog, so # it existing purely to test ref updates is a tad overkill. if message is not None: # pragma: no cover args.extend(('-m', message)) args.extend(ref_args) - self._runcmd(args) + morphlib.git.gitcmd(self._runcmd, *args) def add_ref(self, ref, sha1, message=None): '''Create a ref called `ref` in the repository pointing to `sha1`. @@ -666,18 +673,18 @@ class GitDirectory(object): raise RefDeleteError(self, ref, old_sha1, e) def describe(self): - version = self._runcmd( - ['git', 'describe', '--always', '--dirty=-unreproducible']) + version = morphlib.git.gitcmd(self._runcmd, 'describe', + '--always', '--dirty=-unreproducible') return version.strip() def fat_init(self): # pragma: no cover - return self._runcmd(['git', 'fat', 'init']) + return morphlib.git.gitcmd(self._runcmd, 'fat', 'init') def fat_push(self): # pragma: no cover - return self._runcmd(['git', 'fat', 'push']) + return morphlib.git.gitcmd(self._runcmd, 'fat', 'push') def fat_pull(self): # pragma: no cover - return self._runcmd(['git', 'fat', 'pull']) + return morphlib.git.gitcmd(self._runcmd, 'fat', 'pull') def has_fat(self): # pragma: no cover return os.path.isfile(self.join_path('.gitfat')) @@ -692,7 +699,7 @@ class GitDirectory(object): def init(dirname): '''Initialise a new git repository.''' - cliapp.runcmd(['git', 'init'], cwd=dirname) + morphlib.git.gitcmd(cliapp.runcmd, 'init', cwd=dirname) gd = GitDirectory(dirname) return gd diff --git a/morphlib/gitdir_tests.py b/morphlib/gitdir_tests.py index b3b4a8ab..456e3716 100644 --- a/morphlib/gitdir_tests.py +++ b/morphlib/gitdir_tests.py @@ -71,12 +71,13 @@ class GitDirectoryContentsTests(unittest.TestCase): for fn in ('foo', 'bar.morph', 'baz.morph', 'quux'): with open(os.path.join(self.dirname, fn), "w") as f: f.write('dummy morphology text') - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Initial commit']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Initial commit') os.rename(os.path.join(self.dirname, 'foo'), os.path.join(self.dirname, 'foo.morph')) self.mirror = os.path.join(self.tempdir, 'mirror') - gd._runcmd(['git', 'clone', '--mirror', self.dirname, self.mirror]) + morphlib.git.gitcmd(gd._runcmd, 'clone', '--mirror', self.dirname, + self.mirror) def tearDown(self): shutil.rmtree(self.tempdir) @@ -209,10 +210,11 @@ class GitDirectoryContentsTests(unittest.TestCase): def test_describe(self): gd = morphlib.gitdir.GitDirectory(self.dirname) - gd._runcmd(['git', 'tag', '-a', '-m', 'Example', 'example', 'HEAD']) + morphlib.git.gitcmd(gd._runcmd, 'tag', '-a', '-m', 'Example', + 'example', 'HEAD') self.assertEqual(gd.describe(), 'example-unreproducible') - gd._runcmd(['git', 'reset', '--hard']) + morphlib.git.gitcmd(gd._runcmd, 'reset', '--hard') self.assertEqual(gd.describe(), 'example') @@ -227,10 +229,11 @@ class GitDirectoryFileTypeTests(unittest.TestCase): f.write('dummy morphology text') os.symlink('file', os.path.join(self.dirname, 'link')) os.symlink('no file', os.path.join(self.dirname, 'broken')) - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Initial commit']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Initial commit') self.mirror = os.path.join(self.tempdir, 'mirror') - gd._runcmd(['git', 'clone', '--mirror', self.dirname, self.mirror]) + morphlib.git.gitcmd(gd._runcmd, 'clone', '--mirror', self.dirname, + self.mirror) def tearDown(self): shutil.rmtree(self.tempdir) @@ -262,14 +265,14 @@ class GitDirectoryRefTwiddlingTests(unittest.TestCase): gd = morphlib.gitdir.init(self.dirname) with open(os.path.join(self.dirname, 'foo'), 'w') as f: f.write('dummy text\n') - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Initial commit']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Initial commit') # Add a second commit for update_ref test, so it has another # commit to roll back from with open(os.path.join(self.dirname, 'bar'), 'w') as f: f.write('dummy text\n') - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Second commit']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Second commit') def tearDown(self): shutil.rmtree(self.tempdir) @@ -347,7 +350,8 @@ class GitDirectoryRemoteConfigTests(unittest.TestCase): self.assertEqual(remote.get_fetch_url(), None) self.assertEqual(remote.get_push_url(), None) - gitdir._runcmd(['git', 'remote', 'add', 'origin', 'foobar']) + morphlib.git.gitcmd(gitdir._runcmd, 'remote', 'add', 'origin', + 'foobar') fetch_url = 'git://git.example.com/foo.git' push_url = 'ssh://git@git.example.com/foo.git' remote.set_fetch_url(fetch_url) @@ -424,15 +428,15 @@ class GitDirectoryRemotePushTests(unittest.TestCase): gd = morphlib.gitdir.init(self.dirname) with open(os.path.join(self.dirname, 'foo'), 'w') as f: f.write('dummy text\n') - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Initial commit']) - gd._runcmd(['git', 'checkout', '-b', 'foo']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Initial commit') + morphlib.git.gitcmd(gd._runcmd, 'checkout', '-b', 'foo') with open(os.path.join(self.dirname, 'foo'), 'w') as f: f.write('updated text\n') - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Second commit']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Second commit') self.mirror = os.path.join(self.tempdir, 'mirror') - gd._runcmd(['git', 'init', '--bare', self.mirror]) + morphlib.git.gitcmd(gd._runcmd, 'init', '--bare', self.mirror) def tearDown(self): shutil.rmtree(self.tempdir) diff --git a/morphlib/gitindex.py b/morphlib/gitindex.py index 6be4aacb..e22f6225 100644 --- a/morphlib/gitindex.py +++ b/morphlib/gitindex.py @@ -17,6 +17,7 @@ import collections +import os import morphlib @@ -47,9 +48,9 @@ class GitIndex(object): def _run_git(self, *args, **kwargs): if self._index_file is not None: - kwargs['env'] = kwargs.get('env', {}) + kwargs['env'] = kwargs.get('env', dict(os.environ)) kwargs['env']['GIT_INDEX_FILE'] = self._index_file - return self._gd._runcmd(['git'] + list(args), **kwargs) + return morphlib.git.gitcmd(self._gd._runcmd, *args, **kwargs) def _get_status(self): '''Return git status output in a Python useful format diff --git a/morphlib/gitindex_tests.py b/morphlib/gitindex_tests.py index 7a8953f2..32d40a8c 100644 --- a/morphlib/gitindex_tests.py +++ b/morphlib/gitindex_tests.py @@ -1,4 +1,4 @@ -# Copyright (C) 2013 Codethink Limited +# Copyright (C) 2013-2014 Codethink Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -33,10 +33,11 @@ class GitIndexTests(unittest.TestCase): gd = morphlib.gitdir.init(self.dirname) with open(os.path.join(self.dirname, 'foo'), 'w') as f: f.write('dummy text\n') - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Initial commit']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Initial commit') self.mirror = os.path.join(self.tempdir, 'mirror') - gd._runcmd(['git', 'clone', '--mirror', self.dirname, self.mirror]) + morphlib.git.gitcmd(gd._runcmd, 'clone', '--mirror', self.dirname, + self.mirror) def tearDown(self): shutil.rmtree(self.tempdir) diff --git a/morphlib/localrepocache.py b/morphlib/localrepocache.py index 9c20e4bc..8d2030c4 100644 --- a/morphlib/localrepocache.py +++ b/morphlib/localrepocache.py @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2013 Codethink Limited +# Copyright (C) 2012-2014 Codethink Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -110,7 +110,7 @@ class LocalRepoCache(object): ''' - self._app.runcmd(['git'] + args, cwd=cwd) + morphlib.git.gitcmd(self._app.runcmd, *args, cwd=cwd) def _fetch(self, url, path): # pragma: no cover '''Fetch contents of url into a file. diff --git a/morphlib/morphologyfinder_tests.py b/morphlib/morphologyfinder_tests.py index b07b2613..67161f9b 100644 --- a/morphlib/morphologyfinder_tests.py +++ b/morphlib/morphologyfinder_tests.py @@ -34,8 +34,8 @@ class MorphologyFinderTests(unittest.TestCase): for fn in ('foo', 'bar.morph', 'baz.morph', 'quux'): with open(os.path.join(self.dirname, fn), "w") as f: f.write('dummy morphology text') - gd._runcmd(['git', 'add', '.']) - gd._runcmd(['git', 'commit', '-m', 'Initial commit']) + morphlib.git.gitcmd(gd._runcmd, 'add', '.') + morphlib.git.gitcmd(gd._runcmd, 'commit', '-m', 'Initial commit') # Changes for difference between commited and work tree newmorphpath = os.path.join(self.dirname, 'foo.morph') @@ -45,7 +45,8 @@ class MorphologyFinderTests(unittest.TestCase): # Changes for bare repository self.mirror = os.path.join(self.tempdir, 'mirror') - gd._runcmd(['git', 'clone', '--mirror', self.dirname, self.mirror]) + morphlib.git.gitcmd(gd._runcmd, 'clone', '--mirror', self.dirname, + self.mirror) def tearDown(self): shutil.rmtree(self.tempdir) diff --git a/morphlib/sysbranchdir.py b/morphlib/sysbranchdir.py index 19fba695..4351c6b3 100644 --- a/morphlib/sysbranchdir.py +++ b/morphlib/sysbranchdir.py @@ -61,11 +61,13 @@ class SystemBranchDirectory(object): def set_config(self, key, value): '''Set a configuration key/value pair.''' - cliapp.runcmd(['git', 'config', '-f', self._config_path, key, value]) + morphlib.git.gitcmd(cliapp.runcmd, 'config', '-f', + self._config_path, key, value) def get_config(self, key): '''Get a configuration value for a given key.''' - value = cliapp.runcmd(['git', 'config', '-f', self._config_path, key]) + value = morphlib.git.gitcmd(cliapp.runcmd, 'config', '-f', + self._config_path, key) return value.strip() def _find_git_directory(self, repo_url): diff --git a/morphlib/sysbranchdir_tests.py b/morphlib/sysbranchdir_tests.py index 8b40f69c..1aca54e6 100644 --- a/morphlib/sysbranchdir_tests.py +++ b/morphlib/sysbranchdir_tests.py @@ -50,16 +50,17 @@ class SystemBranchDirectoryTests(unittest.TestCase): self.path = path os.mkdir(self.path) - cliapp.runcmd(['git', 'init', self.path]) + morphlib.git.gitcmd(cliapp.runcmd, 'init', self.path) with open(os.path.join(self.path, 'filename'), 'w') as f: f.write('this is a file\n') - cliapp.runcmd(['git', 'add', 'filename'], cwd=self.path) - cliapp.runcmd( - ['git', 'commit', '-m', 'initial'], cwd=self.path) + morphlib.git.gitcmd(cliapp.runcmd, 'add', 'filename', + cwd=self.path) + morphlib.git.gitcmd(cliapp.runcmd, 'commit', '-m', 'initial', + cwd=self.path) def clone_checkout(self, ref, target_dir): - cliapp.runcmd( - ['git', 'clone', '-b', ref, self.path, target_dir]) + morphlib.git.gitcmd(cliapp.runcmd, 'clone', '-b', ref, + self.path, target_dir) subdir = tempfile.mkdtemp(dir=self.tempdir) path = os.path.join(subdir, 'foo') |