Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / chromite / lib / git.py
index 9dc6fa8..e780fc5 100644 (file)
@@ -21,7 +21,7 @@ from xml import sax
 _path = os.path.realpath(__file__)
 _path = os.path.normpath(os.path.join(os.path.dirname(_path), '..', '..'))
 sys.path.insert(0, _path)
-from chromite.buildbot import constants
+from chromite.cbuildbot import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import osutils
 from chromite.lib import retry_util
@@ -33,13 +33,13 @@ del _path
 # messages. It's all observed 'bad' GoB responses so far.
 GIT_TRANSIENT_ERRORS = (
     # crbug.com/285832
-    r'! \[remote rejected\].* -> .* \(error in hook\)',
+    r'! \[remote rejected\].*\(error in hook\)',
 
     # crbug.com/289932
-    r'! \[remote rejected\].* -> .* \(failed to lock\)',
+    r'! \[remote rejected\].*\(failed to lock\)',
 
     # crbug.com/307156
-    r'! \[remote rejected\].* -> .* \(error in Gerrit backend\)',
+    r'! \[remote rejected\].*\(error in Gerrit backend\)',
 
     # crbug.com/285832
     r'remote error: Internal Server Error',
@@ -64,9 +64,13 @@ GIT_TRANSIENT_ERRORS = (
 
     # crbug.com/315421
     r'The requested URL returned error: 500 while accessing',
+
+    # crbug.com/388876
+    r'Connection timed out',
 )
 
-GIT_TRANSIENT_ERRORS_RE = re.compile('|'.join(GIT_TRANSIENT_ERRORS))
+GIT_TRANSIENT_ERRORS_RE = re.compile('|'.join(GIT_TRANSIENT_ERRORS),
+                                     re.IGNORECASE)
 
 DEFAULT_RETRY_INTERVAL = 3
 DEFAULT_RETRIES = 5
@@ -79,6 +83,7 @@ class RemoteRef(object):
   'https://chromium.googlesource.com/chromiumos/chromite.git', etc.) and a ref
   name (e.g., 'refs/heads/master').
   """
+
   def __init__(self, remote, ref):
     self.remote = remote
     self.ref = ref
@@ -166,6 +171,8 @@ def IsGitRepositoryCorrupted(cwd):
 
 
 _HEX_CHARS = frozenset(string.hexdigits)
+
+
 def IsSHA1(value, full=True):
   """Returns True if the given value looks like a sha1.
 
@@ -185,7 +192,7 @@ def IsRefsTags(value):
 
   Currently this is identified via refs/tags/ prefixing.
   """
-  return value.startswith("refs/tags/")
+  return value.startswith('refs/tags/')
 
 
 def GetGitRepoRevision(cwd, branch='HEAD'):
@@ -196,27 +203,23 @@ def GetGitRepoRevision(cwd, branch='HEAD'):
   return RunGit(cwd, ['rev-parse', branch]).output.strip()
 
 
-def DoesCommitExistInRepo(cwd, commit_hash):
-  """Determine if commit object exists in a repo.
+def DoesCommitExistInRepo(cwd, commit):
+  """Determine whether a commit (SHA1 or ref) exists in a repo.
 
   Args:
     cwd: A directory within the project repo.
-    commit_hash: The hash of the commit object to look for.
-  """
-  return 0 == RunGit(cwd, ['rev-list', '-n1', commit_hash],
-                     error_code_ok=True).returncode
-
+    commit: The commit to look for. This can be a SHA1 or it can be a ref.
 
-def DoesLocalBranchExist(repo_dir, branch):
-  """Returns True if the local branch exists.
-
-  Args:
-    repo_dir: Directory of the git repository to check.
-    branch: The name of the branch to test for.
+  Returns:
+    True if the commit exists in the repo.
   """
-  return os.path.isfile(
-      os.path.join(repo_dir, '.git/refs/heads',
-                   branch.lstrip('/')))
+  try:
+    RunGit(cwd, ['rev-list', '-n1', commit, '--'])
+  except cros_build_lib.RunCommandError as e:
+    if e.result.returncode == 128:
+      return False
+    raise
+  return True
 
 
 def GetCurrentBranch(cwd):
