Merge "Fix 'repo cherry-pick' to avoid hanging on commit-msg update."
diff --git a/error.py b/error.py
index ff948f9..f2a7c4e 100644
--- a/error.py
+++ b/error.py
@@ -80,7 +80,7 @@
self.name = name
def __str__(self):
- if self.Name is None:
+ if self.name is None:
return 'in current directory'
return self.name
@@ -93,7 +93,7 @@
self.name = name
def __str__(self):
- if self.Name is None:
+ if self.name is None:
return 'in current directory'
return self.name
diff --git a/git_command.py b/git_command.py
index 259fb02..0893bff 100644
--- a/git_command.py
+++ b/git_command.py
@@ -92,7 +92,10 @@
def version(self):
p = GitCommand(None, ['--version'], capture_stdout=True)
if p.Wait() == 0:
- return p.stdout.decode('utf-8')
+ if hasattr(p.stdout, 'decode'):
+ return p.stdout.decode('utf-8')
+ else:
+ return p.stdout
return None
def version_tuple(self):
@@ -263,6 +266,8 @@
if not buf:
s_in.remove(s)
continue
+ if not hasattr(buf, 'encode'):
+ buf = buf.decode()
if s.std_name == 'stdout':
self.stdout += buf
else:
diff --git a/git_config.py b/git_config.py
index c4c31e1..8ded7c2 100644
--- a/git_config.py
+++ b/git_config.py
@@ -280,7 +280,7 @@
finally:
fd.close()
except (IOError, TypeError):
- if os.path.exists(self.json):
+ if os.path.exists(self._json):
os.remove(self._json)
def _ReadGit(self):
diff --git a/project.py b/project.py
index 00e41ad..3f1e3b6 100644
--- a/project.py
+++ b/project.py
@@ -16,6 +16,7 @@
import contextlib
import errno
import filecmp
+import glob
import os
import random
import re
@@ -233,28 +234,60 @@
_error('Cannot copy file %s to %s', src, dest)
class _LinkFile(object):
- def __init__(self, src, dest, abssrc, absdest):
+ def __init__(self, git_worktree, src, dest, relsrc, absdest):
+ self.git_worktree = git_worktree
self.src = src
self.dest = dest
- self.abs_src = abssrc
+ self.src_rel_to_dest = relsrc
self.abs_dest = absdest
- def _Link(self):
- src = self.abs_src
- dest = self.abs_dest
+ def __linkIt(self, relSrc, absDest):
# link file if it does not exist or is out of date
- if not os.path.islink(dest) or os.readlink(dest) != src:
+ if not os.path.islink(absDest) or (os.readlink(absDest) != relSrc):
try:
# remove existing file first, since it might be read-only
- if os.path.exists(dest):
- os.remove(dest)
+ if os.path.exists(absDest):
+ os.remove(absDest)
else:
- dest_dir = os.path.dirname(dest)
+ dest_dir = os.path.dirname(absDest)
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir)
- os.symlink(src, dest)
+ os.symlink(relSrc, absDest)
except IOError:
- _error('Cannot link file %s to %s', src, dest)
+ _error('Cannot link file %s to %s', relSrc, absDest)
+
+ def _Link(self):
+ """Link the self.rel_src_to_dest and self.abs_dest. Handles wild cards
+ on the src linking all of the files in the source in to the destination
+ directory.
+ """
+ # We use the absSrc to handle the situation where the current directory
+ # is not the root of the repo
+ absSrc = os.path.join(self.git_worktree, self.src)
+ if os.path.exists(absSrc):
+ # Entity exists so just a simple one to one link operation
+ self.__linkIt(self.src_rel_to_dest, self.abs_dest)
+ else:
+ # Entity doesn't exist assume there is a wild card
+ absDestDir = self.abs_dest
+ if os.path.exists(absDestDir) and not os.path.isdir(absDestDir):
+ _error('Link error: src with wildcard, %s must be a directory',
+ absDestDir)
+ else:
+ absSrcFiles = glob.glob(absSrc)
+ for absSrcFile in absSrcFiles:
+ # Create a releative path from source dir to destination dir
+ absSrcDir = os.path.dirname(absSrcFile)
+ relSrcDir = os.path.relpath(absSrcDir, absDestDir)
+
+ # Get the source file name
+ srcFile = os.path.basename(absSrcFile)
+
+ # Now form the final full paths to srcFile. They will be
+ # absolute for the desintaiton and relative for the srouce.
+ absDest = os.path.join(absDestDir, srcFile)
+ relSrc = os.path.join(relSrcDir, srcFile)
+ self.__linkIt(relSrc, absDest)
class RemoteSpec(object):
def __init__(self,
@@ -1359,9 +1392,10 @@
def AddLinkFile(self, src, dest, absdest):
# dest should already be an absolute path, but src is project relative
- # make src an absolute path
- abssrc = os.path.join(self.worktree, src)
- self.linkfiles.append(_LinkFile(src, dest, abssrc, absdest))
+ # make src relative path to dest
+ absdestdir = os.path.dirname(absdest)
+ relsrc = os.path.relpath(os.path.join(self.worktree, src), absdestdir)
+ self.linkfiles.append(_LinkFile(self.worktree, src, dest, relsrc, absdest))
def AddAnnotation(self, name, value, keep):
self.annotations.append(_Annotation(name, value, keep))
@@ -1908,6 +1942,9 @@
# mode, we just tried sync'ing from the upstream field; it doesn't exist, thus
# abort the optimization attempt and do a full sync.
break
+ elif ret < 0:
+ # Git died with a signal, exit immediately
+ break
time.sleep(random.randint(30, 45))
if initial:
diff --git a/subcmds/forall.py b/subcmds/forall.py
index 88b23fb..ebc8bec 100644
--- a/subcmds/forall.py
+++ b/subcmds/forall.py
@@ -20,6 +20,7 @@
import re
import os
import select
+import signal
import sys
import subprocess
@@ -207,14 +208,12 @@
os.environ['REPO_COUNT'] = str(len(projects))
- pool = multiprocessing.Pool(opt.jobs)
+ pool = multiprocessing.Pool(opt.jobs, InitWorker)
try:
config = self.manifest.manifestProject.config
results_it = pool.imap(
DoWorkWrapper,
- ([mirror, opt, cmd, shell, cnt, config, self._SerializeProject(p)]
- for cnt, p in enumerate(projects))
- )
+ self.ProjectArgs(projects, mirror, opt, cmd, shell, config))
pool.close()
for r in results_it:
rc = rc or r
@@ -236,12 +235,28 @@
if rc != 0:
sys.exit(rc)
+ def ProjectArgs(self, projects, mirror, opt, cmd, shell, config):
+ for cnt, p in enumerate(projects):
+ try:
+ project = self._SerializeProject(p)
+ except Exception as e:
+ print('Project list error: %r' % e,
+ file=sys.stderr)
+ return
+ except KeyboardInterrupt:
+ print('Project list interrupted',
+ file=sys.stderr)
+ return
+ yield [mirror, opt, cmd, shell, cnt, config, project]
class WorkerKeyboardInterrupt(Exception):
""" Keyboard interrupt exception for worker processes. """
pass
+def InitWorker():
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+
def DoWorkWrapper(args):
""" A wrapper around the DoWork() method.
@@ -263,7 +278,9 @@
def setenv(name, val):
if val is None:
val = ''
- env[name] = val.encode()
+ if hasattr(val, 'encode'):
+ val = val.encode()
+ env[name] = val
setenv('REPO_PROJECT', project['name'])
setenv('REPO_PATH', project['relpath'])
diff --git a/subcmds/init.py b/subcmds/init.py
index b73de71..dbb6ddd 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -27,7 +27,7 @@
import imp
import urlparse
urllib = imp.new_module('urllib')
- urllib.parse = urlparse.urlparse
+ urllib.parse = urlparse
from color import Coloring
from command import InteractiveCommand, MirrorSafeCommand
@@ -153,7 +153,7 @@
# server where this git is located, so let's save that here.
mirrored_manifest_git = None
if opt.reference:
- manifest_git_path = urllib.parse(opt.manifest_url).path[1:]
+ manifest_git_path = urllib.parse.urlparse(opt.manifest_url).path[1:]
mirrored_manifest_git = os.path.join(opt.reference, manifest_git_path)
if not mirrored_manifest_git.endswith(".git"):
mirrored_manifest_git += ".git"