Commit cca15f81 authored by Matthias Putz's avatar Matthias Putz

adapted style to PEP8 style guide

parent 294579e8
...@@ -18,34 +18,36 @@ import sys ...@@ -18,34 +18,36 @@ import sys
import pager import pager
COLORS = {None :-1, COLORS = {None: -1,
'normal' :-1, 'normal': -1,
'black' : 0, 'black': 0,
'red' : 1, 'red': 1,
'green' : 2, 'green': 2,
'yellow' : 3, 'yellow': 3,
'blue' : 4, 'blue': 4,
'magenta': 5, 'magenta': 5,
'cyan' : 6, 'cyan': 6,
'white' : 7} 'white': 7}
ATTRS = {None :-1, ATTRS = {None: -1,
'bold' : 1, 'bold': 1,
'dim' : 2, 'dim': 2,
'ul' : 4, 'ul': 4,
'blink' : 5, 'blink': 5,
'reverse': 7} 'reverse': 7}
RESET = "\033[m" # pylint: disable=W1401 RESET = "\033[m" # pylint: disable=W1401
# backslash is not anomalous # backslash is not anomalous
def is_color(s): def is_color(s):
return s in COLORS return s in COLORS
def is_attr(s): def is_attr(s):
return s in ATTRS return s in ATTRS
def _Color(fg = None, bg = None, attr = None):
def _Color(fg=None, bg=None, attr=None):
fg = COLORS[fg] fg = COLORS[fg]
bg = COLORS[bg] bg = COLORS[bg]
attr = ATTRS[attr] attr = ATTRS[attr]
...@@ -122,20 +124,25 @@ class Coloring(object): ...@@ -122,20 +124,25 @@ class Coloring(object):
def printer(self, opt=None, fg=None, bg=None, attr=None): def printer(self, opt=None, fg=None, bg=None, attr=None):
s = self s = self
c = self.colorer(opt, fg, bg, attr) c = self.colorer(opt, fg, bg, attr)
def f(fmt, *args): def f(fmt, *args):
s._out.write(c(fmt, *args)) s._out.write(c(fmt, *args))
return f return f
def colorer(self, opt=None, fg=None, bg=None, attr=None): def colorer(self, opt=None, fg=None, bg=None, attr=None):
if self._on: if self._on:
c = self._parse(opt, fg, bg, attr) c = self._parse(opt, fg, bg, attr)
def f(fmt, *args): def f(fmt, *args):
output = fmt % args output = fmt % args
return ''.join([c, output, RESET]) return ''.join([c, output, RESET])
return f return f
else: else:
def f(fmt, *args): def f(fmt, *args):
return fmt % args return fmt % args
return f return f
def _parse(self, opt, fg, bg, attr): def _parse(self, opt, fg, bg, attr):
......
...@@ -22,6 +22,7 @@ import sys ...@@ -22,6 +22,7 @@ import sys
from error import NoSuchProjectError from error import NoSuchProjectError
from error import InvalidProjectGroupsError from error import InvalidProjectGroupsError
class Command(object): class Command(object):
"""Base class for any command line action in repo. """Base class for any command line action in repo.
""" """
...@@ -62,7 +63,7 @@ class Command(object): ...@@ -62,7 +63,7 @@ class Command(object):
usage = self.helpUsage.strip().replace('%prog', me) usage = self.helpUsage.strip().replace('%prog', me)
except AttributeError: except AttributeError:
usage = 'repo %s' % self.NAME usage = 'repo %s' % self.NAME
self._optparse = optparse.OptionParser(usage = usage) self._optparse = optparse.OptionParser(usage=usage)
self._Options(self._optparse) self._Options(self._optparse)
return self._optparse return self._optparse
...@@ -183,6 +184,7 @@ class Command(object): ...@@ -183,6 +184,7 @@ class Command(object):
def _getpath(x): def _getpath(x):
return x.relpath return x.relpath
result.sort(key=_getpath) result.sort(key=_getpath)
return result return result
...@@ -195,13 +197,16 @@ class InteractiveCommand(Command): ...@@ -195,13 +197,16 @@ class InteractiveCommand(Command):
"""Command which requires user interaction on the tty and """Command which requires user interaction on the tty and
must not run within a pager, even if the user asks to. must not run within a pager, even if the user asks to.
""" """
def WantPager(self, opt): def WantPager(self, opt):
return False return False
class PagedCommand(Command): class PagedCommand(Command):
"""Command which defaults to output in a pager, as its """Command which defaults to output in a pager, as its
display tends to be larger than one screen full. display tends to be larger than one screen full.
""" """
def WantPager(self, opt): def WantPager(self, opt):
return True return True
......
...@@ -22,6 +22,7 @@ import tempfile ...@@ -22,6 +22,7 @@ import tempfile
from error import EditorError from error import EditorError
class Editor(object): class Editor(object):
"""Manages the user's preferred text editor.""" """Manages the user's preferred text editor."""
...@@ -55,9 +56,9 @@ class Editor(object): ...@@ -55,9 +56,9 @@ class Editor(object):
if os.getenv('TERM') == 'dumb': if os.getenv('TERM') == 'dumb':
print( print(
"""No editor specified in GIT_EDITOR, core.editor, VISUAL or EDITOR. """No editor specified in GIT_EDITOR, core.editor, VISUAL or EDITOR.
Tried to fall back to vi but terminal is dumb. Please configure at Tried to fall back to vi but terminal is dumb. Please configure at
least one of these before using this command.""", file=sys.stderr) least one of these before using this command.""", file=sys.stderr)
sys.exit(1) sys.exit(1)
return 'vi' return 'vi'
......
...@@ -17,17 +17,21 @@ class ManifestParseError(Exception): ...@@ -17,17 +17,21 @@ class ManifestParseError(Exception):
"""Failed to parse the manifest file. """Failed to parse the manifest file.
""" """
class ManifestInvalidRevisionError(Exception): class ManifestInvalidRevisionError(Exception):
"""The revision value in a project is incorrect. """The revision value in a project is incorrect.
""" """
class NoManifestException(Exception): class NoManifestException(Exception):
"""The required manifest does not exist. """The required manifest does not exist.
""" """
class EditorError(Exception): class EditorError(Exception):
"""Unspecified error from the user's text editor. """Unspecified error from the user's text editor.
""" """
def __init__(self, reason): def __init__(self, reason):
super(EditorError, self).__init__() super(EditorError, self).__init__()
self.reason = reason self.reason = reason
...@@ -35,9 +39,11 @@ class EditorError(Exception): ...@@ -35,9 +39,11 @@ class EditorError(Exception):
def __str__(self): def __str__(self):
return self.reason return self.reason
class GitError(Exception): class GitError(Exception):
"""Unspecified internal error from git. """Unspecified internal error from git.
""" """
def __init__(self, command): def __init__(self, command):
super(GitError, self).__init__() super(GitError, self).__init__()
self.command = command self.command = command
...@@ -45,9 +51,11 @@ class GitError(Exception): ...@@ -45,9 +51,11 @@ class GitError(Exception):
def __str__(self): def __str__(self):
return self.command return self.command
class UploadError(Exception): class UploadError(Exception):
"""A bundle upload to Gerrit did not succeed. """A bundle upload to Gerrit did not succeed.
""" """
def __init__(self, reason): def __init__(self, reason):
super(UploadError, self).__init__() super(UploadError, self).__init__()
self.reason = reason self.reason = reason
...@@ -55,9 +63,11 @@ class UploadError(Exception): ...@@ -55,9 +63,11 @@ class UploadError(Exception):
def __str__(self): def __str__(self):
return self.reason return self.reason
class DownloadError(Exception): class DownloadError(Exception):
"""Cannot download a repository. """Cannot download a repository.
""" """
def __init__(self, reason): def __init__(self, reason):
super(DownloadError, self).__init__() super(DownloadError, self).__init__()
self.reason = reason self.reason = reason
...@@ -65,9 +75,11 @@ class DownloadError(Exception): ...@@ -65,9 +75,11 @@ class DownloadError(Exception):
def __str__(self): def __str__(self):
return self.reason return self.reason
class NoSuchProjectError(Exception): class NoSuchProjectError(Exception):
"""A specified project does not exist in the work tree. """A specified project does not exist in the work tree.
""" """
def __init__(self, name=None): def __init__(self, name=None):
super(NoSuchProjectError, self).__init__() super(NoSuchProjectError, self).__init__()
self.name = name self.name = name
...@@ -81,6 +93,7 @@ class NoSuchProjectError(Exception): ...@@ -81,6 +93,7 @@ class NoSuchProjectError(Exception):
class InvalidProjectGroupsError(Exception): class InvalidProjectGroupsError(Exception):
"""A specified project is not suitable for the specified groups """A specified project is not suitable for the specified groups
""" """
def __init__(self, name=None): def __init__(self, name=None):
super(InvalidProjectGroupsError, self).__init__() super(InvalidProjectGroupsError, self).__init__()
self.name = name self.name = name
...@@ -90,15 +103,18 @@ class InvalidProjectGroupsError(Exception): ...@@ -90,15 +103,18 @@ class InvalidProjectGroupsError(Exception):
return 'in current directory' return 'in current directory'
return self.name return self.name
class RepoChangedException(Exception): class RepoChangedException(Exception):
"""Thrown if 'repo sync' results in repo updating its internal """Thrown if 'repo sync' results in repo updating its internal
repo or manifest repositories. In this special case we must repo or manifest repositories. In this special case we must
use exec to re-execute repo with the new code and manifest. use exec to re-execute repo with the new code and manifest.
""" """
def __init__(self, extra_args=None): def __init__(self, extra_args=None):
super(RepoChangedException, self).__init__() super(RepoChangedException, self).__init__()
self.extra_args = extra_args or [] self.extra_args = extra_args or []
class HookError(Exception): class HookError(Exception):
"""Thrown if a 'repo-hook' could not be run. """Thrown if a 'repo-hook' could not be run.
......
...@@ -34,6 +34,7 @@ _ssh_proxy_path = None ...@@ -34,6 +34,7 @@ _ssh_proxy_path = None
_ssh_sock_path = None _ssh_sock_path = None
_ssh_clients = [] _ssh_clients = []
def ssh_sock(create=True): def ssh_sock(create=True):
global _ssh_sock_path global _ssh_sock_path
if _ssh_sock_path is None: if _ssh_sock_path is None:
...@@ -47,6 +48,7 @@ def ssh_sock(create=True): ...@@ -47,6 +48,7 @@ def ssh_sock(create=True):
'master-%r@%h:%p') 'master-%r@%h:%p')
return _ssh_sock_path return _ssh_sock_path
def _ssh_proxy(): def _ssh_proxy():
global _ssh_proxy_path global _ssh_proxy_path
if _ssh_proxy_path is None: if _ssh_proxy_path is None:
...@@ -55,15 +57,18 @@ def _ssh_proxy(): ...@@ -55,15 +57,18 @@ def _ssh_proxy():
'git_ssh') 'git_ssh')
return _ssh_proxy_path return _ssh_proxy_path
def _add_ssh_client(p): def _add_ssh_client(p):
_ssh_clients.append(p) _ssh_clients.append(p)
def _remove_ssh_client(p): def _remove_ssh_client(p):
try: try:
_ssh_clients.remove(p) _ssh_clients.remove(p)
except ValueError: except ValueError:
pass pass
def terminate_ssh_clients(): def terminate_ssh_clients():
global _ssh_clients global _ssh_clients
for p in _ssh_clients: for p in _ssh_clients:
...@@ -74,8 +79,10 @@ def terminate_ssh_clients(): ...@@ -74,8 +79,10 @@ def terminate_ssh_clients():
pass pass
_ssh_clients = [] _ssh_clients = []
_git_version = None _git_version = None
class _GitCall(object): class _GitCall(object):
def version(self): def version(self):
p = GitCommand(None, ['--version'], capture_stdout=True) p = GitCommand(None, ['--version'], capture_stdout=True)
...@@ -99,14 +106,19 @@ class _GitCall(object): ...@@ -99,14 +106,19 @@ class _GitCall(object):
return _git_version return _git_version
def __getattr__(self, name): def __getattr__(self, name):
name = name.replace('_','-') name = name.replace('_', '-')
def fun(*cmdv): def fun(*cmdv):
command = [name] command = [name]
command.extend(cmdv) command.extend(cmdv)
return GitCommand(None, command).Wait() == 0 return GitCommand(None, command).Wait() == 0
return fun return fun
git = _GitCall() git = _GitCall()
def git_require(min_version, fail=False): def git_require(min_version, fail=False):
git_version = git.version_tuple() git_version = git.version_tuple()
if min_version <= git_version: if min_version <= git_version:
...@@ -117,21 +129,23 @@ def git_require(min_version, fail=False): ...@@ -117,21 +129,23 @@ def git_require(min_version, fail=False):
sys.exit(1) sys.exit(1)
return False return False
def _setenv(env, name, value): def _setenv(env, name, value):
env[name] = value.encode(encoding='UTF-8') env[name] = value.encode(encoding='UTF-8')
class GitCommand(object): class GitCommand(object):
def __init__(self, def __init__(self,
project, project,
cmdv, cmdv,
bare = False, bare=False,
provide_stdin = False, provide_stdin=False,
capture_stdout = False, capture_stdout=False,
capture_stderr = False, capture_stderr=False,
disable_editor = False, disable_editor=False,
ssh_proxy = False, ssh_proxy=False,
cwd = None, cwd=None,
gitdir = None): gitdir=None):
env = os.environ.copy() env = os.environ.copy()
for key in [REPO_TRACE, for key in [REPO_TRACE,
...@@ -214,11 +228,11 @@ class GitCommand(object): ...@@ -214,11 +228,11 @@ class GitCommand(object):
try: try:
p = subprocess.Popen(command, p = subprocess.Popen(command,
cwd = cwd, cwd=cwd,
env = env, env=env,
stdin = stdin, stdin=stdin,
stdout = stdout, stdout=stdout,
stderr = stderr) stderr=stderr)
except Exception as e: except Exception as e:
raise GitError('%s: %s' % (command[1], e)) raise GitError('%s: %s' % (command[1], e))
......
...@@ -42,30 +42,33 @@ ID_RE = re.compile(r'^[0-9a-f]{40}$') ...@@ -42,30 +42,33 @@ ID_RE = re.compile(r'^[0-9a-f]{40}$')
REVIEW_CACHE = dict() REVIEW_CACHE = dict()
def IsId(rev): def IsId(rev):
return ID_RE.match(rev) return ID_RE.match(rev)
def _key(name): def _key(name):
parts = name.split('.') parts = name.split('.')
if len(parts) < 2: if len(parts) < 2:
return name.lower() return name.lower()
parts[ 0] = parts[ 0].lower() parts[0] = parts[0].lower()
parts[-1] = parts[-1].lower() parts[-1] = parts[-1].lower()
return '.'.join(parts) return '.'.join(parts)
class GitConfig(object): class GitConfig(object):
_ForUser = None _ForUser = None
@classmethod @classmethod
def ForUser(cls): def ForUser(cls):
if cls._ForUser is None: if cls._ForUser is None:
cls._ForUser = cls(configfile = os.path.expanduser('~/.gitconfig')) cls._ForUser = cls(configfile=os.path.expanduser('~/.gitconfig'))
return cls._ForUser return cls._ForUser
@classmethod @classmethod
def ForRepository(cls, gitdir, defaults=None): def ForRepository(cls, gitdir, defaults=None):
return cls(configfile = os.path.join(gitdir, 'config'), return cls(configfile=os.path.join(gitdir, 'config'),
defaults = defaults) defaults=defaults)
def __init__(self, configfile, defaults=None, pickleFile=None): def __init__(self, configfile, defaults=None, pickleFile=None):
self.file = configfile self.file = configfile
...@@ -82,13 +85,13 @@ class GitConfig(object): ...@@ -82,13 +85,13 @@ class GitConfig(object):
else: else:
self._pickle = pickleFile self._pickle = pickleFile
def Has(self, name, include_defaults = True): def Has(self, name, include_defaults=True):
"""Return true if this configuration file has the key. """Return true if this configuration file has the key.
""" """
if _key(name) in self._cache: if _key(name) in self._cache:
return True return True
if include_defaults and self.defaults: if include_defaults and self.defaults:
return self.defaults.Has(name, include_defaults = True) return self.defaults.Has(name, include_defaults=True)
return False return False
def GetBoolean(self, name): def GetBoolean(self, name):
...@@ -117,7 +120,7 @@ class GitConfig(object): ...@@ -117,7 +120,7 @@ class GitConfig(object):
v = self._cache[_key(name)] v = self._cache[_key(name)]
except KeyError: except KeyError:
if self.defaults: if self.defaults:
return self.defaults.GetString(name, all_keys = all_keys) return self.defaults.GetString(name, all_keys=all_keys)
v = [] v = []
if not all_keys: if not all_keys:
...@@ -128,7 +131,7 @@ class GitConfig(object): ...@@ -128,7 +131,7 @@ class GitConfig(object):
r = [] r = []
r.extend(v) r.extend(v)
if self.defaults: if self.defaults:
r.extend(self.defaults.GetString(name, all_keys = True)) r.extend(self.defaults.GetString(name, all_keys=True))
return r return r
def SetString(self, name, value): def SetString(self, name, value):
...@@ -192,7 +195,7 @@ class GitConfig(object): ...@@ -192,7 +195,7 @@ class GitConfig(object):
""" """
return self._sections.get(section, set()) return self._sections.get(section, set())
def HasSection(self, section, subsection = ''): def HasSection(self, section, subsection=''):
"""Does at least one key in section.subsection exist? """Does at least one key in section.subsection exist?
""" """
try: try:
...@@ -312,8 +315,8 @@ class GitConfig(object): ...@@ -312,8 +315,8 @@ class GitConfig(object):
p = GitCommand(None, p = GitCommand(None,
command, command,
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
if p.Wait() == 0: if p.Wait() == 0:
return portable.stream2str(p.stdout) return portable.stream2str(p.stdout)
else: else:
...@@ -381,6 +384,7 @@ _master_keys = set() ...@@ -381,6 +384,7 @@ _master_keys = set()
_ssh_master = True _ssh_master = True
_master_keys_lock = None _master_keys_lock = None
def init_ssh(): def init_ssh():
"""Should be called once at the start of repo to init ssh master handling. """Should be called once at the start of repo to init ssh master handling.
...@@ -390,6 +394,7 @@ def init_ssh(): ...@@ -390,6 +394,7 @@ def init_ssh():
assert _master_keys_lock is None, "Should only call init_ssh once" assert _master_keys_lock is None, "Should only call init_ssh once"
_master_keys_lock = _threading.Lock() _master_keys_lock = _threading.Lock()
def _open_ssh(host, port=None): def _open_ssh(host, port=None):
global _ssh_master global _ssh_master
...@@ -419,7 +424,7 @@ def _open_ssh(host, port=None): ...@@ -419,7 +424,7 @@ def _open_ssh(host, port=None):
# We will make two calls to ssh; this is the common part of both calls. # We will make two calls to ssh; this is the common part of both calls.
command_base = ['ssh', command_base = ['ssh',
'-o','ControlPath %s' % ssh_sock(), '-o', 'ControlPath %s' % ssh_sock(),
host] host]
if port is not None: if port is not None:
command_base[1:1] = ['-p', str(port)] command_base[1:1] = ['-p', str(port)]
...@@ -428,7 +433,7 @@ def _open_ssh(host, port=None): ...@@ -428,7 +433,7 @@ def _open_ssh(host, port=None):
# ...but before actually starting a master, we'll double-check. This can # ...but before actually starting a master, we'll double-check. This can
# be important because we can't tell that that 'git@myhost.com' is the same # be important because we can't tell that that 'git@myhost.com' is the same
# as 'myhost.com' where "User git" is setup in the user's ~/.ssh/config file. # as 'myhost.com' where "User git" is setup in the user's ~/.ssh/config file.
check_command = command_base + ['-O','check'] check_command = command_base + ['-O', 'check']
try: try:
Trace(': %s', ' '.join(check_command)) Trace(': %s', ' '.join(check_command))
check_process = subprocess.Popen(check_command, check_process = subprocess.Popen(check_command,
...@@ -456,7 +461,7 @@ def _open_ssh(host, port=None): ...@@ -456,7 +461,7 @@ def _open_ssh(host, port=None):
except Exception as e: except Exception as e:
_ssh_master = False _ssh_master = False
print('\nwarn: cannot enable ssh control master for %s:%s\n%s' print('\nwarn: cannot enable ssh control master for %s:%s\n%s'
% (host,port, str(e)), file=sys.stderr) % (host, port, str(e)), file=sys.stderr)
return False return False
_master_processes.append(p) _master_processes.append(p)
...@@ -466,6 +471,7 @@ def _open_ssh(host, port=None): ...@@ -466,6 +471,7 @@ def _open_ssh(host, port=None):
finally: finally:
_master_keys_lock.release() _master_keys_lock.release()
def close_ssh(): def close_ssh():
global _master_keys_lock global _master_keys_lock
...@@ -490,15 +496,18 @@ def close_ssh(): ...@@ -490,15 +496,18 @@ def close_ssh():
# We're done with the lock, so we can delete it. # We're done with the lock, so we can delete it.
_master_keys_lock = None _master_keys_lock = None
URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):') URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):')
URI_ALL = re.compile(r'^([a-z][a-z+-]*)://([^@/]*@?[^/]*)/') URI_ALL = re.compile(r'^([a-z][a-z+-]*)://([^@/]*@?[^/]*)/')
def GetSchemeFromUrl(url): def GetSchemeFromUrl(url):
m = URI_ALL.match(url) m = URI_ALL.match(url)
if m: if m:
return m.group(1) return m.group(1)
return None return None
def _preconnect(url): def _preconnect(url):
m = URI_ALL.match(url) m = URI_ALL.match(url)
if m: if m:
...@@ -519,9 +528,11 @@ def _preconnect(url): ...@@ -519,9 +528,11 @@ def _preconnect(url):
return False return False
class Remote(object): class Remote(object):
"""Configuration options related to a remote. """Configuration options related to a remote.
""" """
def __init__(self, config, name): def __init__(self, config, name):
self._config = config self._config = config
self.name = name self.name = name
...@@ -599,7 +610,9 @@ class Remote(object): ...@@ -599,7 +610,9 @@ class Remote(object):
if info == 'NOT_AVAILABLE': if info == 'NOT_AVAILABLE':
# Assume HTTP if SSH is not enabled. # Assume HTTP if SSH is not enabled.
self._review_url = http_url + 'p/' self._review_url = http_url + 'p/'
Trace("warning: proceed upload with http url %s since no protocol given and no infos could be retrieved from %s", self._review_url, info_url) Trace(
"warning: proceed upload with http url %s since no protocol given and no infos could be retrieved from %s",
self._review_url, info_url)
else: else:
host, port = info.split() host, port = info.split()
self._review_url = self._SshReviewUrl(userEmail, host, port) self._review_url = self._SshReviewUrl(userEmail, host, port)
...@@ -666,12 +679,13 @@ class Remote(object): ...@@ -666,12 +679,13 @@ class Remote(object):
def _Get(self, key, all_keys=False): def _Get(self, key, all_keys=False):
key = 'remote.%s.%s' % (self.name, key) key = 'remote.%s.%s' % (self.name, key)
return self._config.GetString(key, all_keys = all_keys) return self._config.GetString(key, all_keys=all_keys)
class Branch(object): class Branch(object):
"""Configuration options related to a single branch. """Configuration options related to a single branch.
""" """
def __init__(self, config, name): def __init__(self, config, name):
self._config = config self._config = config
self.name = name self.name = name
...@@ -718,4 +732,4 @@ class Branch(object): ...@@ -718,4 +732,4 @@ class Branch(object):
def _Get(self, key, all_keys=False): def _Get(self, key, all_keys=False):
key = 'branch.%s.%s' % (self.name, key) key = 'branch.%s.%s' % (self.name, key)
return self._config.GetString(key, all_keys = all_keys) return self._config.GetString(key, all_keys=all_keys)
...@@ -49,7 +49,8 @@ from subcmds import all_commands ...@@ -49,7 +49,8 @@ from subcmds import all_commands
from repo_trace import REPO_TRACE, IsTrace, Trace from repo_trace import REPO_TRACE, IsTrace, Trace
global_options = optparse.OptionParser(usage="repo [-p|--paginate|--no-pager|--piped-into-less|--debug|--debug-host|--debug-env] COMMAND [ARGS]") global_options = optparse.OptionParser(
usage="repo [-p|--paginate|--no-pager|--piped-into-less|--debug|--debug-host|--debug-env] COMMAND [ARGS]")
global_options.add_option('-p', '--paginate', global_options.add_option('-p', '--paginate',
dest='pager', action='store_true', dest='pager', action='store_true',
help='display command output in the pager') help='display command output in the pager')
...@@ -84,6 +85,7 @@ def _UsePager(name, cmd, gopts, copts): ...@@ -84,6 +85,7 @@ def _UsePager(name, cmd, gopts, copts):
else: else:
return False return False
class _Repo(object): class _Repo(object):
def __init__(self, repodir): def __init__(self, repodir):
self.repodir = repodir self.repodir = repodir
...@@ -183,22 +185,29 @@ class _Repo(object): ...@@ -183,22 +185,29 @@ class _Repo(object):
return result return result
def _MyRepoPath(): def _MyRepoPath():
return os.path.dirname(__file__) return os.path.dirname(__file__)
def _MyWrapperPath(): def _MyWrapperPath():
return os.path.join(os.path.dirname(__file__), 'repo') return os.path.join(os.path.dirname(__file__), 'repo')
_wrapper_module = None _wrapper_module = None
def WrapperModule(): def WrapperModule():
global _wrapper_module global _wrapper_module
if not _wrapper_module: if not _wrapper_module:
_wrapper_module = imp.load_source('wrapper', _MyWrapperPath()) _wrapper_module = imp.load_source('wrapper', _MyWrapperPath())
return _wrapper_module return _wrapper_module
def _CurrentWrapperVersion(): def _CurrentWrapperVersion():
return WrapperModule().VERSION return WrapperModule().VERSION
def _CheckWrapperVersion(ver, repo_path): def _CheckWrapperVersion(ver, repo_path):
if not repo_path: if not repo_path:
repo_path = '~/bin/repo' repo_path = '~/bin/repo'
...@@ -230,11 +239,13 @@ def _CheckWrapperVersion(ver, repo_path): ...@@ -230,11 +239,13 @@ def _CheckWrapperVersion(ver, repo_path):
cp %s %s cp %s %s
""" % (exp_str, _MyWrapperPath(), repo_path), file=sys.stderr) """ % (exp_str, _MyWrapperPath(), repo_path), file=sys.stderr)
def _CheckRepoDir(repo_dir): def _CheckRepoDir(repo_dir):
if not repo_dir: if not repo_dir:
print('no --repo-dir argument', file=sys.stderr) print('no --repo-dir argument', file=sys.stderr)
sys.exit(1) sys.exit(1)
def _PruneOptions(argv, opt): def _PruneOptions(argv, opt):
i = 0 i = 0
while i < len(argv): while i < len(argv):
...@@ -250,8 +261,10 @@ def _PruneOptions(argv, opt): ...@@ -250,8 +261,10 @@ def _PruneOptions(argv, opt):
continue continue
i += 1 i += 1
_user_agent = None _user_agent = None
def _UserAgent(): def _UserAgent():
global _user_agent global _user_agent
...@@ -270,8 +283,8 @@ def _UserAgent(): ...@@ -270,8 +283,8 @@ def _UserAgent():
p = GitCommand( p = GitCommand(
None, ['describe', 'HEAD'], None, ['describe', 'HEAD'],
cwd = _MyRepoPath(), cwd=_MyRepoPath(),
capture_stdout = True) capture_stdout=True)
if p.Wait() == 0: if p.Wait() == 0:
repo_version = p.stdout repo_version = p.stdout
if len(repo_version) > 0 and repo_version[-1] == '\n': if len(repo_version) > 0 and repo_version[-1] == '\n':
...@@ -288,6 +301,7 @@ def _UserAgent(): ...@@ -288,6 +301,7 @@ def _UserAgent():
py_version[0], py_version[1], py_version[2]) py_version[0], py_version[1], py_version[2])
return _user_agent return _user_agent
class _UserAgentHandler(urllib.request.BaseHandler): class _UserAgentHandler(urllib.request.BaseHandler):
def http_request(self, req): def http_request(self, req):
req.add_header('User-Agent', _UserAgent()) req.add_header('User-Agent', _UserAgent())
...@@ -297,6 +311,7 @@ class _UserAgentHandler(urllib.request.BaseHandler): ...@@ -297,6 +311,7 @@ class _UserAgentHandler(urllib.request.BaseHandler):
req.add_header('User-Agent', _UserAgent()) req.add_header('User-Agent', _UserAgent())
return req return req
def _AddPasswordFromUserInput(handler, msg, req): def _AddPasswordFromUserInput(handler, msg, req):
# If repo could not find auth info from netrc, try to get it from user input # If repo could not find auth info from netrc, try to get it from user input
url = req.get_full_url() url = req.get_full_url()
...@@ -310,6 +325,7 @@ def _AddPasswordFromUserInput(handler, msg, req): ...@@ -310,6 +325,7 @@ def _AddPasswordFromUserInput(handler, msg, req):
return return
handler.passwd.add_password(None, url, user, password) handler.passwd.add_password(None, url, user, password)
class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler): class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
def http_error_401(self, req, fp, code, msg, headers): def http_error_401(self, req, fp, code, msg, headers):
_AddPasswordFromUserInput(self, msg, req) _AddPasswordFromUserInput(self, msg, req)
...@@ -319,9 +335,11 @@ class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler): ...@@ -319,9 +335,11 @@ class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
def http_error_auth_reqed(self, authreq, host, req, headers): def http_error_auth_reqed(self, authreq, host, req, headers):
try: try:
old_add_header = req.add_header old_add_header = req.add_header
def _add_header(name, val): def _add_header(name, val):
val = val.replace('\n', '') val = val.replace('\n', '')
old_add_header(name, val) old_add_header(name, val)
req.add_header = _add_header req.add_header = _add_header
return urllib.request.AbstractBasicAuthHandler.http_error_auth_reqed( return urllib.request.AbstractBasicAuthHandler.http_error_auth_reqed(
self, authreq, host, req, headers) self, authreq, host, req, headers)
...@@ -333,6 +351,7 @@ class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler): ...@@ -333,6 +351,7 @@ class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
self.retried = 0 self.retried = 0
raise raise
class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler): class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
def http_error_401(self, req, fp, code, msg, headers): def http_error_401(self, req, fp, code, msg, headers):
_AddPasswordFromUserInput(self, msg, req) _AddPasswordFromUserInput(self, msg, req)
...@@ -342,9 +361,11 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler): ...@@ -342,9 +361,11 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
def http_error_auth_reqed(self, auth_header, host, req, headers): def http_error_auth_reqed(self, auth_header, host, req, headers):
try: try:
old_add_header = req.add_header old_add_header = req.add_header
def _add_header(name, val): def _add_header(name, val):
val = val.replace('\n', '') val = val.replace('\n', '')
old_add_header(name, val) old_add_header(name, val)
req.add_header = _add_header req.add_header = _add_header
return urllib.request.AbstractDigestAuthHandler.http_error_auth_reqed( return urllib.request.AbstractDigestAuthHandler.http_error_auth_reqed(
self, auth_header, host, req, headers) self, auth_header, host, req, headers)
...@@ -356,6 +377,7 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler): ...@@ -356,6 +377,7 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
self.retried = 0 self.retried = 0
raise raise
def init_http(): def init_http():
handlers = [_UserAgentHandler()] handlers = [_UserAgentHandler()]
...@@ -418,7 +440,7 @@ def _WindowsPager(repo): ...@@ -418,7 +440,7 @@ def _WindowsPager(repo):
args = sys.argv[1:] args = sys.argv[1:]
argsSplit = args.index('--') argsSplit = args.index('--')
args1 = args[:argsSplit] args1 = args[:argsSplit]
args2 = args[argsSplit+1:] args2 = args[argsSplit + 1:]
pager = _SelectPager(cmd.manifest.globalConfig) pager = _SelectPager(cmd.manifest.globalConfig)
shellCommand = [python, thisScript] + args1 + ['--', '--piped-into-pager', '--no-pager'] + args2 + ['|', pager] shellCommand = [python, thisScript] + args1 + ['--', '--piped-into-pager', '--no-pager'] + args2 + ['|', pager]
if IsTrace(): if IsTrace():
...@@ -429,10 +451,12 @@ def _WindowsPager(repo): ...@@ -429,10 +451,12 @@ def _WindowsPager(repo):
# set global variable if output is piped into pager; means that pager is simulated, this # set global variable if output is piped into pager; means that pager is simulated, this
# leads to correct coloring in windows # leads to correct coloring in windows
import pager import pager
pager.active = gopts.pipedIntoPager pager.active = gopts.pipedIntoPager
return False return False
def _Main(argv): def _Main(argv):
result = 0 result = 0
...@@ -500,6 +524,7 @@ def _Main(argv): ...@@ -500,6 +524,7 @@ def _Main(argv):
return result return result
if __name__ == '__main__': if __name__ == '__main__':
result = _Main(sys.argv[1:]) result = _Main(sys.argv[1:])
sys.exit(result) sys.exit(result)
...@@ -35,6 +35,7 @@ LOCAL_MANIFESTS_DIR_NAME = 'local_manifests' ...@@ -35,6 +35,7 @@ LOCAL_MANIFESTS_DIR_NAME = 'local_manifests'
urllib.parse.uses_relative.extend(['ssh', 'git']) urllib.parse.uses_relative.extend(['ssh', 'git'])
urllib.parse.uses_netloc.extend(['ssh', 'git']) urllib.parse.uses_netloc.extend(['ssh', 'git'])
class _Default(object): class _Default(object):
"""Project defaults within the manifest.""" """Project defaults within the manifest."""
...@@ -44,6 +45,7 @@ class _Default(object): ...@@ -44,6 +45,7 @@ class _Default(object):
sync_c = False sync_c = False
sync_s = False sync_s = False
class _XmlRemote(object): class _XmlRemote(object):
def __init__(self, def __init__(self,
name, name,
...@@ -88,6 +90,7 @@ class _XmlRemote(object): ...@@ -88,6 +90,7 @@ class _XmlRemote(object):
remoteName = self.remoteAlias remoteName = self.remoteAlias
return RemoteSpec(remoteName, url, self.reviewUrl) return RemoteSpec(remoteName, url, self.reviewUrl)
class XmlManifest(object): class XmlManifest(object):
"""manages the repo configuration file""" """manages the repo configuration file"""
...@@ -98,12 +101,12 @@ class XmlManifest(object): ...@@ -98,12 +101,12 @@ class XmlManifest(object):
self.globalConfig = GitConfig.ForUser() self.globalConfig = GitConfig.ForUser()
self.repoProject = MetaProject(self, 'repo', self.repoProject = MetaProject(self, 'repo',
gitdir = os.path.join(repodir, 'repo/.git'), gitdir=os.path.join(repodir, 'repo/.git'),
worktree = os.path.join(repodir, 'repo')) worktree=os.path.join(repodir, 'repo'))
self.manifestProject = MetaProject(self, 'manifests', self.manifestProject = MetaProject(self, 'manifests',
gitdir = os.path.join(repodir, 'manifests.git'), gitdir=os.path.join(repodir, 'manifests.git'),
worktree = os.path.join(repodir, 'manifests')) worktree=os.path.join(repodir, 'manifests'))
self._Unload() self._Unload()
...@@ -162,7 +165,7 @@ class XmlManifest(object): ...@@ -162,7 +165,7 @@ class XmlManifest(object):
if self.notice: if self.notice:
notice_element = root.appendChild(doc.createElement('notice')) notice_element = root.appendChild(doc.createElement('notice'))
notice_lines = self.notice.splitlines() notice_lines = self.notice.splitlines()
indented_notice = ('\n'.join(" "*4 + line for line in notice_lines))[4:] indented_notice = ('\n'.join(" " * 4 + line for line in notice_lines))[4:]
notice_element.appendChild(doc.createTextNode(indented_notice)) notice_element.appendChild(doc.createTextNode(indented_notice))
d = self.default d = self.default
...@@ -391,7 +394,7 @@ class XmlManifest(object): ...@@ -391,7 +394,7 @@ class XmlManifest(object):
name = self._reqatt(node, 'name') name = self._reqatt(node, 'name')
fp = os.path.join(include_root, name) fp = os.path.join(include_root, name)
if not os.path.isfile(fp): if not os.path.isfile(fp):
raise ManifestParseError(\ raise ManifestParseError( \
"include %s doesn't exist or isn't a file" % \ "include %s doesn't exist or isn't a file" % \
(name,)) (name,))
try: try:
...@@ -521,14 +524,14 @@ class XmlManifest(object): ...@@ -521,14 +524,14 @@ class XmlManifest(object):
if name not in self._projects: if name not in self._projects:
m.PreSync() m.PreSync()
gitdir = os.path.join(self.topdir, '%s.git' % name) gitdir = os.path.join(self.topdir, '%s.git' % name)
project = Project(manifest = self, project = Project(manifest=self,
name = name, name=name,
remote = remote.ToRemoteSpec(name), remote=remote.ToRemoteSpec(name),
gitdir = gitdir, gitdir=gitdir,
worktree = None, worktree=None,
relpath = None, relpath=None,
revisionExpr = m.revisionExpr, revisionExpr=m.revisionExpr,
revisionId = None) revisionId=None)
self._projects[project.name] = project self._projects[project.name] = project
def _ParseRemote(self, node): def _ParseRemote(self, node):
...@@ -620,7 +623,7 @@ class XmlManifest(object): ...@@ -620,7 +623,7 @@ class XmlManifest(object):
def _UnjoinName(self, parent_name, name): def _UnjoinName(self, parent_name, name):
return os.path.relpath(name, parent_name) return os.path.relpath(name, parent_name)
def _ParseProject(self, node, parent = None): def _ParseProject(self, node, parent=None):
""" """
reads a <project> element from the manifest file reads a <project> element from the manifest file
""" """
...@@ -632,7 +635,7 @@ class XmlManifest(object): ...@@ -632,7 +635,7 @@ class XmlManifest(object):
if remote is None: if remote is None:
remote = self._default.remote remote = self._default.remote
if remote is None: if remote is None:
raise ManifestParseError(\ raise ManifestParseError( \
"no remote for project %s within %s" % \ "no remote for project %s within %s" % \
(name, self.manifestFile)) (name, self.manifestFile))
...@@ -640,7 +643,7 @@ class XmlManifest(object): ...@@ -640,7 +643,7 @@ class XmlManifest(object):
if not revisionExpr: if not revisionExpr:
revisionExpr = self._default.revisionExpr revisionExpr = self._default.revisionExpr
if not revisionExpr: if not revisionExpr:
raise ManifestParseError(\ raise ManifestParseError( \
"no revision for project %s within %s" % \ "no revision for project %s within %s" % \
(name, self.manifestFile)) (name, self.manifestFile))
...@@ -648,7 +651,7 @@ class XmlManifest(object): ...@@ -648,7 +651,7 @@ class XmlManifest(object):
if not path: if not path:
path = name path = name
if path.startswith('/'): if path.startswith('/'):
raise ManifestParseError(\ raise ManifestParseError( \
"project %s path cannot be absolute in %s" % \ "project %s path cannot be absolute in %s" % \
(name, self.manifestFile)) (name, self.manifestFile))
...@@ -685,20 +688,20 @@ class XmlManifest(object): ...@@ -685,20 +688,20 @@ class XmlManifest(object):
default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath] default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath]
groups.extend(set(default_groups).difference(groups)) groups.extend(set(default_groups).difference(groups))
project = Project(manifest = self, project = Project(manifest=self,
name = name, name=name,
remote = remote.ToRemoteSpec(name), remote=remote.ToRemoteSpec(name),
gitdir = gitdir, gitdir=gitdir,
worktree = worktree, worktree=worktree,
relpath = relpath, relpath=relpath,
revisionExpr = revisionExpr, revisionExpr=revisionExpr,
revisionId = None, revisionId=None,
rebase = rebase, rebase=rebase,
groups = groups, groups=groups,
sync_c = sync_c, sync_c=sync_c,
sync_s = sync_s, sync_s=sync_s,
upstream = upstream, upstream=upstream,
parent = parent) parent=parent)
for n in node.childNodes: for n in node.childNodes:
if n.nodeName == 'copyfile': if n.nodeName == 'copyfile':
...@@ -706,7 +709,7 @@ class XmlManifest(object): ...@@ -706,7 +709,7 @@ class XmlManifest(object):
if n.nodeName == 'annotation': if n.nodeName == 'annotation':
self._ParseAnnotation(project, n) self._ParseAnnotation(project, n)
if n.nodeName == 'project': if n.nodeName == 'project':
project.subprojects.append(self._ParseProject(n, parent = project)) project.subprojects.append(self._ParseProject(n, parent=project))
return project return project
...@@ -764,7 +767,7 @@ class XmlManifest(object): ...@@ -764,7 +767,7 @@ class XmlManifest(object):
v = self._remotes.get(name) v = self._remotes.get(name)
if not v: if not v:
raise ManifestParseError(\ raise ManifestParseError( \
"remote %s not defined in %s" % \ "remote %s not defined in %s" % \
(name, self.manifestFile)) (name, self.manifestFile))
return v return v
...@@ -775,7 +778,7 @@ class XmlManifest(object): ...@@ -775,7 +778,7 @@ class XmlManifest(object):
""" """
v = node.getAttribute(attname) v = node.getAttribute(attname)
if not v: if not v:
raise ManifestParseError(\ raise ManifestParseError( \
"no %s in <%s> within %s" % \ "no %s in <%s> within %s" % \
(attname, node.nodeName, self.manifestFile)) (attname, node.nodeName, self.manifestFile))
return v return v
...@@ -20,6 +20,7 @@ import sys ...@@ -20,6 +20,7 @@ import sys
active = False active = False
def RunPager(globalConfig): def RunPager(globalConfig):
global active global active
...@@ -53,6 +54,7 @@ def RunPager(globalConfig): ...@@ -53,6 +54,7 @@ def RunPager(globalConfig):
print("fatal: cannot start pager '%s'" % pager, file=sys.stderr) print("fatal: cannot start pager '%s'" % pager, file=sys.stderr)
sys.exit(255) sys.exit(255)
def _SelectPager(globalConfig): def _SelectPager(globalConfig):
try: try:
return os.environ['GIT_PAGER'] return os.environ['GIT_PAGER']
...@@ -70,6 +72,7 @@ def _SelectPager(globalConfig): ...@@ -70,6 +72,7 @@ def _SelectPager(globalConfig):
return 'less' return 'less'
def _BecomePager(pager): def _BecomePager(pager):
# Delaying execution of the pager until we have output # Delaying execution of the pager until we have output
# ready works around a long-standing bug in popularly # ready works around a long-standing bug in popularly
......
...@@ -14,21 +14,25 @@ from repo_trace import REPO_TRACE, IsTrace, Trace ...@@ -14,21 +14,25 @@ from repo_trace import REPO_TRACE, IsTrace, Trace
SUBPROCESSES = [] SUBPROCESSES = []
def terminateHandle(signal, frame): def terminateHandle(signal, frame):
for cmd in SUBPROCESSES: for cmd in SUBPROCESSES:
if cmd: if cmd:
cmd.terminate() cmd.terminate()
sys.exit(0) sys.exit(0)
def stream2str(stream): def stream2str(stream):
return str(stream, encoding='UTF-8') return str(stream, encoding='UTF-8')
def isUnix(): def isUnix():
if platform.system() == "Windows": if platform.system() == "Windows":
return False return False
else: else:
return True return True
def isPosix(): def isPosix():
return platform.system() != "Windows" return platform.system() != "Windows"
...@@ -36,6 +40,7 @@ def isPosix(): ...@@ -36,6 +40,7 @@ def isPosix():
def toUnixPath(path): def toUnixPath(path):
return path.replace('\\', '/') return path.replace('\\', '/')
def toWindowsPath(path): def toWindowsPath(path):
return path.replace('/', '\\') return path.replace('/', '\\')
...@@ -63,9 +68,11 @@ def os_link(src, dst): ...@@ -63,9 +68,11 @@ def os_link(src, dst):
Trace(cmd) Trace(cmd)
subprocess.Popen(cmd, stdout=subprocess.PIPE).wait() subprocess.Popen(cmd, stdout=subprocess.PIPE).wait()
def removeReadOnlyFilesHandler(fn, path, excinfo): def removeReadOnlyFilesHandler(fn, path, excinfo):
removeReadOnlyFiles(fn, path) removeReadOnlyFiles(fn, path)
def removeReadOnlyFiles(fn, path): def removeReadOnlyFiles(fn, path):
if not os.access(path, os.W_OK): if not os.access(path, os.W_OK):
os.chmod(path, stat.S_IWUSR) os.chmod(path, stat.S_IWUSR)
......
...@@ -20,6 +20,7 @@ from repo_trace import IsTrace ...@@ -20,6 +20,7 @@ from repo_trace import IsTrace
_NOT_TTY = not os.isatty(2) _NOT_TTY = not os.isatty(2)
class Progress(object): class Progress(object):
def __init__(self, title, total=0, units=''): def __init__(self, title, total=0, units=''):
self._title = title self._title = title
......
...@@ -37,6 +37,7 @@ from repo_trace import IsTrace, Trace ...@@ -37,6 +37,7 @@ from repo_trace import IsTrace, Trace
from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M
import portable import portable
def _lwrite(path, content): def _lwrite(path, content):
lock = '%s.lock' % path lock = '%s.lock' % path
...@@ -52,17 +53,23 @@ def _lwrite(path, content): ...@@ -52,17 +53,23 @@ def _lwrite(path, content):
os.remove(lock) os.remove(lock)
raise raise
def _error(fmt, *args): def _error(fmt, *args):
msg = fmt % args msg = fmt % args
print('error in project: %s' % msg, file=sys.stderr) print('error in project: %s' % msg, file=sys.stderr)
def not_rev(r): def not_rev(r):
return '^' + r return '^' + r
def sq(r): def sq(r):
return "'" + r.replace("'", "'\''") + "'" return "'" + r.replace("'", "'\''") + "'"
_project_hook_list = None _project_hook_list = None
def _ProjectHooks(): def _ProjectHooks():
"""List the hooks present in the 'hooks' directory. """List the hooks present in the 'hooks' directory.
...@@ -78,7 +85,7 @@ def _ProjectHooks(): ...@@ -78,7 +85,7 @@ def _ProjectHooks():
global _project_hook_list global _project_hook_list
if _project_hook_list is None: if _project_hook_list is None:
d = os.path.abspath(os.path.dirname(__file__)) d = os.path.abspath(os.path.dirname(__file__))
d = os.path.join(d , 'hooks') d = os.path.join(d, 'hooks')
_project_hook_list = [os.path.join(d, x) for x in os.listdir(d)] _project_hook_list = [os.path.join(d, x) for x in os.listdir(d)]
return _project_hook_list return _project_hook_list
...@@ -172,23 +179,25 @@ class ReviewableBranch(object): ...@@ -172,23 +179,25 @@ class ReviewableBranch(object):
return refs return refs
class StatusColoring(Coloring): class StatusColoring(Coloring):
def __init__(self, config): def __init__(self, config):
Coloring.__init__(self, config, 'status') Coloring.__init__(self, config, 'status')
self.project = self.printer('header', attr = 'bold') self.project = self.printer('header', attr='bold')
self.branch = self.printer('header', attr = 'bold') self.branch = self.printer('header', attr='bold')
self.nobranch = self.printer('nobranch', fg = 'red') self.nobranch = self.printer('nobranch', fg='red')
self.important = self.printer('important', fg = 'red') self.important = self.printer('important', fg='red')
self.added = self.printer('added', fg = 'green') self.added = self.printer('added', fg='green')
self.changed = self.printer('changed', fg = 'red') self.changed = self.printer('changed', fg='red')
self.untracked = self.printer('untracked', fg = 'red') self.untracked = self.printer('untracked', fg='red')
class DiffColoring(Coloring): class DiffColoring(Coloring):
def __init__(self, config): def __init__(self, config):
Coloring.__init__(self, config, 'diff') Coloring.__init__(self, config, 'diff')
self.project = self.printer('header', attr = 'bold') self.project = self.printer('header', attr='bold')
class _Annotation: class _Annotation:
def __init__(self, name, value, keep): def __init__(self, name, value, keep):
...@@ -196,6 +205,7 @@ class _Annotation: ...@@ -196,6 +205,7 @@ class _Annotation:
self.value = value self.value = value
self.keep = keep self.keep = keep
class _CopyFile: class _CopyFile:
def __init__(self, src, dest, abssrc, absdest): def __init__(self, src, dest, abssrc, absdest):
self.src = src self.src = src
...@@ -224,15 +234,17 @@ class _CopyFile: ...@@ -224,15 +234,17 @@ class _CopyFile:
except IOError: except IOError:
_error('Cannot copy file %s to %s', src, dest) _error('Cannot copy file %s to %s', src, dest)
class RemoteSpec(object): class RemoteSpec(object):
def __init__(self, def __init__(self,
name, name,
url = None, url=None,
review = None): review=None):
self.name = name self.name = name
self.url = url self.url = url
self.review = review self.review = review
class RepoHook(object): class RepoHook(object):
"""A RepoHook contains information about a script to run as a hook. """A RepoHook contains information about a script to run as a hook.
...@@ -246,6 +258,7 @@ class RepoHook(object): ...@@ -246,6 +258,7 @@ class RepoHook(object):
Hooks are always python. When a hook is run, we will load the hook into the Hooks are always python. When a hook is run, we will load the hook into the
interpreter and execute its main() function. interpreter and execute its main() function.
""" """
def __init__(self, def __init__(self,
hook_type, hook_type,
hooks_project, hooks_project,
...@@ -485,13 +498,13 @@ class Project(object): ...@@ -485,13 +498,13 @@ class Project(object):
relpath, relpath,
revisionExpr, revisionExpr,
revisionId, revisionId,
rebase = True, rebase=True,
groups = None, groups=None,
sync_c = False, sync_c=False,
sync_s = False, sync_s=False,
upstream = None, upstream=None,
parent = None, parent=None,
is_derived = False): is_derived=False):
"""Init a Project object. """Init a Project object.
Args: Args:
...@@ -543,8 +556,8 @@ class Project(object): ...@@ -543,8 +556,8 @@ class Project(object):
self.copyfiles = [] self.copyfiles = []
self.annotations = [] self.annotations = []
self.config = GitConfig.ForRepository( self.config = GitConfig.ForRepository(
gitdir = self.gitdir, gitdir=self.gitdir,
defaults = self.manifest.globalConfig) defaults=self.manifest.globalConfig)
if self.worktree: if self.worktree:
self.work_git = self._GitGetByExec(self, bare=False) self.work_git = self._GitGetByExec(self, bare=False)
...@@ -686,7 +699,7 @@ class Project(object): ...@@ -686,7 +699,7 @@ class Project(object):
return matched return matched
## Status Display ## ## Status Display ##
def HasChanges(self): def HasChanges(self):
"""Returns true if there are uncommitted changes. """Returns true if there are uncommitted changes.
...@@ -811,8 +824,8 @@ class Project(object): ...@@ -811,8 +824,8 @@ class Project(object):
cmd.append('--') cmd.append('--')
p = GitCommand(self, p = GitCommand(self,
cmd, cmd,
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
has_diff = False has_diff = False
for line in p.process.stdout: for line in p.process.stdout:
if not has_diff: if not has_diff:
...@@ -824,7 +837,7 @@ class Project(object): ...@@ -824,7 +837,7 @@ class Project(object):
p.Wait() p.Wait()
## Publish / Upload ## ## Publish / Upload ##
def WasPublished(self, branch, all_refs=None): def WasPublished(self, branch, all_refs=None):
"""Was the branch published (uploaded) for code review? """Was the branch published (uploaded) for code review?
...@@ -897,7 +910,7 @@ class Project(object): ...@@ -897,7 +910,7 @@ class Project(object):
return None return None
def UploadForReview(self, branch=None, def UploadForReview(self, branch=None,
people=([],[]), people=([], []),
auto_topic=False, auto_topic=False,
draft=False): draft=False):
"""Uploads the named branch for code review. """Uploads the named branch for code review.
...@@ -949,16 +962,16 @@ class Project(object): ...@@ -949,16 +962,16 @@ class Project(object):
ref_spec = ref_spec + '/' + branch.name ref_spec = ref_spec + '/' + branch.name
cmd.append(ref_spec) cmd.append(ref_spec)
if GitCommand(self, cmd, bare = True).Wait() != 0: if GitCommand(self, cmd, bare=True).Wait() != 0:
raise UploadError('Upload failed') raise UploadError('Upload failed')
msg = "posted to %s for %s" % (branch.remote.review, dest_branch) msg = "posted to %s for %s" % (branch.remote.review, dest_branch)
self.bare_git.UpdateRef(R_PUB + branch.name, self.bare_git.UpdateRef(R_PUB + branch.name,
R_HEADS + branch.name, R_HEADS + branch.name,
message = msg) message=msg)
## Sync ## ## Sync ##
def Sync_NetworkHalf(self, def Sync_NetworkHalf(self,
quiet=False, quiet=False,
...@@ -1180,8 +1193,9 @@ class Project(object): ...@@ -1180,8 +1193,9 @@ class Project(object):
if cnt_mine > 0 and self.rebase: if cnt_mine > 0 and self.rebase:
def _dorebase(): def _dorebase():
self._Rebase(upstream = '%s^1' % last_mine, onto = revid) self._Rebase(upstream='%s^1' % last_mine, onto=revid)
self._CopyFiles() self._CopyFiles()
syncbuf.later2(self, _dorebase) syncbuf.later2(self, _dorebase)
elif local_changes: elif local_changes:
try: try:
...@@ -1220,7 +1234,7 @@ class Project(object): ...@@ -1220,7 +1234,7 @@ class Project(object):
self.bare_git.rev_parse('FETCH_HEAD')) self.bare_git.rev_parse('FETCH_HEAD'))
## Branch Management ## ## Branch Management ##
def StartBranch(self, name): def StartBranch(self, name):
"""Create a new branch off the manifest's revision. """Create a new branch off the manifest's revision.
...@@ -1233,8 +1247,8 @@ class Project(object): ...@@ -1233,8 +1247,8 @@ class Project(object):
if (R_HEADS + name) in all_refs: if (R_HEADS + name) in all_refs:
return GitCommand(self, return GitCommand(self,
['checkout', name, '--'], ['checkout', name, '--'],
capture_stdout = True, capture_stdout=True,
capture_stderr = True).Wait() == 0 capture_stderr=True).Wait() == 0
branch = self.GetBranch(name) branch = self.GetBranch(name)
branch.remote = self.GetRemote(self.remote.name) branch.remote = self.GetRemote(self.remote.name)
...@@ -1261,8 +1275,8 @@ class Project(object): ...@@ -1261,8 +1275,8 @@ class Project(object):
if GitCommand(self, if GitCommand(self,
['checkout', '-b', branch.name, revid], ['checkout', '-b', branch.name, revid],
capture_stdout = True, capture_stdout=True,
capture_stderr = True).Wait() == 0: capture_stderr=True).Wait() == 0:
branch.Save() branch.Save()
return True return True
return False return False
...@@ -1308,8 +1322,8 @@ class Project(object): ...@@ -1308,8 +1322,8 @@ class Project(object):
return GitCommand(self, return GitCommand(self,
['checkout', name, '--'], ['checkout', name, '--'],
capture_stdout = True, capture_stdout=True,
capture_stderr = True).Wait() == 0 capture_stderr=True).Wait() == 0
def AbandonBranch(self, name): def AbandonBranch(self, name):
"""Destroy a local topic branch. """Destroy a local topic branch.
...@@ -1343,8 +1357,8 @@ class Project(object): ...@@ -1343,8 +1357,8 @@ class Project(object):
return GitCommand(self, return GitCommand(self,
['branch', '-D', name], ['branch', '-D', name],
capture_stdout = True, capture_stdout=True,
capture_stderr = True).Wait() == 0 capture_stderr=True).Wait() == 0
def PruneHeads(self): def PruneHeads(self):
"""Prune any topic branches already merged into upstream. """Prune any topic branches already merged into upstream.
...@@ -1361,7 +1375,7 @@ class Project(object): ...@@ -1361,7 +1375,7 @@ class Project(object):
rev = self.GetRevisionId(left) rev = self.GetRevisionId(left)
if cb is not None \ if cb is not None \
and not self._revlist(HEAD + '...' + rev) \ and not self._revlist(HEAD + '...' + rev) \
and not self.IsDirty(consider_untracked = False): and not self.IsDirty(consider_untracked=False):
self.work_git.DetachHead(HEAD) self.work_git.DetachHead(HEAD)
kill.append(cb) kill.append(cb)
...@@ -1403,16 +1417,18 @@ class Project(object): ...@@ -1403,16 +1417,18 @@ class Project(object):
return kept return kept
## Submodule Management ## ## Submodule Management ##
def GetRegisteredSubprojects(self): def GetRegisteredSubprojects(self):
result = [] result = []
def rec(subprojects): def rec(subprojects):
if not subprojects: if not subprojects:
return return
result.extend(subprojects) result.extend(subprojects)
for p in subprojects: for p in subprojects:
rec(p.subprojects) rec(p.subprojects)
rec(self.subprojects) rec(self.subprojects)
return result return result
...@@ -1441,11 +1457,12 @@ class Project(object): ...@@ -1441,11 +1457,12 @@ class Project(object):
re_path = re.compile(r'^submodule\.([^.]+)\.path=(.*)$') re_path = re.compile(r'^submodule\.([^.]+)\.path=(.*)$')
re_url = re.compile(r'^submodule\.([^.]+)\.url=(.*)$') re_url = re.compile(r'^submodule\.([^.]+)\.url=(.*)$')
def parse_gitmodules(gitdir, rev): def parse_gitmodules(gitdir, rev):
cmd = ['cat-file', 'blob', '%s:.gitmodules' % rev] cmd = ['cat-file', 'blob', '%s:.gitmodules' % rev]
try: try:
p = GitCommand(None, cmd, capture_stdout = True, capture_stderr = True, p = GitCommand(None, cmd, capture_stdout=True, capture_stderr=True,
bare = True, gitdir = gitdir) bare=True, gitdir=gitdir)
except GitError: except GitError:
return [], [] return [], []
if p.Wait() != 0: if p.Wait() != 0:
...@@ -1457,8 +1474,8 @@ class Project(object): ...@@ -1457,8 +1474,8 @@ class Project(object):
os.write(fd, p.stdout) os.write(fd, p.stdout)
os.close(fd) os.close(fd)
cmd = ['config', '--file', temp_gitmodules_path, '--list'] cmd = ['config', '--file', temp_gitmodules_path, '--list']
p = GitCommand(None, cmd, capture_stdout = True, capture_stderr = True, p = GitCommand(None, cmd, capture_stdout=True, capture_stderr=True,
bare = True, gitdir = gitdir) bare=True, gitdir=gitdir)
if p.Wait() != 0: if p.Wait() != 0:
return [], [] return [], []
gitmodules_lines = p.stdout.split('\n') gitmodules_lines = p.stdout.split('\n')
...@@ -1491,8 +1508,8 @@ class Project(object): ...@@ -1491,8 +1508,8 @@ class Project(object):
cmd = ['ls-tree', rev, '--'] cmd = ['ls-tree', rev, '--']
cmd.extend(paths) cmd.extend(paths)
try: try:
p = GitCommand(None, cmd, capture_stdout = True, capture_stderr = True, p = GitCommand(None, cmd, capture_stdout=True, capture_stderr=True,
bare = True, gitdir = gitdir) bare=True, gitdir=gitdir)
except GitError: except GitError:
return [] return []
if p.Wait() != 0: if p.Wait() != 0:
...@@ -1525,28 +1542,28 @@ class Project(object): ...@@ -1525,28 +1542,28 @@ class Project(object):
continue continue
relpath, worktree, gitdir = self.manifest.GetSubprojectPaths(self, path) relpath, worktree, gitdir = self.manifest.GetSubprojectPaths(self, path)
remote = RemoteSpec(self.remote.name, remote = RemoteSpec(self.remote.name,
url = url, url=url,
review = self.remote.review) review=self.remote.review)
subproject = Project(manifest = self.manifest, subproject = Project(manifest=self.manifest,
name = name, name=name,
remote = remote, remote=remote,
gitdir = gitdir, gitdir=gitdir,
worktree = worktree, worktree=worktree,
relpath = relpath, relpath=relpath,
revisionExpr = self.revisionExpr, revisionExpr=self.revisionExpr,
revisionId = rev, revisionId=rev,
rebase = self.rebase, rebase=self.rebase,
groups = self.groups, groups=self.groups,
sync_c = self.sync_c, sync_c=self.sync_c,
sync_s = self.sync_s, sync_s=self.sync_s,
parent = self, parent=self,
is_derived = True) is_derived=True)
result.append(subproject) result.append(subproject)
result.extend(subproject.GetDerivedSubprojects()) result.extend(subproject.GetDerivedSubprojects())
return result return result
## Direct Git Commands ## ## Direct Git Commands ##
def _RemoteFetch(self, name=None, def _RemoteFetch(self, name=None,
current_branch_only=False, current_branch_only=False,
...@@ -1816,7 +1833,7 @@ class Project(object): ...@@ -1816,7 +1833,7 @@ class Project(object):
if GitCommand(self, cmd).Wait() != 0: if GitCommand(self, cmd).Wait() != 0:
raise GitError('%s reset --hard %s ' % (self.name, rev)) raise GitError('%s reset --hard %s ' % (self.name, rev))
def _Rebase(self, upstream, onto = None): def _Rebase(self, upstream, onto=None):
cmd = ['rebase'] cmd = ['rebase']
if onto is not None: if onto is not None:
cmd.extend(['--onto', onto]) cmd.extend(['--onto', onto])
...@@ -1873,7 +1890,7 @@ class Project(object): ...@@ -1873,7 +1890,7 @@ class Project(object):
m = self.manifest.manifestProject.config m = self.manifest.manifestProject.config
for key in ['user.name', 'user.email']: for key in ['user.name', 'user.email']:
if m.Has(key, include_defaults = False): if m.Has(key, include_defaults=False):
self.config.SetString(key, m.GetString(key)) self.config.SetString(key, m.GetString(key))
def _InitHooks(self): def _InitHooks(self):
...@@ -1936,7 +1953,7 @@ class Project(object): ...@@ -1936,7 +1953,7 @@ class Project(object):
if cur != '' or self.bare_ref.get(ref) != self.revisionId: if cur != '' or self.bare_ref.get(ref) != self.revisionId:
msg = 'manifest set to %s' % self.revisionId msg = 'manifest set to %s' % self.revisionId
dst = self.revisionId + '^0' dst = self.revisionId + '^0'
self.bare_git.UpdateRef(ref, dst, message = msg, detach = True) self.bare_git.UpdateRef(ref, dst, message=msg, detach=True)
else: else:
remote = self.GetRemote(self.remote.name) remote = self.GetRemote(self.remote.name)
dst = remote.ToLocal(self.revisionExpr) dst = remote.ToLocal(self.revisionExpr)
...@@ -1990,7 +2007,6 @@ class Project(object): ...@@ -1990,7 +2007,6 @@ class Project(object):
if GitCommand(self, cmd).Wait() != 0: if GitCommand(self, cmd).Wait() != 0:
raise GitError("cannot initialize work tree") raise GitError("cannot initialize work tree")
self._CopyFiles() self._CopyFiles()
def _gitdir_path(self, path): def _gitdir_path(self, path):
...@@ -2017,9 +2033,9 @@ class Project(object): ...@@ -2017,9 +2033,9 @@ class Project(object):
'-z', '-z',
'--others', '--others',
'--exclude-standard'], '--exclude-standard'],
bare = False, bare=False,
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
if p.Wait() == 0: if p.Wait() == 0:
out = p.stdout out = p.stdout
if out: if out:
...@@ -2033,9 +2049,9 @@ class Project(object): ...@@ -2033,9 +2049,9 @@ class Project(object):
cmd.extend(args) cmd.extend(args)
p = GitCommand(self._project, p = GitCommand(self._project,
cmd, cmd,
bare = False, bare=False,
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
try: try:
out = p.process.stdout.read() out = p.process.stdout.read()
r = {} r = {}
...@@ -2137,9 +2153,9 @@ class Project(object): ...@@ -2137,9 +2153,9 @@ class Project(object):
cmdv.extend(args) cmdv.extend(args)
p = GitCommand(self._project, p = GitCommand(self._project,
cmdv, cmdv,
bare = self._bare, bare=self._bare,
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
r = [] r = []
for line in p.process.stdout: for line in p.process.stdout:
if line[-1] == '\n': if line[-1] == '\n':
...@@ -2172,6 +2188,7 @@ class Project(object): ...@@ -2172,6 +2188,7 @@ class Project(object):
A callable object that will try to call git with the named command. A callable object that will try to call git with the named command.
""" """
name = name.replace('_', '-') name = name.replace('_', '-')
def runner(*args, **kwargs): def runner(*args, **kwargs):
cmdv = [] cmdv = []
config = kwargs.pop('config', None) config = kwargs.pop('config', None)
...@@ -2189,9 +2206,9 @@ class Project(object): ...@@ -2189,9 +2206,9 @@ class Project(object):
cmdv.extend(args) cmdv.extend(args)
p = GitCommand(self._project, p = GitCommand(self._project,
cmdv, cmdv,
bare = self._bare, bare=self._bare,
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
if p.Wait() != 0: if p.Wait() != 0:
raise GitError('%s %s: %s' % ( raise GitError('%s %s: %s' % (
self._project.name, self._project.name,
...@@ -2201,6 +2218,7 @@ class Project(object): ...@@ -2201,6 +2218,7 @@ class Project(object):
if r.endswith('\n') and r.index('\n') == len(r) - 1: if r.endswith('\n') and r.index('\n') == len(r) - 1:
return r[:-1] return r[:-1]
return r return r
return runner return runner
...@@ -2208,10 +2226,12 @@ class _PriorSyncFailedError(Exception): ...@@ -2208,10 +2226,12 @@ class _PriorSyncFailedError(Exception):
def __str__(self): def __str__(self):
return 'prior sync failed; rebase still in progress' return 'prior sync failed; rebase still in progress'
class _DirtyError(Exception): class _DirtyError(Exception):
def __str__(self): def __str__(self):
return 'contains uncommitted changes' return 'contains uncommitted changes'
class _InfoMessage(object): class _InfoMessage(object):
def __init__(self, project, text): def __init__(self, project, text):
self.project = project self.project = project
...@@ -2221,6 +2241,7 @@ class _InfoMessage(object): ...@@ -2221,6 +2241,7 @@ class _InfoMessage(object):
syncbuf.out.info('%s/: %s', self.project.relpath, self.text) syncbuf.out.info('%s/: %s', self.project.relpath, self.text)
syncbuf.out.nl() syncbuf.out.nl()
class _Failure(object): class _Failure(object):
def __init__(self, project, why): def __init__(self, project, why):
self.project = project self.project = project
...@@ -2232,6 +2253,7 @@ class _Failure(object): ...@@ -2232,6 +2253,7 @@ class _Failure(object):
str(self.why)) str(self.why))
syncbuf.out.nl() syncbuf.out.nl()
class _Later(object): class _Later(object):
def __init__(self, project, action): def __init__(self, project, action):
self.project = project self.project = project
...@@ -2249,13 +2271,15 @@ class _Later(object): ...@@ -2249,13 +2271,15 @@ class _Later(object):
out.nl() out.nl()
return False return False
class _SyncColoring(Coloring): class _SyncColoring(Coloring):
def __init__(self, config): def __init__(self, config):
Coloring.__init__(self, config, 'reposync') Coloring.__init__(self, config, 'reposync')
self.project = self.printer('header', attr = 'bold') self.project = self.printer('header', attr='bold')
self.info = self.printer('info') self.info = self.printer('info')
self.fail = self.printer('fail', fg='red') self.fail = self.printer('fail', fg='red')
class SyncBuffer(object): class SyncBuffer(object):
def __init__(self, config, detach_head=False): def __init__(self, config, detach_head=False):
self._messages = [] self._messages = []
...@@ -2314,17 +2338,18 @@ class SyncBuffer(object): ...@@ -2314,17 +2338,18 @@ class SyncBuffer(object):
class MetaProject(Project): class MetaProject(Project):
"""A special project housed under .repo. """A special project housed under .repo.
""" """
def __init__(self, manifest, name, gitdir, worktree): def __init__(self, manifest, name, gitdir, worktree):
Project.__init__(self, Project.__init__(self,
manifest = manifest, manifest=manifest,
name = name, name=name,
gitdir = gitdir, gitdir=gitdir,
worktree = worktree, worktree=worktree,
remote = RemoteSpec('origin'), remote=RemoteSpec('origin'),
relpath = '.repo/%s' % name, relpath='.repo/%s' % name,
revisionExpr = 'refs/heads/master', revisionExpr='refs/heads/master',
revisionId = None, revisionId=None,
groups = None) groups=None)
def PreSync(self): def PreSync(self):
if self.Exists: if self.Exists:
...@@ -2341,14 +2366,14 @@ class MetaProject(Project): ...@@ -2341,14 +2366,14 @@ class MetaProject(Project):
# detach and delete manifest branch, allowing a new # detach and delete manifest branch, allowing a new
# branch to take over # branch to take over
syncbuf = SyncBuffer(self.config, detach_head = True) syncbuf = SyncBuffer(self.config, detach_head=True)
self.Sync_LocalHalf(syncbuf) self.Sync_LocalHalf(syncbuf)
syncbuf.Finish() syncbuf.Finish()
return GitCommand(self, return GitCommand(self,
['update-ref', '-d', 'refs/heads/default'], ['update-ref', '-d', 'refs/heads/default'],
capture_stdout = True, capture_stdout=True,
capture_stderr = True).Wait() == 0 capture_stderr=True).Wait() == 0
@property @property
......
...@@ -10,9 +10,11 @@ def removeReadOnlyFiles(fn, path): ...@@ -10,9 +10,11 @@ def removeReadOnlyFiles(fn, path):
else: else:
raise Exception("Could not delete %s" % path) raise Exception("Could not delete %s" % path)
def stream2str(stream): def stream2str(stream):
return str(stream, encoding='UTF-8') return str(stream, encoding='UTF-8')
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
print('git-repo is written for python3, your version is %s, please upgrade from www.python.org.' % sys.version) print('git-repo is written for python3, your version is %s, please upgrade from www.python.org.' % sys.version)
exit(0) exit(0)
...@@ -83,7 +85,6 @@ S_repo = 'repo' # special repo repository ...@@ -83,7 +85,6 @@ S_repo = 'repo' # special repo repository
S_manifests = 'manifests' # special manifest repository S_manifests = 'manifests' # special manifest repository
REPO_MAIN = S_repo + '/main.py' # main script REPO_MAIN = S_repo + '/main.py' # main script
import optparse import optparse
import os import os
import re import re
...@@ -154,6 +155,7 @@ group.add_option('--config-name', ...@@ -154,6 +155,7 @@ group.add_option('--config-name',
dest='config_name', action="store_true", default=False, dest='config_name', action="store_true", default=False,
help='Always prompt for name/e-mail') help='Always prompt for name/e-mail')
class CloneFailure(Exception): class CloneFailure(Exception):
"""Indicate the remote clone of repo itself failed. """Indicate the remote clone of repo itself failed.
""" """
...@@ -287,8 +289,8 @@ def SetupGnuPG(quiet): ...@@ -287,8 +289,8 @@ def SetupGnuPG(quiet):
cmd = ['gpg', '--import'] cmd = ['gpg', '--import']
try: try:
proc = subprocess.Popen(cmd, proc = subprocess.Popen(cmd,
env = env, env=env,
stdin = subprocess.PIPE) stdin=subprocess.PIPE)
except OSError as e: except OSError as e:
if not quiet: if not quiet:
print('warning: gpg (GnuPG) is not available.', file=sys.stderr) print('warning: gpg (GnuPG) is not available.', file=sys.stderr)
...@@ -314,7 +316,7 @@ def _SetConfig(local, name, value): ...@@ -314,7 +316,7 @@ def _SetConfig(local, name, value):
"""Set a git configuration option to the specified value. """Set a git configuration option to the specified value.
""" """
cmd = [GIT, 'config', name, value] cmd = [GIT, 'config', name, value]
if subprocess.Popen(cmd, cwd = local).wait() != 0: if subprocess.Popen(cmd, cwd=local).wait() != 0:
raise CloneFailure() raise CloneFailure()
...@@ -324,6 +326,7 @@ def _InitHttp(): ...@@ -324,6 +326,7 @@ def _InitHttp():
mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
try: try:
import netrc import netrc
n = netrc.netrc() n = netrc.netrc()
for host in n.hosts: for host in n.hosts:
p = n.hosts[host] p = n.hosts[host]
...@@ -342,6 +345,7 @@ def _InitHttp(): ...@@ -342,6 +345,7 @@ def _InitHttp():
handlers.append(urllib.request.HTTPSHandler(debuglevel=1)) handlers.append(urllib.request.HTTPSHandler(debuglevel=1))
urllib.request.install_opener(urllib.request.build_opener(*handlers)) urllib.request.install_opener(urllib.request.build_opener(*handlers))
def _Fetch(url, local, src, quiet): def _Fetch(url, local, src, quiet):
if not quiet: if not quiet:
print('Get %s' % url, file=sys.stderr) print('Get %s' % url, file=sys.stderr)
...@@ -356,13 +360,14 @@ def _Fetch(url, local, src, quiet): ...@@ -356,13 +360,14 @@ def _Fetch(url, local, src, quiet):
cmd.append('+refs/heads/*:refs/remotes/origin/*') cmd.append('+refs/heads/*:refs/remotes/origin/*')
cmd.append('refs/tags/*:refs/tags/*') cmd.append('refs/tags/*:refs/tags/*')
proc = subprocess.Popen(cmd, cwd = local, stderr = err) proc = subprocess.Popen(cmd, cwd=local, stderr=err)
if err: if err:
proc.stderr.read() proc.stderr.read()
proc.stderr.close() proc.stderr.close()
if proc.wait() != 0: if proc.wait() != 0:
raise CloneFailure() raise CloneFailure()
def _DownloadBundle(url, local, quiet): def _DownloadBundle(url, local, quiet):
if not url.endswith('/'): if not url.endswith('/'):
url += '/' url += '/'
...@@ -370,8 +375,8 @@ def _DownloadBundle(url, local, quiet): ...@@ -370,8 +375,8 @@ def _DownloadBundle(url, local, quiet):
proc = subprocess.Popen( proc = subprocess.Popen(
[GIT, 'config', '--get-regexp', 'url.*.insteadof'], [GIT, 'config', '--get-regexp', 'url.*.insteadof'],
cwd = local, cwd=local,
stdout = subprocess.PIPE) stdout=subprocess.PIPE)
for line in proc.stdout: for line in proc.stdout:
m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line) m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line)
if m: if m:
...@@ -413,6 +418,7 @@ def _DownloadBundle(url, local, quiet): ...@@ -413,6 +418,7 @@ def _DownloadBundle(url, local, quiet):
finally: finally:
dest.close() dest.close()
def _ImportBundle(local): def _ImportBundle(local):
path = os.path.join(local, '.git', 'clone.bundle') path = os.path.join(local, '.git', 'clone.bundle')
try: try:
...@@ -420,6 +426,7 @@ def _ImportBundle(local): ...@@ -420,6 +426,7 @@ def _ImportBundle(local):
finally: finally:
os.remove(path) os.remove(path)
def _Clone(url, local, quiet): def _Clone(url, local, quiet):
"""Clones a git repository to a new subdirectory of repodir """Clones a git repository to a new subdirectory of repodir
""" """
...@@ -432,7 +439,7 @@ def _Clone(url, local, quiet): ...@@ -432,7 +439,7 @@ def _Clone(url, local, quiet):
cmd = [GIT, 'init', '--quiet'] cmd = [GIT, 'init', '--quiet']
try: try:
proc = subprocess.Popen(cmd, cwd = local) proc = subprocess.Popen(cmd, cwd=local)
except OSError as e: except OSError as e:
print(file=sys.stderr) print(file=sys.stderr)
print("fatal: '%s' is not available" % GIT, file=sys.stderr) print("fatal: '%s' is not available" % GIT, file=sys.stderr)
...@@ -462,7 +469,7 @@ def _Verify(cwd, branch, quiet): ...@@ -462,7 +469,7 @@ def _Verify(cwd, branch, quiet):
proc = subprocess.Popen(cmd, proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
cwd = cwd) cwd=cwd)
cur = stream2str(proc.stdout.read()).strip() cur = stream2str(proc.stdout.read()).strip()
proc.stdout.close() proc.stdout.close()
...@@ -488,10 +495,10 @@ def _Verify(cwd, branch, quiet): ...@@ -488,10 +495,10 @@ def _Verify(cwd, branch, quiet):
cmd = [GIT, 'tag', '-v', cur] cmd = [GIT, 'tag', '-v', cur]
proc = subprocess.Popen(cmd, proc = subprocess.Popen(cmd,
stdout = subprocess.PIPE, stdout=subprocess.PIPE,
stderr = subprocess.PIPE, stderr=subprocess.PIPE,
cwd = cwd, cwd=cwd,
env = env) env=env)
out = proc.stdout.read() out = proc.stdout.read()
proc.stdout.close() proc.stdout.close()
...@@ -511,21 +518,21 @@ def _Checkout(cwd, branch, rev, quiet): ...@@ -511,21 +518,21 @@ def _Checkout(cwd, branch, rev, quiet):
"""Checkout an upstream branch into the repository and track it. """Checkout an upstream branch into the repository and track it.
""" """
cmd = [GIT, 'update-ref', 'refs/heads/default', rev] cmd = [GIT, 'update-ref', 'refs/heads/default', rev]
if subprocess.Popen(cmd, cwd = cwd).wait() != 0: if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
raise CloneFailure() raise CloneFailure()
_SetConfig(cwd, 'branch.default.remote', 'origin') _SetConfig(cwd, 'branch.default.remote', 'origin')
_SetConfig(cwd, 'branch.default.merge', 'refs/heads/%s' % branch) _SetConfig(cwd, 'branch.default.merge', 'refs/heads/%s' % branch)
cmd = [GIT, 'symbolic-ref', 'HEAD', 'refs/heads/default'] cmd = [GIT, 'symbolic-ref', 'HEAD', 'refs/heads/default']
if subprocess.Popen(cmd, cwd = cwd).wait() != 0: if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
raise CloneFailure() raise CloneFailure()
cmd = [GIT, 'read-tree', '--reset', '-u'] cmd = [GIT, 'read-tree', '--reset', '-u']
if not quiet: if not quiet:
cmd.append('-v') cmd.append('-v')
cmd.append('HEAD') cmd.append('HEAD')
if subprocess.Popen(cmd, cwd = cwd).wait() != 0: if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
raise CloneFailure() raise CloneFailure()
...@@ -570,17 +577,17 @@ def _ParseArguments(args): ...@@ -570,17 +577,17 @@ def _ParseArguments(args):
def _Usage(): def _Usage():
print( print(
"""usage: repo COMMAND [ARGS] """usage: repo COMMAND [ARGS]
repo is not yet installed. Use "repo init" to install it here. repo is not yet installed. Use "repo init" to install it here.
The most commonly used repo commands are: The most commonly used repo commands are:
init Install repo in the current working directory init Install repo in the current working directory
help Display detailed help on a command help Display detailed help on a command
For access to the full online help, install repo ("repo init"). For access to the full online help, install repo ("repo init").
""", file=sys.stderr) """, file=sys.stderr)
sys.exit(1) sys.exit(1)
...@@ -634,8 +641,8 @@ def _SetDefaultsTo(gitdir): ...@@ -634,8 +641,8 @@ def _SetDefaultsTo(gitdir):
'--git-dir=%s' % gitdir, '--git-dir=%s' % gitdir,
'symbolic-ref', 'symbolic-ref',
'HEAD'], 'HEAD'],
stdout = subprocess.PIPE, stdout=subprocess.PIPE,
stderr = subprocess.PIPE) stderr=subprocess.PIPE)
REPO_REV = stream2str(proc.stdout.read()).strip() REPO_REV = stream2str(proc.stdout.read()).strip()
proc.stdout.close() proc.stdout.close()
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
import sys import sys
import os import os
REPO_TRACE = 'REPO_TRACE' REPO_TRACE = 'REPO_TRACE'
try: try:
...@@ -23,13 +24,16 @@ try: ...@@ -23,13 +24,16 @@ try:
except KeyError: except KeyError:
_TRACE = False _TRACE = False
def IsTrace(): def IsTrace():
return _TRACE return _TRACE
def SetTrace(): def SetTrace():
global _TRACE global _TRACE
_TRACE = True _TRACE = True
def Trace(fmt, *args): def Trace(fmt, *args):
if IsTrace(): if IsTrace():
print(fmt % args, file=sys.stderr) print(fmt % args, file=sys.stderr)
...@@ -19,6 +19,7 @@ from command import Command ...@@ -19,6 +19,7 @@ from command import Command
from git_command import git from git_command import git
from progress import Progress from progress import Progress
class Abandon(Command): class Abandon(Command):
common = True common = True
helpSummary = "Permanently abandon a development branch" helpSummary = "Permanently abandon a development branch"
......
...@@ -18,6 +18,7 @@ import sys ...@@ -18,6 +18,7 @@ import sys
from color import Coloring from color import Coloring
from command import Command from command import Command
class BranchColoring(Coloring): class BranchColoring(Coloring):
def __init__(self, config): def __init__(self, config):
Coloring.__init__(self, config, 'branch') Coloring.__init__(self, config, 'branch')
...@@ -25,6 +26,7 @@ class BranchColoring(Coloring): ...@@ -25,6 +26,7 @@ class BranchColoring(Coloring):
self.local = self.printer('local') self.local = self.printer('local')
self.notinproject = self.printer('notinproject', fg='red') self.notinproject = self.printer('notinproject', fg='red')
class BranchInfo(object): class BranchInfo(object):
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
...@@ -161,7 +163,7 @@ is shown, then the branch appears in all projects. ...@@ -161,7 +163,7 @@ is shown, then the branch appears in all projects.
fmt(' %s:' % in_type) fmt(' %s:' % in_type)
for p in paths: for p in paths:
out.nl() out.nl()
fmt(width*' ' + ' %s' % p) fmt(width * ' ' + ' %s' % p)
else: else:
out.write(' in all projects') out.write(' in all projects')
out.nl() out.nl()
...@@ -18,6 +18,7 @@ import sys ...@@ -18,6 +18,7 @@ import sys
from command import Command from command import Command
from progress import Progress from progress import Progress
class Checkout(Command): class Checkout(Command):
common = True common = True
helpSummary = "Checkout a branch for development" helpSummary = "Checkout a branch for development"
......
...@@ -22,6 +22,7 @@ import portable ...@@ -22,6 +22,7 @@ import portable
CHANGE_ID_RE = re.compile(r'^\s*Change-Id: I([0-9a-f]{40})\s*$') CHANGE_ID_RE = re.compile(r'^\s*Change-Id: I([0-9a-f]{40})\s*$')
class CherryPick(Command): class CherryPick(Command):
common = True common = True
helpSummary = "Cherry-pick a change." helpSummary = "Cherry-pick a change."
...@@ -45,8 +46,8 @@ change id will be added. ...@@ -45,8 +46,8 @@ change id will be added.
p = GitCommand(None, p = GitCommand(None,
['rev-parse', '--verify', reference], ['rev-parse', '--verify', reference],
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
if p.Wait() != 0: if p.Wait() != 0:
print(p.stderr, file=sys.stderr) print(p.stderr, file=sys.stderr)
sys.exit(1) sys.exit(1)
...@@ -60,8 +61,8 @@ change id will be added. ...@@ -60,8 +61,8 @@ change id will be added.
p = GitCommand(None, p = GitCommand(None,
['cherry-pick', sha1], ['cherry-pick', sha1],
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
status = p.Wait() status = p.Wait()
print(p.stdout, file=sys.stdout) print(p.stdout, file=sys.stdout)
...@@ -73,9 +74,9 @@ change id will be added. ...@@ -73,9 +74,9 @@ change id will be added.
new_msg = self._Reformat(old_msg, sha1) new_msg = self._Reformat(old_msg, sha1)
p = GitCommand(None, ['commit', '--amend', '-F', '-'], p = GitCommand(None, ['commit', '--amend', '-F', '-'],
provide_stdin = True, provide_stdin=True,
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
p.stdin.write(new_msg) p.stdin.write(new_msg)
if p.Wait() != 0: if p.Wait() != 0:
print("error: Failed to update commit message", file=sys.stderr) print("error: Failed to update commit message", file=sys.stderr)
...@@ -95,7 +96,7 @@ change id will be added. ...@@ -95,7 +96,7 @@ change id will be added.
def _StripHeader(self, commit_msg): def _StripHeader(self, commit_msg):
lines = commit_msg.splitlines() lines = commit_msg.splitlines()
return "\n".join(lines[lines.index("")+1:]) return "\n".join(lines[lines.index("") + 1:])
def _Reformat(self, old_msg, sha1): def _Reformat(self, old_msg, sha1):
new_msg = [] new_msg = []
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
from command import PagedCommand from command import PagedCommand
class Diff(PagedCommand): class Diff(PagedCommand):
common = True common = True
helpSummary = "Show changes between commit and working tree" helpSummary = "Show changes between commit and working tree"
...@@ -31,6 +32,7 @@ to the Unix 'patch' command. ...@@ -31,6 +32,7 @@ to the Unix 'patch' command.
setattr(parser.values, option.dest, list(parser.rargs)) setattr(parser.values, option.dest, list(parser.rargs))
while parser.rargs: while parser.rargs:
del parser.rargs[0] del parser.rargs[0]
p.add_option('-u', '--absolute', p.add_option('-u', '--absolute',
dest='absolute', action='store_true', dest='absolute', action='store_true',
help='Paths are relative to the repository root') help='Paths are relative to the repository root')
......
...@@ -21,6 +21,7 @@ from command import Command ...@@ -21,6 +21,7 @@ from command import Command
CHANGE_RE = re.compile(r'^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$') CHANGE_RE = re.compile(r'^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$')
class Download(Command): class Download(Command):
common = True common = True
helpSummary = "Download and checkout a change" helpSummary = "Download and checkout a change"
......
...@@ -31,6 +31,7 @@ _CAN_COLOR = [ ...@@ -31,6 +31,7 @@ _CAN_COLOR = [
'log', 'log',
] ]
class ForallColoring(Coloring): class ForallColoring(Coloring):
def __init__(self, config): def __init__(self, config):
Coloring.__init__(self, config, 'forall') Coloring.__init__(self, config, 'forall')
...@@ -103,6 +104,7 @@ without iterating through the remaining projects. ...@@ -103,6 +104,7 @@ without iterating through the remaining projects.
setattr(parser.values, option.dest, list(parser.rargs)) setattr(parser.values, option.dest, list(parser.rargs))
while parser.rargs: while parser.rargs:
del parser.rargs[0] del parser.rargs[0]
p.add_option('-c', '--command', p.add_option('-c', '--command',
help='Command (and arguments) to execute', help='Command (and arguments) to execute',
dest='command', dest='command',
...@@ -155,6 +157,7 @@ without iterating through the remaining projects. ...@@ -155,6 +157,7 @@ without iterating through the remaining projects.
class ColorCmd(Coloring): class ColorCmd(Coloring):
def __init__(self, config, cmd): def __init__(self, config, cmd):
Coloring.__init__(self, config, cmd) Coloring.__init__(self, config, cmd)
if ColorCmd(self.manifest.manifestProject.config, cn).is_on: if ColorCmd(self.manifest.manifestProject.config, cn).is_on:
cmd.insert(cmd.index(cn) + 1, '--color') cmd.insert(cmd.index(cn) + 1, '--color')
# pylint: enable=W0631 # pylint: enable=W0631
...@@ -168,6 +171,7 @@ without iterating through the remaining projects. ...@@ -168,6 +171,7 @@ without iterating through the remaining projects.
for project in self.GetProjects(args): for project in self.GetProjects(args):
env = os.environ.copy() env = os.environ.copy()
def setenv(name, val): def setenv(name, val):
if val is None: if val is None:
val = '' val = ''
...@@ -203,62 +207,63 @@ without iterating through the remaining projects. ...@@ -203,62 +207,63 @@ without iterating through the remaining projects.
stderr = None stderr = None
p = subprocess.Popen(cmd, p = subprocess.Popen(cmd,
cwd = cwd, cwd=cwd,
shell = shell, shell=shell,
env = env, env=env,
stdin = stdin, stdin=stdin,
stdout = stdout, stdout=stdout,
stderr = stderr) stderr=stderr)
if opt.project_header: if opt.project_header:
class sfd(object): class sfd(object):
def __init__(self, fd, dest): def __init__(self, fd, dest):
self.fd = fd self.fd = fd
self.dest = dest self.dest = dest
def fileno(self): def fileno(self):
return self.fd.fileno() return self.fd.fileno()
# empty = True # empty = True
# errbuf = '' # errbuf = ''
# #
# p.stdin.close() # p.stdin.close()
# s_in = [sfd(p.stdout, sys.stdout), # s_in = [sfd(p.stdout, sys.stdout),
# sfd(p.stderr, sys.stderr)] # sfd(p.stderr, sys.stderr)]
# #
# for s in s_in: # for s in s_in:
# flags = fcntl.fcntl(s.fd, fcntl.F_GETFL) # flags = fcntl.fcntl(s.fd, fcntl.F_GETFL)
# fcntl.fcntl(s.fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) # fcntl.fcntl(s.fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
# #
# while s_in: # while s_in:
# in_ready, _out_ready, _err_ready = select.select(s_in, [], []) # in_ready, _out_ready, _err_ready = select.select(s_in, [], [])
# for s in in_ready: # for s in in_ready:
# buf = s.fd.read(4096) # buf = s.fd.read(4096)
# if not buf: # if not buf:
# s.fd.close() # s.fd.close()
# s_in.remove(s) # s_in.remove(s)
# continue # continue
# #
# if not opt.verbose: # if not opt.verbose:
# if s.fd != p.stdout: # if s.fd != p.stdout:
# errbuf += buf # errbuf += buf
# continue # continue
# #
# if empty: # if empty:
# if first: # if first:
# first = False # first = False
# else: # else:
# out.nl() # out.nl()
# out.project('project %s/', project.relpath) # out.project('project %s/', project.relpath)
# out.nl() # out.nl()
# out.flush() # out.flush()
# if errbuf: # if errbuf:
# sys.stderr.write(errbuf) # sys.stderr.write(errbuf)
# sys.stderr.flush() # sys.stderr.flush()
# errbuf = '' # errbuf = ''
# empty = False # empty = False
# #
# s.dest.write(buf) # s.dest.write(buf)
# s.dest.flush() # s.dest.flush()
r = p.wait() r = p.wait()
if r != 0: if r != 0:
......
...@@ -20,11 +20,13 @@ from command import PagedCommand ...@@ -20,11 +20,13 @@ from command import PagedCommand
from git_command import git_require, GitCommand from git_command import git_require, GitCommand
import portable import portable
class GrepColoring(Coloring): class GrepColoring(Coloring):
def __init__(self, config): def __init__(self, config):
Coloring.__init__(self, config, 'grep') Coloring.__init__(self, config, 'grep')
self.project = self.printer('project', attr='bold') self.project = self.printer('project', attr='bold')
class Grep(PagedCommand): class Grep(PagedCommand):
common = True common = True
helpSummary = "Print lines matching a pattern" helpSummary = "Print lines matching a pattern"
...@@ -192,9 +194,9 @@ contain a line that matches both expressions: ...@@ -192,9 +194,9 @@ contain a line that matches both expressions:
for project in projects: for project in projects:
p = GitCommand(project, p = GitCommand(project,
cmd_argv, cmd_argv,
bare = False, bare=False,
capture_stdout = True, capture_stdout=True,
capture_stderr = True) capture_stderr=True)
if p.Wait() != 0: if p.Wait() != 0:
# no results # no results
# #
......
...@@ -21,6 +21,7 @@ from formatter import AbstractFormatter, DumbWriter ...@@ -21,6 +21,7 @@ from formatter import AbstractFormatter, DumbWriter
from color import Coloring from color import Coloring
from command import PagedCommand, MirrorSafeCommand from command import PagedCommand, MirrorSafeCommand
class Help(PagedCommand, MirrorSafeCommand): class Help(PagedCommand, MirrorSafeCommand):
common = False common = False
helpSummary = "Display detailed help on a command" helpSummary = "Display detailed help on a command"
...@@ -73,8 +74,8 @@ Displays detailed usage information about a command. ...@@ -73,8 +74,8 @@ Displays detailed usage information about a command.
summary = '' summary = ''
print(fmt % (name, summary)) print(fmt % (name, summary))
print( print(
"See 'repo help <command>' for more information on a specific command.\n" "See 'repo help <command>' for more information on a specific command.\n"
"See 'repo help --all' for a complete list of recognized commands.") "See 'repo help --all' for a complete list of recognized commands.")
def _PrintCommandHelp(self, cmd): def _PrintCommandHelp(self, cmd):
class _Out(Coloring): class _Out(Coloring):
...@@ -122,6 +123,7 @@ Displays detailed usage information about a command. ...@@ -122,6 +123,7 @@ Displays detailed usage information about a command.
def _p(fmt, *args): def _p(fmt, *args):
self.write(' ') self.write(' ')
self.heading(fmt, *args) self.heading(fmt, *args)
p = _p p = _p
p('%s', title) p('%s', title)
......
...@@ -18,10 +18,12 @@ from color import Coloring ...@@ -18,10 +18,12 @@ from color import Coloring
from error import NoSuchProjectError from error import NoSuchProjectError
from git_refs import R_M from git_refs import R_M
class _Coloring(Coloring): class _Coloring(Coloring):
def __init__(self, config): def __init__(self, config):
Coloring.__init__(self, config, "status") Coloring.__init__(self, config, "status")
class Info(PagedCommand): class Info(PagedCommand):
common = True common = True
helpSummary = "Get info on the manifest branch, current branch or unmerged branches" helpSummary = "Get info on the manifest branch, current branch or unmerged branches"
...@@ -44,12 +46,12 @@ class Info(PagedCommand): ...@@ -44,12 +46,12 @@ class Info(PagedCommand):
def Execute(self, opt, args): def Execute(self, opt, args):
self.out = _Coloring(self.manifest.globalConfig) self.out = _Coloring(self.manifest.globalConfig)
self.heading = self.out.printer('heading', attr = 'bold') self.heading = self.out.printer('heading', attr='bold')
self.headtext = self.out.printer('headtext', fg = 'yellow') self.headtext = self.out.printer('headtext', fg='yellow')
self.redtext = self.out.printer('redtext', fg = 'red') self.redtext = self.out.printer('redtext', fg='red')
self.sha = self.out.printer("sha", fg = 'yellow') self.sha = self.out.printer("sha", fg='yellow')
self.text = self.out.printer('text') self.text = self.out.printer('text')
self.dimtext = self.out.printer('dimtext', attr = 'dim') self.dimtext = self.out.printer('dimtext', attr='dim')
self.opt = opt self.opt = opt
...@@ -189,7 +191,7 @@ class Info(PagedCommand): ...@@ -189,7 +191,7 @@ class Info(PagedCommand):
for commit in commits: for commit in commits:
split = commit.split() split = commit.split()
self.text('{0:38}{1} '.format('','-')) self.text('{0:38}{1} '.format('', '-'))
self.sha(split[0] + " ") self.sha(split[0] + " ")
self.text(" ".join(split[1:])) self.text(" ".join(split[1:]))
self.out.nl() self.out.nl()
...@@ -28,6 +28,7 @@ from project import SyncBuffer ...@@ -28,6 +28,7 @@ from project import SyncBuffer
from git_config import GitConfig from git_config import GitConfig
from git_command import git_require, MIN_GIT_VERSION from git_command import git_require, MIN_GIT_VERSION
class Init(InteractiveCommand, MirrorSafeCommand): class Init(InteractiveCommand, MirrorSafeCommand):
common = True common = True
helpSummary = "Initialize repo in the current directory" helpSummary = "Initialize repo in the current directory"
...@@ -283,6 +284,7 @@ to update the working directory files. ...@@ -283,6 +284,7 @@ to update the working directory files.
def __init__(self): def __init__(self):
Coloring.__init__(self, gc, 'test color display') Coloring.__init__(self, gc, 'test color display')
self._on = True self._on = True
out = _Test() out = _Test()
print() print()
......
...@@ -18,6 +18,7 @@ import re ...@@ -18,6 +18,7 @@ import re
from command import Command, MirrorSafeCommand from command import Command, MirrorSafeCommand
class List(Command, MirrorSafeCommand): class List(Command, MirrorSafeCommand):
common = True common = True
helpSummary = "List projects and their associated directories" helpSummary = "List projects and their associated directories"
......
...@@ -19,6 +19,7 @@ import sys ...@@ -19,6 +19,7 @@ import sys
from command import PagedCommand from command import PagedCommand
class Manifest(PagedCommand): class Manifest(PagedCommand):
common = False common = False
helpSummary = "Manifest inspection utility" helpSummary = "Manifest inspection utility"
...@@ -66,8 +67,8 @@ in a Git repository for use during future 'repo init' invocations. ...@@ -66,8 +67,8 @@ in a Git repository for use during future 'repo init' invocations.
else: else:
fd = open(opt.output_file, 'w') fd = open(opt.output_file, 'w')
self.manifest.Save(fd, self.manifest.Save(fd,
peg_rev = opt.peg_rev, peg_rev=opt.peg_rev,
peg_rev_upstream = opt.peg_rev_upstream) peg_rev_upstream=opt.peg_rev_upstream)
fd.close() fd.close()
if opt.output_file != '-': if opt.output_file != '-':
print('Saved manifest to %s' % opt.output_file, file=sys.stderr) print('Saved manifest to %s' % opt.output_file, file=sys.stderr)
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
from color import Coloring from color import Coloring
from command import PagedCommand from command import PagedCommand
class Prune(PagedCommand): class Prune(PagedCommand):
common = True common = True
helpSummary = "Prune (delete) already merged topics" helpSummary = "Prune (delete) already merged topics"
......
...@@ -19,6 +19,7 @@ import sys ...@@ -19,6 +19,7 @@ import sys
from command import Command from command import Command
from git_command import GitCommand from git_command import GitCommand
class Rebase(Command): class Rebase(Command):
common = True common = True
helpSummary = "Rebase local branches on upstream branch" helpSummary = "Rebase local branches on upstream branch"
......
...@@ -21,6 +21,7 @@ from command import Command, MirrorSafeCommand ...@@ -21,6 +21,7 @@ from command import Command, MirrorSafeCommand
from subcmds.sync import _PostRepoUpgrade from subcmds.sync import _PostRepoUpgrade
from subcmds.sync import _PostRepoFetch from subcmds.sync import _PostRepoFetch
class Selfupdate(Command, MirrorSafeCommand): class Selfupdate(Command, MirrorSafeCommand):
common = False common = False
helpSummary = "Update repo to the latest version" helpSummary = "Update repo to the latest version"
...@@ -58,5 +59,5 @@ need to be performed by an end-user. ...@@ -58,5 +59,5 @@ need to be performed by an end-user.
rp.bare_git.gc('--auto') rp.bare_git.gc('--auto')
_PostRepoFetch(rp, _PostRepoFetch(rp,
no_repo_verify = opt.no_repo_verify, no_repo_verify=opt.no_repo_verify,
verbose = True) verbose=True)
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
from subcmds.sync import Sync from subcmds.sync import Sync
class Smartsync(Sync): class Smartsync(Sync):
common = True common = True
helpSummary = "Update working tree to the latest known good revision" helpSummary = "Update working tree to the latest known good revision"
......
...@@ -20,6 +20,7 @@ from color import Coloring ...@@ -20,6 +20,7 @@ from color import Coloring
from command import InteractiveCommand from command import InteractiveCommand
from git_command import GitCommand from git_command import GitCommand
class _ProjectList(Coloring): class _ProjectList(Coloring):
def __init__(self, gc): def __init__(self, gc):
Coloring.__init__(self, gc, 'interactive') Coloring.__init__(self, gc, 'interactive')
...@@ -27,6 +28,7 @@ class _ProjectList(Coloring): ...@@ -27,6 +28,7 @@ class _ProjectList(Coloring):
self.header = self.printer('header', attr='bold') self.header = self.printer('header', attr='bold')
self.help = self.printer('help', fg='red', attr='bold') self.help = self.printer('help', fg='red', attr='bold')
class Stage(InteractiveCommand): class Stage(InteractiveCommand):
common = True common = True
helpSummary = "Stage file(s) for commit" helpSummary = "Stage file(s) for commit"
...@@ -104,6 +106,7 @@ The '%prog' command stages files to prepare the next commit. ...@@ -104,6 +106,7 @@ The '%prog' command stages files to prepare the next commit.
continue continue
print('Bye.') print('Bye.')
def _AddI(project): def _AddI(project):
p = GitCommand(project, ['add', '--interactive'], bare=False) p = GitCommand(project, ['add', '--interactive'], bare=False)
p.Wait() p.Wait()
...@@ -20,6 +20,7 @@ from git_config import IsId ...@@ -20,6 +20,7 @@ from git_config import IsId
from git_command import git from git_command import git
from progress import Progress from progress import Progress
class Start(Command): class Start(Command):
common = True common = True
helpSummary = "Start a new branch for development" helpSummary = "Start a new branch for development"
......
...@@ -28,6 +28,7 @@ import io ...@@ -28,6 +28,7 @@ import io
from color import Coloring from color import Coloring
class Status(PagedCommand): class Status(PagedCommand):
common = True common = True
helpSummary = "Show the working tree status" helpSummary = "Show the working tree status"
...@@ -145,6 +146,7 @@ the following meanings: ...@@ -145,6 +146,7 @@ the following meanings:
class BufList(io.StringIO): class BufList(io.StringIO):
def dump(self, ostream): def dump(self, ostream):
ostream.write(self.getvalue()) ostream.write(self.getvalue())
output = BufList() output = BufList()
t = _threading.Thread(target=self._StatusHelper, t = _threading.Thread(target=self._StatusHelper,
...@@ -173,8 +175,8 @@ the following meanings: ...@@ -173,8 +175,8 @@ the following meanings:
class StatusColoring(Coloring): class StatusColoring(Coloring):
def __init__(self, config): def __init__(self, config):
Coloring.__init__(self, config, 'status') Coloring.__init__(self, config, 'status')
self.project = self.printer('header', attr = 'bold') self.project = self.printer('header', attr='bold')
self.untracked = self.printer('untracked', fg = 'red') self.untracked = self.printer('untracked', fg='red')
orig_path = os.getcwd() orig_path = os.getcwd()
try: try:
......
...@@ -35,6 +35,7 @@ import portable ...@@ -35,6 +35,7 @@ import portable
try: try:
import resource import resource
def _rlimit_nofile(): def _rlimit_nofile():
return resource.getrlimit(resource.RLIMIT_NOFILE) return resource.getrlimit(resource.RLIMIT_NOFILE)
except ImportError: except ImportError:
...@@ -58,10 +59,12 @@ from progress import Progress ...@@ -58,10 +59,12 @@ from progress import Progress
_ONE_DAY_S = 24 * 60 * 60 _ONE_DAY_S = 24 * 60 * 60
class _FetchError(Exception): class _FetchError(Exception):
"""Internal error thrown in _FetchHelper() when we don't want stack trace.""" """Internal error thrown in _FetchHelper() when we don't want stack trace."""
pass pass
class Sync(Command, MirrorSafeCommand): class Sync(Command, MirrorSafeCommand):
jobs = 1 jobs = 1
common = True common = True
...@@ -296,8 +299,8 @@ later is required to fix a server side protocol bug. ...@@ -296,8 +299,8 @@ later is required to fix a server side protocol bug.
break break
sem.acquire() sem.acquire()
t = _threading.Thread(target = self._FetchHelper, t = _threading.Thread(target=self._FetchHelper,
args = (opt, args=(opt,
project, project,
lock, lock,
fetched, fetched,
...@@ -392,16 +395,16 @@ later is required to fix a server side protocol bug. ...@@ -392,16 +395,16 @@ later is required to fix a server side protocol bug.
# If the path has already been deleted, we don't need to do it # If the path has already been deleted, we don't need to do it
if os.path.exists(self.manifest.topdir + '/' + path): if os.path.exists(self.manifest.topdir + '/' + path):
project = Project( project = Project(
manifest = self.manifest, manifest=self.manifest,
name = path, name=path,
remote = RemoteSpec('origin'), remote=RemoteSpec('origin'),
gitdir = os.path.join(self.manifest.topdir, gitdir=os.path.join(self.manifest.topdir,
path, '.git'), path, '.git'),
worktree = os.path.join(self.manifest.topdir, path), worktree=os.path.join(self.manifest.topdir, path),
relpath = path, relpath=path,
revisionExpr = 'HEAD', revisionExpr='HEAD',
revisionId = None, revisionId=None,
groups = None) groups=None)
if project.IsDirty(): if project.IsDirty():
print('error: Cannot remove project "%s": uncommitted changes' print('error: Cannot remove project "%s": uncommitted changes'
...@@ -519,7 +522,7 @@ later is required to fix a server side protocol bug. ...@@ -519,7 +522,7 @@ later is required to fix a server side protocol bug.
else: else:
[success, manifest_str] = server.GetApprovedManifest(branch) [success, manifest_str] = server.GetApprovedManifest(branch)
else: else:
assert(opt.smart_tag) assert (opt.smart_tag)
[success, manifest_str] = server.GetManifest(opt.smart_tag) [success, manifest_str] = server.GetManifest(opt.smart_tag)
if success: if success:
...@@ -625,7 +628,7 @@ later is required to fix a server side protocol bug. ...@@ -625,7 +628,7 @@ later is required to fix a server side protocol bug.
sys.exit(1) sys.exit(1)
syncbuf = SyncBuffer(mp.config, syncbuf = SyncBuffer(mp.config,
detach_head = opt.detach_head) detach_head=opt.detach_head)
pm = Progress('Syncing work tree', len(all_projects)) pm = Progress('Syncing work tree', len(all_projects))
for project in all_projects: for project in all_projects:
pm.update() pm.update()
...@@ -641,6 +644,7 @@ later is required to fix a server side protocol bug. ...@@ -641,6 +644,7 @@ later is required to fix a server side protocol bug.
if self.manifest.notice: if self.manifest.notice:
print(self.manifest.notice) print(self.manifest.notice)
def _PostRepoUpgrade(manifest, quiet=False): def _PostRepoUpgrade(manifest, quiet=False):
wrapper = WrapperModule() wrapper = WrapperModule()
if wrapper.NeedSetupGnuPG(): if wrapper.NeedSetupGnuPG():
...@@ -649,6 +653,7 @@ def _PostRepoUpgrade(manifest, quiet=False): ...@@ -649,6 +653,7 @@ def _PostRepoUpgrade(manifest, quiet=False):
if project.Exists: if project.Exists:
project.PostRepoUpgrade() project.PostRepoUpgrade()
def _PostRepoFetch(rp, no_repo_verify=False, verbose=False): def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
if rp.HasChanges: if rp.HasChanges:
print('info: A new version of repo is available', file=sys.stderr) print('info: A new version of repo is available', file=sys.stderr)
...@@ -667,6 +672,7 @@ def _PostRepoFetch(rp, no_repo_verify=False, verbose=False): ...@@ -667,6 +672,7 @@ def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
print('repo version %s is current' % rp.work_git.describe(HEAD), print('repo version %s is current' % rp.work_git.describe(HEAD),
file=sys.stderr) file=sys.stderr)
def _VerifyTag(project): def _VerifyTag(project):
gpg_dir = os.path.expanduser('~/.repoconfig/gnupg') gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
if not os.path.exists(gpg_dir): if not os.path.exists(gpg_dir):
...@@ -697,9 +703,9 @@ def _VerifyTag(project): ...@@ -697,9 +703,9 @@ def _VerifyTag(project):
cmd = [GIT, 'tag', '-v', cur] cmd = [GIT, 'tag', '-v', cur]
proc = subprocess.Popen(cmd, proc = subprocess.Popen(cmd,
stdout = subprocess.PIPE, stdout=subprocess.PIPE,
stderr = subprocess.PIPE, stderr=subprocess.PIPE,
env = env) env=env)
out = proc.stdout.read() out = proc.stdout.read()
proc.stdout.close() proc.stdout.close()
...@@ -714,6 +720,7 @@ def _VerifyTag(project): ...@@ -714,6 +720,7 @@ def _VerifyTag(project):
return False return False
return True return True
class _FetchTimes(object): class _FetchTimes(object):
_ALPHA = 0.5 _ALPHA = 0.5
...@@ -732,7 +739,7 @@ class _FetchTimes(object): ...@@ -732,7 +739,7 @@ class _FetchTimes(object):
old = self._times.get(name, t) old = self._times.get(name, t)
self._seen.add(name) self._seen.add(name)
a = self._ALPHA a = self._ALPHA
self._times[name] = (a*t) + ((1-a) * old) self._times[name] = (a * t) + ((1 - a) * old)
def _Load(self): def _Load(self):
if self._times is None: if self._times is None:
......
...@@ -26,6 +26,7 @@ from project import RepoHook ...@@ -26,6 +26,7 @@ from project import RepoHook
UNUSUAL_COMMIT_THRESHOLD = 5 UNUSUAL_COMMIT_THRESHOLD = 5
def _ConfirmManyUploads(multiple_branches=False): def _ConfirmManyUploads(multiple_branches=False):
if multiple_branches: if multiple_branches:
print('ATTENTION: One or more branches has an unusually high number' print('ATTENTION: One or more branches has an unusually high number'
...@@ -37,17 +38,20 @@ def _ConfirmManyUploads(multiple_branches=False): ...@@ -37,17 +38,20 @@ def _ConfirmManyUploads(multiple_branches=False):
answer = input("If you are sure you intend to do this, type 'yes': ").strip() answer = input("If you are sure you intend to do this, type 'yes': ").strip()
return answer == "yes" return answer == "yes"
def _die(fmt, *args): def _die(fmt, *args):
msg = fmt % args msg = fmt % args
print('error: %s' % msg, file=sys.stderr) print('error: %s' % msg, file=sys.stderr)
sys.exit(1) sys.exit(1)
def _SplitEmails(values): def _SplitEmails(values):
result = [] result = []
for value in values: for value in values:
result.extend([s.strip() for s in value.split(',')]) result.extend([s.strip() for s in value.split(',')])
return result return result
class Upload(InteractiveCommand): class Upload(InteractiveCommand):
common = True common = True
helpSummary = "Upload changes for code review" helpSummary = "Upload changes for code review"
...@@ -235,10 +239,10 @@ Gerrit Code Review: http://code.google.com/p/gerrit/ ...@@ -235,10 +239,10 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
branches[project.name] = b branches[project.name] = b
script.append('') script.append('')
script = [ x.encode('utf-8') script = [x.encode('utf-8')
if issubclass(type(x), str) if issubclass(type(x), str)
else x else x
for x in script ] for x in script]
script = portable.stream2str(Editor.EditString("\n".join(script))).split("\n") script = portable.stream2str(Editor.EditString("\n".join(script))).split("\n")
...@@ -319,7 +323,8 @@ Gerrit Code Review: http://code.google.com/p/gerrit/ ...@@ -319,7 +323,8 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
# if they want to auto upload, let's not ask because it could be automated # if they want to auto upload, let's not ask because it could be automated
if answer is None: if answer is None:
sys.stdout.write('Uncommitted changes in ' + branch.project.name + ' (did you forget to amend?). Continue uploading? (y/N) ') sys.stdout.write(
'Uncommitted changes in ' + branch.project.name + ' (did you forget to amend?). Continue uploading? (y/N) ')
sys.stdout.flush() sys.stdout.flush()
a = sys.stdin.readline().strip().lower() a = sys.stdin.readline().strip().lower()
if a not in ('y', 'yes', 't', 'true', 'on'): if a not in ('y', 'yes', 't', 'true', 'on'):
......
...@@ -19,6 +19,7 @@ from command import Command, MirrorSafeCommand ...@@ -19,6 +19,7 @@ from command import Command, MirrorSafeCommand
from git_command import git from git_command import git
from git_refs import HEAD from git_refs import HEAD
class Version(Command, MirrorSafeCommand): class Version(Command, MirrorSafeCommand):
wrapper_version = None wrapper_version = None
wrapper_path = None wrapper_path = None
......
...@@ -38,6 +38,7 @@ def RunPager(): ...@@ -38,6 +38,7 @@ def RunPager():
print("fatal: cannot start pager '%s'" % pager, file=sys.stderr) print("fatal: cannot start pager '%s'" % pager, file=sys.stderr)
sys.exit(255) sys.exit(255)
def _BecomePager(pager): def _BecomePager(pager):
# Delaying execution of the pager until we have output # Delaying execution of the pager until we have output
# ready works around a long-standing bug in popularly # ready works around a long-standing bug in popularly
......
...@@ -38,6 +38,7 @@ def RunPager(): ...@@ -38,6 +38,7 @@ def RunPager():
print("fatal: cannot start pager '%s'" % pager, file=sys.stderr) print("fatal: cannot start pager '%s'" % pager, file=sys.stderr)
sys.exit(255) sys.exit(255)
def _BecomePager(pager): def _BecomePager(pager):
# Delaying execution of the pager until we have output # Delaying execution of the pager until we have output
# ready works around a long-standing bug in popularly # ready works around a long-standing bug in popularly
......
...@@ -3,14 +3,17 @@ import unittest ...@@ -3,14 +3,17 @@ import unittest
import git_config import git_config
def fixture(*paths): def fixture(*paths):
"""Return a path relative to test/fixtures. """Return a path relative to test/fixtures.
""" """
return os.path.join(os.path.dirname(__file__), 'fixtures', *paths) return os.path.join(os.path.dirname(__file__), 'fixtures', *paths)
class GitConfigUnitTest(unittest.TestCase): class GitConfigUnitTest(unittest.TestCase):
"""Tests the GitConfig class. """Tests the GitConfig class.
""" """
def setUp(self): def setUp(self):
"""Create a GitConfig object using the test.gitconfig fixture. """Create a GitConfig object using the test.gitconfig fixture.
""" """
...@@ -48,5 +51,6 @@ class GitConfigUnitTest(unittest.TestCase): ...@@ -48,5 +51,6 @@ class GitConfigUnitTest(unittest.TestCase):
val = config.GetString('empty') val = config.GetString('empty')
self.assertEqual(val, None) self.assertEqual(val, None)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment