Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / native_client / pynacl / repo_tools.py
index d8e22f7..3751273 100644 (file)
@@ -5,6 +5,7 @@
 
 import logging
 import os
+import posixpath
 import subprocess
 import sys
 import urlparse
@@ -13,6 +14,9 @@ import file_tools
 import log_tools
 import platform
 
+GIT_ALTERNATES_PATH = os.path.join('.git', 'objects', 'info', 'alternates')
+
+
 class InvalidRepoException(Exception):
   def __init__(self, expected_repo, msg, *args):
     Exception.__init__(self, msg % args)
@@ -47,7 +51,7 @@ def SvnCmd():
     return ['svn']
 
 
-def ValidateGitRepo(url, directory, clobber_mismatch=False):
+def ValidateGitRepo(url, directory, clobber_mismatch=False, logger=None):
   """Validates a git repository tracks a particular URL.
 
   Given a git directory, this function will validate if the git directory
@@ -60,6 +64,8 @@ def ValidateGitRepo(url, directory, clobber_mismatch=False):
   clobber_mismatch: If True, will delete invalid directories instead of raising
                     an exception.
   """
+  if logger is None:
+    logger = log_tools.GetConsoleLogger()
   git_dir = os.path.join(directory, '.git')
   if os.path.exists(git_dir):
     try:
@@ -67,15 +73,15 @@ def ValidateGitRepo(url, directory, clobber_mismatch=False):
                                include_push=False):
         return
 
-      logging.warn('Local git repo (%s) does not track url (%s)',
+      logger.warn('Local git repo (%s) does not track url (%s)',
                    directory, url)
     except:
-      logging.error('Invalid git repo: %s', directory)
+      logger.error('Invalid git repo: %s', directory)
 
     if not clobber_mismatch:
       raise InvalidRepoException(url, 'Invalid local git repo: %s', directory)
     else:
-      logging.debug('Clobbering invalid git repo %s' % directory)
+      logger.debug('Clobbering invalid git repo %s' % directory)
       file_tools.RemoveDirectoryIfPresent(directory)
   elif os.path.exists(directory) and len(os.listdir(directory)) != 0:
     if not clobber_mismatch:
@@ -83,12 +89,12 @@ def ValidateGitRepo(url, directory, clobber_mismatch=False):
                                  'Invalid non-empty repository destination %s',
                                  directory)
     else:
-      logging.debug('Clobbering intended repository destination: %s', directory)
+      logger.debug('Clobbering intended repository destination: %s', directory)
       file_tools.RemoveDirectoryIfPresent(directory)
 
 
 def SyncGitRepo(url, destination, revision, reclone=False, clean=False,
-                pathspec=None, git_cache=None, push_url=None):
+                pathspec=None, git_cache=None, push_url=None, logger=None):
   """Sync an individual git repo.
 
   Args:
@@ -106,70 +112,91 @@ def SyncGitRepo(url, destination, revision, reclone=False, clean=False,
              directory specified and sets the fetch URL to be from the
              git_cache.
   """
+  if logger is None:
+    logger = log_tools.GetConsoleLogger()
   if reclone:
-    logging.debug('Clobbering source directory %s' % destination)
+    logger.debug('Clobbering source directory %s' % destination)
     file_tools.RemoveDirectoryIfPresent(destination)
 
   if git_cache:
-    fetch_url = GetGitCacheURL(git_cache, url)
+    git_cache_url = GetGitCacheURL(git_cache, url)
   else:
-    fetch_url = url
+    git_cache_url = None
 
   # If the destination is a git repository, validate the tracked origin.
   git_dir = os.path.join(destination, '.git')
   if os.path.exists(git_dir):
-    if not IsURLInRemoteRepoList(fetch_url, destination, include_fetch=True,
+    if not IsURLInRemoteRepoList(url, destination, include_fetch=True,
                                  include_push=False):
-      # If the original URL is being tracked instead of the fetch URL, we
+      # If the git cache URL is being tracked instead of the fetch URL, we
       # can safely redirect it to the fetch URL instead.
-      if (fetch_url != url and IsURLInRemoteRepoList(url, destination,
-                                                     include_fetch=True,
-                                                     include_push=False)):
-        GitSetRemoteRepo(fetch_url, destination, push_url=push_url)
+      if git_cache_url and IsURLInRemoteRepoList(git_cache_url, destination,
+                                                 include_fetch=True,
+                                                 include_push=False):
+        GitSetRemoteRepo(url, destination, push_url=push_url,
+                         logger=logger)
       else:
-        logging.error('Git Repo (%s) does not track URL: %s',
-                      destination, fetch_url)
-        raise InvalidRepoException(fetch_url, 'Could not sync git repo: %s',
+        logger.error('Git Repo (%s) does not track URL: %s',
+                      destination, url)
+        raise InvalidRepoException(url, 'Could not sync git repo: %s',
                                    destination)
 
+      # Make sure the push URL is set correctly as well.
+      if not IsURLInRemoteRepoList(push_url, destination, include_fetch=False,
+                                   include_push=True):
+        GitSetRemoteRepo(url, destination, push_url=push_url)
+
   git = GitCmd()
   if not os.path.exists(git_dir):
-    logging.info('Cloning %s...' % url)
-    clone_args = ['clone', '-n']
-    if git_cache:
-      clone_args.append('-s')
+    logger.info('Cloning %s...' % url)
 
     file_tools.MakeDirectoryIfAbsent(destination)
-    log_tools.CheckCall(git + clone_args + [fetch_url, '.'], cwd=destination)
+    clone_args = ['clone', '-n']
+    if git_cache_url:
+      clone_args.extend(['--reference', git_cache_url])
 
-    if fetch_url != url:
-      GitSetRemoteRepo(fetch_url, destination, push_url=push_url)
+    log_tools.CheckCall(git + clone_args + [url, '.'],
+                        logger=logger, cwd=destination)
 
+    if url != push_url:
+      GitSetRemoteRepo(url, destination, push_url=push_url, logger=logger)
   elif clean:
-    log_tools.CheckCall(git + ['clean', '-dffx'], cwd=destination)
-    log_tools.CheckCall(git + ['reset', '--hard', 'HEAD'], cwd=destination)
+    log_tools.CheckCall(git + ['clean', '-dffx'],
+                        logger=logger, cwd=destination)
+    log_tools.CheckCall(git + ['reset', '--hard', 'HEAD'],
+                        logger=logger, cwd=destination)
+
+  # If a git cache URL is supplied, make sure it is setup as a git alternate.
+  if git_cache_url:
+    git_alternates = [git_cache_url]
+  else:
+    git_alternates = []
+
+  GitSetRepoAlternates(destination, git_alternates, append=False, logger=logger)
 
   if revision is not None:
-    logging.info('Checking out pinned revision...')
-    log_tools.CheckCall(git + ['fetch', '--all'], cwd=destination)
+    logger.info('Checking out pinned revision...')
+    log_tools.CheckCall(git + ['fetch', '--all'],
+                        logger=logger, cwd=destination)
     checkout_flags = ['-f'] if clean else []
     path = [pathspec] if pathspec else []
     log_tools.CheckCall(
         git + ['checkout'] + checkout_flags + [revision] + path,
-        cwd=destination)
+        logger=logger, cwd=destination)
 
 
-def CleanGitWorkingDir(directory, path):
+def CleanGitWorkingDir(directory, path, logger=None):
   """Clean a particular path of an existing git checkout.
 
      Args:
      directory: Directory where the git repo is currently checked out
      path: path to clean, relative to the repo directory
   """
-  log_tools.CheckCall(GitCmd() + ['clean', '-f', path], cwd=directory)
+  log_tools.CheckCall(GitCmd() + ['clean', '-f', path],
+                      logger=logger, cwd=directory)
 
 
-def PopulateGitCache(cache_dir, url_list):
+def PopulateGitCache(cache_dir, url_list, logger=None):
   """Fetches a git repo that combines a list of git repos.
 
   This is an interface to the "git cache" command found within depot_tools.
@@ -186,10 +213,10 @@ def PopulateGitCache(cache_dir, url_list):
     git = GitCmd()
     for url in url_list:
       log_tools.CheckCall(git + ['cache', 'populate', '-c', '.', url],
-                          cwd=cache_dir)
+                          logger=logger, cwd=cache_dir)
 
 
-def GetGitCacheURL(cache_dir, url):
+def GetGitCacheURL(cache_dir, url, logger=None):
   """Converts a regular git URL to a git cache URL within a cache directory.
 
   Args:
@@ -211,10 +238,11 @@ def GetGitCacheURL(cache_dir, url):
 
   git_url = log_tools.CheckOutput(GitCmd() + ['cache', 'exists',
                                               '-c', cache_dir,
-                                              url]).strip()
+                                              url],
+                                  logger=logger).strip()
 
-  # For cygwin paths, convert forward slashes to backslashes to mimic URLs.
-  if cygwin_path:
+  # For windows, make sure the git cache URL is a posix path.
+  if platform.IsWindows():
     git_url = git_url.replace('\\', '/')
   return git_url
 
