Commit cca15f81 authored by Matthias Putz's avatar Matthias Putz

adapted style to PEP8 style guide

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