@@ -245,8 +248,8 @@ def StripRefsHeads(ref, strict=True):
 def StripRefs(ref):
   """Remove leading 'refs/heads', 'refs/remotes/[^/]+/' from a ref name."""
   ref = StripRefsHeads(ref, False)
-  if ref.startswith("refs/remotes/"):
-    return ref.split("/", 3)[-1]
+  if ref.startswith('refs/remotes/'):
+    return ref.split('/', 3)[-1]
   return ref
 
 
@@ -292,7 +295,8 @@ class ProjectCheckout(dict):
 
   def IsBranchableProject(self):
     """Return whether this project is hosted on ChromeOS git servers."""
-    return (self['remote'] in constants.CROS_REMOTES and
+    return (
+        self['remote'] in constants.CROS_REMOTES and
         re.match(constants.BRANCHABLE_PROJECTS[self['remote']], self['name']))
 
   def IsPatchable(self):
@@ -309,8 +313,8 @@ class ProjectCheckout(dict):
     # - For an unversioned manifest, if the 'revision' is a raw SHA1 hash
     #   and not a named branch, assume it is a pinned project path and can not
     #   be patched.
-    # - For a versioned manifest (generated via repo -r), repo will sets
-    #   revision to the actual git sha1 ref, and adds an 'upstream'
+    # - For a versioned manifest (generated via repo -r), repo will set
+    #   revision to the actual git sha1 ref, and add an 'upstream'
     #   field corresponding to branch name in the original manifest. For
     #   a project with a SHA1 'revision' but no named branch in the
     #   'upstream' field, assume it can not be patched.
@@ -386,15 +390,15 @@ class Manifest(object):
       attrs.setdefault('alias', attrs['name'])
       self.remotes[attrs['name']] = attrs
     elif name == 'project':
-      self.checkouts_by_path[attrs['path']] = attrs
+      self.checkouts_by_path[attrs.get('path', attrs['name'])] = attrs
       self.checkouts_by_name.setdefault(attrs['name'], []).append(attrs)
     elif name == 'manifest':
       self.revision = attrs.get('revision')
     elif name == 'include':
       if self.manifest_include_dir is None:
         raise OSError(
-            errno.ENOENT, "No manifest_include_dir given, but an include was "
-            "encountered; attrs=%r" % (attrs,))
+            errno.ENOENT, 'No manifest_include_dir given, but an include was '
+            'encountered; attrs=%r' % (attrs,))
       # Include is calculated relative to the manifest that has the include;
       # thus set the path temporarily to the dirname of the target.
       original_include_dir = self.manifest_include_dir
@@ -529,7 +533,6 @@ class ManifestCheckout(Manifest):
     manifest_include_dir = os.path.dirname(self.manifest_path)
     self.manifest_branch = self._GetManifestsBranch(self.root)
     self._content_merging = {}
-    self.configured_groups = self._GetManifestGroups(self.root)
     Manifest.__init__(self, self.manifest_path,
                       manifest_include_dir=manifest_include_dir)
 
@@ -541,40 +544,12 @@ class ManifestCheckout(Manifest):
     root = os.path.normpath(os.path.realpath(root))
     if not search:
       if os.path.normpath(os.path.realpath(path)) != root:
-        raise OSError(errno.ENOENT, "Path %s is not a repo root, and search "
-                      "is disabled." % path)
+        raise OSError(errno.ENOENT, 'Path %s is not a repo root, and search '
+                      'is disabled.' % path)
     if manifest_path is None:
       manifest_path = os.path.join(root, '.repo', 'manifest.xml')
     return root, manifest_path
 
