Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1067)

Unified Diff: infra/services/gnumbd/support/git.py

Issue 355153002: Refactor infra git libs and testing. (Closed) Base URL: https://chromium.googlesource.com/infra/infra@fake_testing_support
Patch Set: Change config ref to have a sandard naming scheme Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: infra/services/gnumbd/support/git.py
diff --git a/infra/services/gnumbd/support/git.py b/infra/services/gnumbd/support/git.py
deleted file mode 100644
index b337ac20c4a65e682839ac350a1f56d5783eb255..0000000000000000000000000000000000000000
--- a/infra/services/gnumbd/support/git.py
+++ /dev/null
@@ -1,270 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-import collections
-import fnmatch
-import logging
-import os
-import subprocess
-import sys
-import tempfile
-import urlparse
-
-from infra.services.gnumbd.support.util import (
- cached_property, CalledProcessError)
-
-from infra.services.gnumbd.support.data import CommitData
-
-LOGGER = logging.getLogger(__name__)
-
-
-class _Invalid(object):
- def __call__(self, *_args, **_kwargs):
- return self
-
- def __getattr__(self, _key):
- return self
-
- def __eq__(self, _other):
- return False
-
- def __ne__(self, _other): # pylint: disable=R0201
- return True
-
-INVALID = _Invalid()
-
-
-class Repo(object):
- """Represents a remote git repo.
-
- Manages the (bare) on-disk mirror of the remote repo.
- """
- MAX_CACHE_SIZE = 1024
-
- def __init__(self, url):
- self.dry_run = False
- self.repos_dir = None
-
- self._url = url
- self._repo_path = None
- self._commit_cache = collections.OrderedDict()
- self._log = LOGGER.getChild('Repo')
-
- def reify(self):
- """Ensures the local mirror of this Repo exists."""
- assert self.repos_dir is not None
- parsed = urlparse.urlparse(self._url)
- norm_url = parsed.netloc + parsed.path
- if norm_url.endswith('.git'):
- norm_url = norm_url[:-len('.git')]
- folder = norm_url.replace('-', '--').replace('/', '-').lower()
-
- rpath = os.path.abspath(os.path.join(self.repos_dir, folder))
- if not os.path.isdir(rpath):
- self._log.debug('initializing %r -> %r', self, rpath)
- name = tempfile.mkdtemp(dir=self.repos_dir)
- self.run('clone', '--mirror', self._url, os.path.basename(name),
- stdout=sys.stdout, stderr=sys.stderr, cwd=self.repos_dir)
- os.rename(os.path.join(self.repos_dir, name),
- os.path.join(self.repos_dir, folder))
- else:
- self._log.debug('%r already initialized', self)
- self._repo_path = rpath
-
- # This causes pushes to fail, so unset it.
- self.run('config', '--unset', 'remote.origin.mirror', ok_ret={0, 5})
-
- # Representation
- def __repr__(self):
- return 'Repo({_url!r})'.format(**self.__dict__)
-
- # Methods
- def get_commit(self, hsh):
- """Creates a new |Commit| object for this |Repo|.
-
- Uses a very basic LRU cache for commit objects, keeping up to
- |MAX_CACHE_SIZE| before eviction. This cuts down on the number of redundant
- git commands by > 50%, and allows expensive cached_property's to remain
- for the life of the process.
- """
- if hsh in self._commit_cache:
- self._log.debug('Hit %s', hsh)
- r = self._commit_cache.pop(hsh)
- else:
- self._log.debug('Miss %s', hsh)
- if len(self._commit_cache) >= self.MAX_CACHE_SIZE:
- self._commit_cache.popitem(last=False)
- r = Commit(self, hsh)
-
- self._commit_cache[hsh] = r
- return r
-
- def refglob(self, globstring):
- """Yield every Ref in this repo which matches |globstring|."""
- for _, ref in (l.split() for l in self.run('show-ref').splitlines()):
- if fnmatch.fnmatch(ref, globstring):
- yield Ref(self, ref)
-
- def run(self, *args, **kwargs):
- """Yet-another-git-subprocess-wrapper.
-
- Args: argv tokens. 'git' is always argv[0]
-
- Kwargs:
- indata - String data to feed to communicate()
- ok_ret - A set() of valid return codes. Defaults to {0}.
- ... - passes through to subprocess.Popen()
- """
- if args[0] == 'push' and self.dry_run:
- self._log.warn('DRY-RUN: Would have pushed %r', args[1:])
- return
-
- if not 'cwd' in kwargs:
- assert self._repo_path is not None
- kwargs.setdefault('cwd', self._repo_path)
-
- kwargs.setdefault('stderr', subprocess.PIPE)
- kwargs.setdefault('stdout', subprocess.PIPE)
- indata = kwargs.pop('indata', None)
- if indata:
- assert 'stdin' not in kwargs
- kwargs['stdin'] = subprocess.PIPE
- ok_ret = kwargs.pop('ok_ret', {0})
- cmd = ('git',) + args
-
- self._log.debug('Running %r', cmd)
- process = subprocess.Popen(cmd, **kwargs)
- output, errout = process.communicate(indata)
- retcode = process.poll()
- if retcode not in ok_ret:
- raise CalledProcessError(retcode, cmd, output, errout)
-
- if errout:
- sys.stderr.write(errout)
- return output
-
- def intern(self, data, typ='blob'):
- return self.run(
- 'hash-object', '-w', '-t', typ, '--stdin', indata=str(data)).strip()
-
-
-class Commit(object):
- """Represents the identity of a commit in a git repo."""
-
- def __init__(self, repo, hsh):
- """
- @type repo: Repo
- """
- assert CommitData.HASH_RE.match(hsh)
- self._repo = repo
- self._hsh = hsh
-
- # Comparison & Representation
- def __eq__(self, other):
- return (self is other) or (
- isinstance(other, Commit) and (
- self.hsh == other.hsh
- )
- )
-
- def __ne__(self, other):
- return not (self == other)
-
- def __repr__(self):
- return 'Commit({_repo!r}, {_hsh!r})'.format(**self.__dict__)
-
- # Accessors
- # pylint: disable=W0212
- repo = property(lambda self: self._repo)
- hsh = property(lambda self: self._hsh)
-
- # Properties
- @cached_property
- def data(self):
- """Get a structured data representation of this commit."""
- try:
- raw_data = self.repo.run('cat-file', 'commit', self.hsh)
- except CalledProcessError:
- return INVALID
- return CommitData.from_raw(raw_data)
-
- @cached_property
- def parent(self):
- """Get the corresponding parent Commit() for this Commit(), or None.
-
- If self has more than one parent, this raises an Exception.
- """
- parents = self.data.parents
- if len(parents) > 1:
- LOGGER.error('Commit %r has more than one parent!', self.hsh)
- return INVALID
- return self.repo.get_commit(parents[0]) if parents else None
-
- # Methods
- def alter(self, **kwargs):
- """Get a new Commit which is the same as this one, except for alterations
- specified by kwargs.
-
- This will intern the new Commit object into the Repo.
- """
- return self.repo.get_commit(
- self.repo.intern(self.data.alter(**kwargs), 'commit'))
-
-
-class Ref(object):
- """Represents a single simple ref in a git Repo."""
- def __init__(self, repo, ref_str):
- """
- @type repo: Repo
- @type ref_str: str
- """
- self._repo = repo
- self._ref = ref_str
-
- # Comparison & Representation
- def __eq__(self, other):
- return (self is other) or (
- isinstance(other, Ref) and (
- self.ref == other.ref and
- self.repo is other.repo
- )
- )
-
- def __ne__(self, other):
- return not (self == other)
-
- def __repr__(self):
- return 'Ref({_repo!r}, {_ref!r})'.format(**self.__dict__)
-
- # Accessors
- # pylint: disable=W0212
- repo = property(lambda self: self._repo)
- ref = property(lambda self: self._ref)
-
- # Properties
- @property
- def commit(self):
- """Get the Commit at the tip of this Ref."""
- try:
- val = self._repo.run('show-ref', '--verify', self._ref)
- except CalledProcessError:
- return INVALID
- return self._repo.get_commit(val.split()[0])
-
- # Methods
- def to(self, other):
- """Generate Commit()'s which occur from `self..other`."""
- assert self.commit is not INVALID
- arg = '%s..%s' % (self.ref, other.ref)
- for hsh in self.repo.run('rev-list', '--reverse', arg).splitlines():
- yield self.repo.get_commit(hsh)
-
- def fast_forward_push(self, commit):
- """Push |commit| to this ref on the remote, and update the local copy of the
- ref to |commit|."""
- self.repo.run('push', 'origin', '%s:%s' % (commit.hsh, self.ref))
- self.update_to(commit)
-
- def update_to(self, commit):
- """Update the local copy of the ref to |commit|."""
- self.repo.run('update-ref', self.ref, commit.hsh)

Powered by Google App Engine
This is Rietveld 408576698