@@ -270,7 +298,8 @@ def GetAuthenticatedGitURL(url):
   return urlsplit.geturl()
 
 
-def GitRemoteRepoList(directory, include_fetch=True, include_push=True):
+def GitRemoteRepoList(directory, include_fetch=True, include_push=True,
+                      logger=None):
   """Returns a list of remote git repos associated with a directory.
 
   Args:
@@ -279,7 +308,7 @@ def GitRemoteRepoList(directory, include_fetch=True, include_push=True):
       List of (repo_name, repo_url) for tracked remote repos.
   """
   remote_repos = log_tools.CheckOutput(GitCmd() + ['remote', '-v'],
-                                       cwd=directory)
+                                       logger=logger, cwd=directory)
 
   repo_set = set()
   for remote_repo_line in remote_repos.splitlines():
@@ -292,7 +321,8 @@ def GitRemoteRepoList(directory, include_fetch=True, include_push=True):
   return sorted(repo_set)
 
 
-def GitSetRemoteRepo(url, directory, push_url=None, repo_name='origin'):
+def GitSetRemoteRepo(url, directory, push_url=None,
+                     repo_name='origin', logger=None):
   """Sets the remotely tracked URL for a git repository.
 
   Args:
@@ -304,20 +334,20 @@ def GitSetRemoteRepo(url, directory, push_url=None, repo_name='origin'):
   git = GitCmd()
   try:
     log_tools.CheckCall(git + ['remote', 'set-url', repo_name, url],
-                        cwd=directory)
+                        logger=logger, cwd=directory)
   except subprocess.CalledProcessError:
     # If setting the URL failed, repo_name may be new. Try adding the URL.
     log_tools.CheckCall(git + ['remote', 'add', repo_name, url],
-                        cwd=directory)
+                        logger=logger, cwd=directory)
 
   if push_url:
     log_tools.CheckCall(git + ['remote', 'set-url', '--push',
                                repo_name, push_url],
-                        cwd=directory)
+                        logger=logger, cwd=directory)
 
 
 def IsURLInRemoteRepoList(url, directory, include_fetch=True, include_push=True,
-                          try_authenticated_url=True):
+                          try_authenticated_url=True, logger=None):
   """Returns whether or not a url is a remote repo in a local git directory.
 
   Args:
@@ -331,7 +361,62 @@ def IsURLInRemoteRepoList(url, directory, include_fetch=True, include_push=True,
 
   remote_repo_list = GitRemoteRepoList(directory,
                                        include_fetch=include_fetch,
-                                       include_push=include_push)
+                                       include_push=include_push,
+                                       logger=logger)
   return len([repo_name for
               repo_name, repo_url in remote_repo_list
               if repo_url in valid_urls]) > 0
+
+
+def GitGetRepoAlternates(directory):
+  """Gets the list of git alternates for a local git repo.
+
+  Args:
+      directory: Local git repository to get the git alternate for.
+
+  Returns:
+      List of git alternates set for the local git repository.
+  """
+  git_alternates_file = os.path.join(directory, GIT_ALTERNATES_PATH)
+  if os.path.isfile(git_alternates_file):
+    with open(git_alternates_file, 'rt') as f:
+      alternates_list = []
+      for line in f.readlines():
+        line = line.strip()
+        if line:
+          if posixpath.basename(line) == 'objects':
+            line = posixpath.dirname(line)
+          alternates_list.append(line)
+
+      return alternates_list
+
+  return []
+
+
+def GitSetRepoAlternates(directory, alternates_list, append=True, logger=None):
+  """Sets the list of git alternates for a local git repo.
+
+  Args:
+      directory: Local git repository.
+      alternates_list: List of local git repositories for the git alternates.
+      append: If True, will append the list to currently set list of alternates.
+  """
+  if logger is None:
+    logger = log_tools.GetConsoleLogger()
+  git_alternates_file = os.path.join(directory, GIT_ALTERNATES_PATH)
+  git_alternates_dir = os.path.dirname(git_alternates_file)
+  if not os.path.isdir(git_alternates_dir):
+    raise InvalidRepoException(directory,
+                               'Invalid local git repo: %s', directory)
+
+  original_alternates_list = GitGetRepoAlternates(directory)
+  if append:
+    alternates_list.extend(original_alternates_list)
+    alternates_list = sorted(set(alternates_list))
+
+  if set(original_alternates_list) != set(alternates_list):
+    lines = [posixpath.join(line, 'objects') + '\n' for line in alternates_list]
+    logger.info('Setting git alternates:\n\t%s', '\t'.join(lines))
+
+    with open(git_alternates_file, 'wb') as f:
+      f.writelines(lines)