-  def ProjectIsContentMerging(self, project):
-    """Returns whether the given project has content merging enabled in git.
-
-    Note this functionality should *only* be used against a remote that is
-    known to be >=gerrit-2.2; <gerrit-2.2 lacks the required branch holding
-    this data thus will trigger a RunCommandError.
-
-    Returns:
-      True if content merging is enabled.
-
-    Raises:
-      AssertionError: If no patchable checkout was found or if the patchable
-        checkout does not have a pushable project remote.
-      RunCommandError: If the branch can't be fetched due to network
-        conditions or if this was invoked against a <gerrit-2.2 server,
-        or a mirror that has refs/meta/config stripped from it.
-    """
-    result = self._content_merging.get(project)
-    if result is None:
-      checkouts = self.FindCheckouts(project, only_patchable=True)
-      if len(checkouts) < 1:
-        raise AssertionError('No patchable checkout of %s was found' % project)
-      for checkout in checkouts:
-        checkout.AssertPushable()
-        self._content_merging[project] = result = _GitRepoIsContentMerging(
-            checkout['local_path'], checkout['push_remote'])
-    return result
-
   def FindCheckouts(self, project, branch=None, only_patchable=False):
     """Returns the list of checkouts for a given |project|/|branch|.
 
@@ -632,7 +607,7 @@ class ManifestCheckout(Manifest):
     """Find the associated checkouts for a given |path|.
 
     The |path| can either be to the root of a project, or within the
-    project itself (chromite/buildbot for example).  It may be relative
+    project itself (chromite.cbuildbot for example).  It may be relative
     to the repo root, or an absolute path.  If |path| is not within a
     checkout, return None.
 
@@ -677,25 +652,6 @@ class ManifestCheckout(Manifest):
     attrs['local_path'] = os.path.join(self.root, attrs['path'])
 
   @staticmethod
-  def _GetManifestGroups(root):
-    """Discern which manifest groups were enabled for this checkout."""
-    path = os.path.join(root, '.repo', 'manifests.git')
-    try:
-      result = RunGit(path, ['config', '--get', 'manifest.groups'])
-    except cros_build_lib.RunCommandError as e:
-      if e.result.returncode == 1:
-        # Value wasn't found, which is fine.
-        return frozenset(['default'])
-      # If exit code 2, multiple values matched (broken checkout).  Anything
-      # else, git internal error.
-      raise
-
-    result = result.output.replace(',', ' ').split()
-    if not result:
-      result = ['default']
-    return frozenset(result)
-
-  @staticmethod
   def _GetManifestsBranch(root):
     """Get the tracking branch of the manifest repository.
 
@@ -710,7 +666,7 @@ class ManifestCheckout(Manifest):
     current_branch = GetCurrentBranch(path)
     if current_branch != 'default':
       raise OSError(errno.ENOENT,
-                    "Manifest repository at %s is checked out to %s.  "
+                    'Manifest repository at %s is checked out to %s.  '
                     "It should be checked out to 'default'."
                     % (root, 'detached HEAD' if current_branch is None
                        else current_branch))
@@ -723,8 +679,8 @@ class ManifestCheckout(Manifest):
 
     raise OSError(errno.ENOENT,
                   "Manifest repository at %s is checked out to 'default', but "
-                  "the git tracking configuration for that branch is broken; "
-                  "failing due to that." % (root,))
+                  'the git tracking configuration for that branch is broken; '
+                  'failing due to that.' % (root,))
 
   # pylint: disable=W0221
   @classmethod
@@ -756,47 +712,6 @@ class ManifestCheckout(Manifest):
     return obj
 
 
-def _GitRepoIsContentMerging(git_repo, remote):
-  """Identify if the given git repo has content merging marked.
-
-  This is a gerrit >=2.2 bit of functionality; specifically, the content
-  merging configuration is stored in a specially crafted branch which
-  we access.  If the branch is fetchable, we either return True or False.
-
-  Args:
-    git_repo: The local path to the git repository to inspect.
-    remote: The configured remote to use from the given git repository.
-
-  Returns:
-    True if content merging is enabled, False if not.
-
-  Raises:
-    RunCommandError: Thrown if fetching fails due to either the namespace
-      not existing, or a network error intervening.
-  """
-  # Need to use the manifest to get upstream gerrit; also, if upstream
-  # doesn't provide a refs/meta/config for the repo, this will fail.
-  RunGit(git_repo, ['fetch', remote, 'refs/meta/config:refs/meta/config'])
-
-  content = RunGit(git_repo, ['show', 'refs/meta/config:project.config'],
-                   error_code_ok=True)
-
-  if content.returncode != 0:
-    return False
-
-  try:
-    result = RunGit(git_repo, ['config', '-f', '/dev/stdin', '--get',
-                               'submit.mergeContent'], input=content.output)
-    return result.output.strip().lower() == 'true'
-  except cros_build_lib.RunCommandError as e:
-    # If the field isn't set at all, exit code is 1.
-    # Anything else is a bad invocation or an indecipherable state.
-    if e.result.returncode != 1:
-      raise
-
-  return False
-
-
 def RunGit(git_repo, cmd, retry=True, **kwargs):
   """RunCommand wrapper for git commands.
 
@@ -946,8 +861,8 @@ def GetTrackingBranchViaGitConfig(git_repo, branch, for_checkout=True,
     elif remote == '.':
       if recurse == 0:
         raise Exception(
-            "While tracing out tracking branches, we recursed too deeply: "
-            "bailing at %s" % branch)
+            'While tracing out tracking branches, we recursed too deeply: '
+            'bailing at %s' % branch)
       return GetTrackingBranchViaGitConfig(
           git_repo, StripRefsHeads(rev), for_checkout=for_checkout,
           allow_broken_merge_settings=allow_broken_merge_settings,
@@ -1139,10 +1054,10 @@ def SyncPushBranch(git_repo, remote, rebase_target):
       start with refs/remotes/ (specifically must be a proper remote
       target rather than an ambiguous name).
   """
-  if not rebase_target.startswith("refs/remotes/"):
+  if not rebase_target.startswith('refs/remotes/'):
     raise Exception(
-        "Was asked to rebase to a non branch target w/in the push pathways.  "
-        "This is highly indicative of an internal bug.  remote %s, rebase %s"
+        'Was asked to rebase to a non branch target w/in the push pathways.  '
+        'This is highly indicative of an internal bug.  remote %s, rebase %s'
         % (remote, rebase_target))
 
   cmd = ['remote', 'update', remote]
@@ -1181,11 +1096,11 @@ def PushWithRetry(branch, git_repo, dryrun=False, retries=5):
   # impedence here; cros_mark_as_stable
   _, local_ref = GetTrackingBranch(git_repo, branch, for_push=True)
 
-  if not ref.startswith("refs/heads/"):
-    raise Exception("Was asked to push to a non branch namespace: %s" % (ref,))
+  if not ref.startswith('refs/heads/'):
+    raise Exception('Was asked to push to a non branch namespace: %s' % (ref,))
 
   push_command = ['push', remote, '%s:%s' % (branch, ref)]
-  cros_build_lib.Debug("Trying to push %s to %s:%s", git_repo, branch, ref)
+  cros_build_lib.Debug('Trying to push %s to %s:%s', git_repo, branch, ref)
 
   if dryrun:
     push_command.append('--dry-run')
@@ -1201,7 +1116,7 @@ def PushWithRetry(branch, git_repo, dryrun=False, retries=5):
         continue
       raise
 
-  cros_build_lib.Info("Successfully pushed %s to %s:%s", git_repo, branch, ref)
+  cros_build_lib.Info('Successfully pushed %s to %s:%s', git_repo, branch, ref)
 
 
 def CleanAndDetachHead(git_repo):
@@ -1259,8 +1174,8 @@ def GetChromiteTrackingBranch():
   # Not a manifest checkout.
   Warning(
       "Chromite checkout at %s isn't controlled by repo, nor is it on a "
-      "branch (or if it is, the tracking configuration is missing or broken).  "
-      "Falling back to assuming the chromite checkout is derived from "
+      'branch (or if it is, the tracking configuration is missing or broken).  '
+      'Falling back to assuming the chromite checkout is derived from '
       "'master'; this *may* result in breakage." % cwd)
   return 'master'