Merge "Re-initialise repos git hooks when updating the forest"
diff --git a/.project b/.project
index 67e4a0f..3aefb86 100644
--- a/.project
+++ b/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>repo</name>
+ <name>git-repo</name>
<comment></comment>
<projects>
</projects>
diff --git a/.pydevproject b/.pydevproject
index 880abd6..27c2485 100644
--- a/.pydevproject
+++ b/.pydevproject
@@ -3,7 +3,7 @@
<pydev_project>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
-<path>/repo</path>
+<path>/git-repo</path>
</pydev_pathproperty>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
diff --git a/.pylintrc b/.pylintrc
index 9e8882e..10b842d 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -53,7 +53,7 @@
enable=RP0004
# Disable the message(s) with the given id(s).
-disable=R0903,R0912,R0913,R0914,R0915,W0141,C0111,C0103,W0603,W0703,R0911,C0301,C0302,R0902,R0904,W0142,W0212,E1101,E1103,R0201,W0201,W0122,W0232,RP0001,RP0003,RP0101,RP0002,RP0401,RP0701,RP0801
+disable=R0903,R0912,R0913,R0914,R0915,W0141,C0111,C0103,W0603,W0703,R0911,C0301,C0302,R0902,R0904,W0142,W0212,E1101,E1103,R0201,W0201,W0122,W0232,RP0001,RP0003,RP0101,RP0002,RP0401,RP0701,RP0801,F0401,E0611,R0801
[REPORTS]
diff --git a/command.py b/command.py
index 96d7848..287f4d3 100644
--- a/command.py
+++ b/command.py
@@ -136,11 +136,11 @@
groups = mp.config.GetString('manifest.groups')
if not groups:
- groups = 'all,-notdefault,platform-' + platform.system().lower()
+ groups = 'default,platform-' + platform.system().lower()
groups = [x for x in re.split(r'[,\s]+', groups) if x]
if not args:
- all_projects_list = all_projects.values()
+ all_projects_list = list(all_projects.values())
derived_projects = {}
for project in all_projects_list:
if submodules_ok or project.sync_s:
@@ -186,6 +186,17 @@
result.sort(key=_getpath)
return result
+ def FindProjects(self, args):
+ result = []
+ patterns = [re.compile(r'%s' % a, re.IGNORECASE) for a in args]
+ for project in self.GetProjects(''):
+ for pattern in patterns:
+ if pattern.search(project.name) or pattern.search(project.relpath):
+ result.append(project)
+ break
+ result.sort(key=lambda project: project.relpath)
+ return result
+
# pylint: disable=W0223
# Pylint warns that the `InteractiveCommand` and `PagedCommand` classes do not
# override method `Execute` which is abstract in `Command`. Since that method
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt
index 0bf09f6..59f6a2f 100644
--- a/docs/manifest-format.txt
+++ b/docs/manifest-format.txt
@@ -56,6 +56,8 @@
<!ATTLIST project sync-c CDATA #IMPLIED>
<!ATTLIST project sync-s CDATA #IMPLIED>
<!ATTLIST project upstream CDATA #IMPLIED>
+ <!ATTLIST project clone-depth CDATA #IMPLIED>
+ <!ATTLIST project force-path CDATA #IMPLIED>
<!ELEMENT annotation (EMPTY)>
<!ATTLIST annotation name CDATA #REQUIRED>
@@ -222,6 +224,16 @@
can be found. Used when syncing a revision locked manifest in
-c mode to avoid having to sync the entire ref space.
+Attribute `clone-depth`: Set the depth to use when fetching this
+project. If specified, this value will override any value given
+to repo init with the --depth option on the command line.
+
+Attribute `force-path`: Set to true to force this project to create the
+local mirror repository according to its `path` attribute (if supplied)
+rather than the `name` attribute. This attribute only applies to the
+local mirrors syncing, it will be ignored when syncing the projects in a
+client working directory.
+
Element annotation
------------------
diff --git a/git_config.py b/git_config.py
index 56cc6a2..9524df9 100644
--- a/git_config.py
+++ b/git_config.py
@@ -14,8 +14,9 @@
# limitations under the License.
from __future__ import print_function
-import cPickle
+
import os
+import pickle
import re
import subprocess
import sys
@@ -262,7 +263,7 @@
Trace(': unpickle %s', self.file)
fd = open(self._pickle, 'rb')
try:
- return cPickle.load(fd)
+ return pickle.load(fd)
finally:
fd.close()
except EOFError:
@@ -271,7 +272,7 @@
except IOError:
os.remove(self._pickle)
return None
- except cPickle.PickleError:
+ except pickle.PickleError:
os.remove(self._pickle)
return None
@@ -279,13 +280,13 @@
try:
fd = open(self._pickle, 'wb')
try:
- cPickle.dump(cache, fd, cPickle.HIGHEST_PROTOCOL)
+ pickle.dump(cache, fd, pickle.HIGHEST_PROTOCOL)
finally:
fd.close()
except IOError:
if os.path.exists(self._pickle):
os.remove(self._pickle)
- except cPickle.PickleError:
+ except pickle.PickleError:
if os.path.exists(self._pickle):
os.remove(self._pickle)
@@ -537,8 +538,8 @@
self.url = self._Get('url')
self.review = self._Get('review')
self.projectname = self._Get('projectname')
- self.fetch = map(RefSpec.FromString,
- self._Get('fetch', all_keys=True))
+ self.fetch = list(map(RefSpec.FromString,
+ self._Get('fetch', all_keys=True)))
self._review_url = None
def _InsteadOf(self):
@@ -657,7 +658,7 @@
self._Set('url', self.url)
self._Set('review', self.review)
self._Set('projectname', self.projectname)
- self._Set('fetch', map(str, self.fetch))
+ self._Set('fetch', list(map(str, self.fetch)))
def _Set(self, key, value):
key = 'remote.%s.%s' % (self.name, key)
diff --git a/git_refs.py b/git_refs.py
index cfeffba..4dd6876 100644
--- a/git_refs.py
+++ b/git_refs.py
@@ -66,7 +66,7 @@
def _NeedUpdate(self):
Trace(': scan refs %s', self._gitdir)
- for name, mtime in self._mtime.iteritems():
+ for name, mtime in self._mtime.items():
try:
if mtime != os.path.getmtime(os.path.join(self._gitdir, name)):
return True
@@ -89,7 +89,7 @@
attempts = 0
while scan and attempts < 5:
scan_next = {}
- for name, dest in scan.iteritems():
+ for name, dest in scan.items():
if dest in self._phyref:
self._phyref[name] = self._phyref[dest]
else:
@@ -108,6 +108,7 @@
return
try:
for line in fd:
+ line = str(line)
if line[0] == '#':
continue
if line[0] == '^':
@@ -150,6 +151,10 @@
finally:
fd.close()
+ try:
+ ref_id = ref_id.decode()
+ except AttributeError:
+ pass
if not ref_id:
return
ref_id = ref_id[:-1]
diff --git a/main.py b/main.py
index 9cc2639..49d2482 100755
--- a/main.py
+++ b/main.py
@@ -50,6 +50,11 @@
from subcmds import all_commands
+try:
+ input = raw_input
+except NameError:
+ pass
+
global_options = optparse.OptionParser(
usage="repo [-p|--paginate|--no-pager] COMMAND [ARGS]"
)
@@ -286,7 +291,7 @@
if user is None:
print(msg)
try:
- user = raw_input('User: ')
+ user = input('User: ')
password = getpass.getpass()
except KeyboardInterrupt:
return
diff --git a/manifest_xml.py b/manifest_xml.py
index 50417c6..cc441dc 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -18,7 +18,15 @@
import os
import re
import sys
-import urlparse
+try:
+ # For python3
+ import urllib.parse
+except ImportError:
+ # For python2
+ import imp
+ import urlparse
+ urllib = imp.new_module('urllib')
+ urllib.parse = urlparse
import xml.dom.minidom
from git_config import GitConfig
@@ -30,8 +38,8 @@
LOCAL_MANIFEST_NAME = 'local_manifest.xml'
LOCAL_MANIFESTS_DIR_NAME = 'local_manifests'
-urlparse.uses_relative.extend(['ssh', 'git'])
-urlparse.uses_netloc.extend(['ssh', 'git'])
+urllib.parse.uses_relative.extend(['ssh', 'git'])
+urllib.parse.uses_netloc.extend(['ssh', 'git'])
class _Default(object):
"""Project defaults within the manifest."""
@@ -73,7 +81,7 @@
# ie, if manifestUrl is of the form <hostname:port>
if manifestUrl.find(':') != manifestUrl.find('/') - 1:
manifestUrl = 'gopher://' + manifestUrl
- url = urlparse.urljoin(manifestUrl, url)
+ url = urllib.parse.urljoin(manifestUrl, url)
url = re.sub(r'^gopher://', '', url)
if p:
url = 'persistent-' + url
@@ -82,8 +90,6 @@
def ToRemoteSpec(self, projectName):
url = self.resolvedFetchUrl.rstrip('/') + '/' + projectName
remoteName = self.name
- if self.remoteAlias:
- remoteName = self.remoteAlias
return RemoteSpec(remoteName, url, self.reviewUrl)
class XmlManifest(object):
@@ -164,10 +170,8 @@
notice_element.appendChild(doc.createTextNode(indented_notice))
d = self.default
- sort_remotes = list(self.remotes.keys())
- sort_remotes.sort()
- for r in sort_remotes:
+ for r in sorted(self.remotes):
self._RemoteToXml(self.remotes[r], doc, root)
if self.remotes:
root.appendChild(doc.createTextNode(''))
@@ -259,12 +263,11 @@
e.setAttribute('sync-s', 'true')
if p.subprojects:
- sort_projects = [subp.name for subp in p.subprojects]
- sort_projects.sort()
+ sort_projects = list(sorted([subp.name for subp in p.subprojects]))
output_projects(p, e, sort_projects)
- sort_projects = [key for key in self.projects.keys()
- if not self.projects[key].parent]
+ sort_projects = list(sorted([key for key, value in self.projects.items()
+ if not value.parent]))
sort_projects.sort()
output_projects(None, root, sort_projects)
@@ -388,9 +391,8 @@
name = self._reqatt(node, 'name')
fp = os.path.join(include_root, name)
if not os.path.isfile(fp):
- raise ManifestParseError, \
- "include %s doesn't exist or isn't a file" % \
- (name,)
+ raise ManifestParseError("include %s doesn't exist or isn't a file"
+ % (name,))
try:
nodes.extend(self._ParseManifestXml(fp, include_root))
# should isolate this to the exact exception, but that's
@@ -496,7 +498,7 @@
name = None
m_url = m.GetRemote(m.remote.name).url
if m_url.endswith('/.git'):
- raise ManifestParseError, 'refusing to mirror %s' % m_url
+ raise ManifestParseError('refusing to mirror %s' % m_url)
if self._default and self._default.remote:
url = self._default.remote.resolvedFetchUrl
@@ -590,7 +592,7 @@
# Figure out minimum indentation, skipping the first line (the same line
# as the <notice> tag)...
- minIndent = sys.maxint
+ minIndent = sys.maxsize
lines = notice.splitlines()
for line in lines[1:]:
lstrippedLine = line.lstrip()
@@ -629,25 +631,22 @@
if remote is None:
remote = self._default.remote
if remote is None:
- raise ManifestParseError, \
- "no remote for project %s within %s" % \
- (name, self.manifestFile)
+ raise ManifestParseError("no remote for project %s within %s" %
+ (name, self.manifestFile))
revisionExpr = node.getAttribute('revision')
if not revisionExpr:
revisionExpr = self._default.revisionExpr
if not revisionExpr:
- raise ManifestParseError, \
- "no revision for project %s within %s" % \
- (name, self.manifestFile)
+ raise ManifestParseError("no revision for project %s within %s" %
+ (name, self.manifestFile))
path = node.getAttribute('path')
if not path:
path = name
if path.startswith('/'):
- raise ManifestParseError, \
- "project %s path cannot be absolute in %s" % \
- (name, self.manifestFile)
+ raise ManifestParseError("project %s path cannot be absolute in %s" %
+ (name, self.manifestFile))
rebase = node.getAttribute('rebase')
if not rebase:
@@ -667,6 +666,16 @@
else:
sync_s = sync_s.lower() in ("yes", "true", "1")
+ clone_depth = node.getAttribute('clone-depth')
+ if clone_depth:
+ try:
+ clone_depth = int(clone_depth)
+ if clone_depth <= 0:
+ raise ValueError()
+ except ValueError:
+ raise ManifestParseError('invalid clone-depth %s in %s' %
+ (clone_depth, self.manifestFile))
+
upstream = node.getAttribute('upstream')
groups = ''
@@ -682,6 +691,10 @@
default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath]
groups.extend(set(default_groups).difference(groups))
+ if self.IsMirror and node.hasAttribute('force-path'):
+ if node.getAttribute('force-path').lower() in ("yes", "true", "1"):
+ gitdir = os.path.join(self.topdir, '%s.git' % path)
+
project = Project(manifest = self,
name = name,
remote = remote.ToRemoteSpec(name),
@@ -694,6 +707,7 @@
groups = groups,
sync_c = sync_c,
sync_s = sync_s,
+ clone_depth = clone_depth,
upstream = upstream,
parent = parent)
@@ -751,7 +765,8 @@
except ManifestParseError:
keep = "true"
if keep != "true" and keep != "false":
- raise ManifestParseError, "optional \"keep\" attribute must be \"true\" or \"false\""
+ raise ManifestParseError('optional "keep" attribute must be '
+ '"true" or "false"')
project.AddAnnotation(name, value, keep)
def _get_remote(self, node):
@@ -761,9 +776,8 @@
v = self._remotes.get(name)
if not v:
- raise ManifestParseError, \
- "remote %s not defined in %s" % \
- (name, self.manifestFile)
+ raise ManifestParseError("remote %s not defined in %s" %
+ (name, self.manifestFile))
return v
def _reqatt(self, node, attname):
@@ -772,7 +786,6 @@
"""
v = node.getAttribute(attname)
if not v:
- raise ManifestParseError, \
- "no %s in <%s> within %s" % \
- (attname, node.nodeName, self.manifestFile)
+ raise ManifestParseError("no %s in <%s> within %s" %
+ (attname, node.nodeName, self.manifestFile))
return v
diff --git a/project.py b/project.py
index 792ad4c..516d3b6 100644
--- a/project.py
+++ b/project.py
@@ -36,6 +36,11 @@
from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M
+try:
+ input = raw_input
+except NameError:
+ pass
+
def _lwrite(path, content):
lock = '%s.lock' % path
@@ -78,7 +83,7 @@
if _project_hook_list is None:
d = os.path.abspath(os.path.dirname(__file__))
d = os.path.join(d , 'hooks')
- _project_hook_list = map(lambda x: os.path.join(d, x), os.listdir(d))
+ _project_hook_list = [os.path.join(d, x) for x in os.listdir(d)]
return _project_hook_list
@@ -361,7 +366,7 @@
'Do you want to allow this script to run '
'(yes/yes-never-ask-again/NO)? ') % (
self._GetMustVerb(), self._script_fullpath)
- response = raw_input(prompt).lower()
+ response = input(prompt).lower()
print()
# User is doing a one-time approval.
@@ -488,6 +493,7 @@
groups = None,
sync_c = False,
sync_s = False,
+ clone_depth = None,
upstream = None,
parent = None,
is_derived = False):
@@ -533,6 +539,7 @@
self.groups = groups
self.sync_c = sync_c
self.sync_s = sync_s
+ self.clone_depth = clone_depth
self.upstream = upstream
self.parent = parent
self.is_derived = is_derived
@@ -644,7 +651,7 @@
all_refs = self._allrefs
heads = {}
- for name, ref_id in all_refs.iteritems():
+ for name, ref_id in all_refs.items():
if name.startswith(R_HEADS):
name = name[len(R_HEADS):]
b = self.GetBranch(name)
@@ -653,7 +660,7 @@
b.revision = ref_id
heads[name] = b
- for name, ref_id in all_refs.iteritems():
+ for name, ref_id in all_refs.items():
if name.startswith(R_PUB):
name = name[len(R_PUB):]
b = heads.get(name)
@@ -672,9 +679,14 @@
project_groups: "all,group1,group2"
manifest_groups: "-group1,group2"
the project will be matched.
+
+ The special manifest group "default" will match any project that
+ does not have the special project group "notdefault"
"""
- expanded_manifest_groups = manifest_groups or ['all', '-notdefault']
+ expanded_manifest_groups = manifest_groups or ['default']
expanded_project_groups = ['all'] + (self.groups or [])
+ if not 'notdefault' in expanded_project_groups:
+ expanded_project_groups += ['default']
matched = False
for group in expanded_manifest_groups:
@@ -754,10 +766,7 @@
paths.extend(df.keys())
paths.extend(do)
- paths = list(set(paths))
- paths.sort()
-
- for p in paths:
+ for p in sorted(set(paths)):
try:
i = di[p]
except KeyError:
@@ -849,13 +858,13 @@
all_refs = self._allrefs
heads = set()
canrm = {}
- for name, ref_id in all_refs.iteritems():
+ for name, ref_id in all_refs.items():
if name.startswith(R_HEADS):
heads.add(name)
elif name.startswith(R_PUB):
canrm[name] = ref_id
- for name, ref_id in canrm.iteritems():
+ for name, ref_id in canrm.items():
n = name[len(R_PUB):]
if R_HEADS + n not in heads:
self.bare_git.DeleteRef(name, ref_id)
@@ -866,14 +875,14 @@
heads = {}
pubed = {}
- for name, ref_id in self._allrefs.iteritems():
+ for name, ref_id in self._allrefs.items():
if name.startswith(R_HEADS):
heads[name[len(R_HEADS):]] = ref_id
elif name.startswith(R_PUB):
pubed[name[len(R_PUB):]] = ref_id
ready = []
- for branch, ref_id in heads.iteritems():
+ for branch, ref_id in heads.items():
if branch in pubed and pubed[branch] == ref_id:
continue
if selected_branch and branch != selected_branch:
@@ -1218,7 +1227,7 @@
cmd = ['fetch', remote.name]
cmd.append('refs/changes/%2.2d/%d/%d' \
% (change_id % 100, change_id, patch_id))
- cmd.extend(map(str, remote.fetch))
+ cmd.extend(list(map(str, remote.fetch)))
if GitCommand(self, cmd, bare=True).Wait() != 0:
return None
return DownloadedChange(self,
@@ -1607,7 +1616,7 @@
ids = set(all_refs.values())
tmp = set()
- for r, ref_id in GitRefs(ref_dir).all.iteritems():
+ for r, ref_id in GitRefs(ref_dir).all.items():
if r not in all_refs:
if r.startswith(R_TAGS) or remote.WritesTo(r):
all_refs[r] = ref_id
@@ -1622,13 +1631,10 @@
ids.add(ref_id)
tmp.add(r)
- ref_names = list(all_refs.keys())
- ref_names.sort()
-
tmp_packed = ''
old_packed = ''
- for r in ref_names:
+ for r in sorted(all_refs):
line = '%s %s\n' % (all_refs[r], r)
tmp_packed += line
if r not in tmp:
@@ -1642,7 +1648,10 @@
# The --depth option only affects the initial fetch; after that we'll do
# full fetches of changes.
- depth = self.manifest.manifestProject.config.GetString('repo.depth')
+ if self.clone_depth:
+ depth = self.clone_depth
+ else:
+ depth = self.manifest.manifestProject.config.GetString('repo.depth')
if depth and initial:
cmd.append('--depth=%s' % depth)
@@ -1654,11 +1663,13 @@
if not current_branch_only:
# Fetch whole repo
- if no_tags:
+ # If using depth then we should not get all the tags since they may
+ # be outside of the depth.
+ if no_tags or depth:
cmd.append('--no-tags')
else:
cmd.append('--tags')
- cmd.append((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*'))
+ cmd.append(str((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*')))
elif tag_name is not None:
cmd.append('tag')
cmd.append(tag_name)
@@ -1668,7 +1679,7 @@
branch = self.upstream
if branch.startswith(R_HEADS):
branch = branch[len(R_HEADS):]
- cmd.append((u'+refs/heads/%s:' % branch) + remote.ToLocal('refs/heads/%s' % branch))
+ cmd.append(str((u'+refs/heads/%s:' % branch) + remote.ToLocal('refs/heads/%s' % branch)))
ok = False
for _i in range(2):
@@ -1702,7 +1713,7 @@
return ok
def _ApplyCloneBundle(self, initial=False, quiet=False):
- if initial and self.manifest.manifestProject.config.GetString('repo.depth'):
+ if initial and (self.manifest.manifestProject.config.GetString('repo.depth') or self.clone_depth):
return False
remote = self.GetRemote(self.remote.name)
@@ -2099,6 +2110,10 @@
line = fd.read()
finally:
fd.close()
+ try:
+ line = line.decode()
+ except AttributeError:
+ pass
if line.startswith('ref: '):
return line[5:-1]
return line[:-1]
@@ -2192,7 +2207,7 @@
if not git_require((1, 7, 2)):
raise ValueError('cannot set config on command line for %s()'
% name)
- for k, v in config.iteritems():
+ for k, v in config.items():
cmdv.append('-c')
cmdv.append('%s=%s' % (k, v))
cmdv.append(name)
@@ -2208,6 +2223,10 @@
name,
p.stderr))
r = p.stdout
+ try:
+ r = r.decode()
+ except AttributeError:
+ pass
if r.endswith('\n') and r.index('\n') == len(r) - 1:
return r[:-1]
return r
diff --git a/repo b/repo
index 6b374f7..791e40c 100755
--- a/repo
+++ b/repo
@@ -108,6 +108,7 @@
S_repo = 'repo' # special repo repository
S_manifests = 'manifests' # special manifest repository
REPO_MAIN = S_repo + '/main.py' # main script
+MIN_PYTHON_VERSION = (2, 6) # minimum supported python version
import optparse
@@ -129,6 +130,19 @@
urllib.request = urllib2
urllib.error = urllib2
+# Python version check
+ver = sys.version_info
+if ver[0] == 3:
+ print('error: Python 3 support is not fully implemented in repo yet.\n'
+ 'Please use Python 2.6 - 2.7 instead.',
+ file=sys.stderr)
+ sys.exit(1)
+if (ver[0], ver[1]) < MIN_PYTHON_VERSION:
+ print('error: Python version %s unsupported.\n'
+ 'Please use Python 2.6 - 2.7 instead.'
+ % sys.version.split(' ')[0], file=sys.stderr)
+ sys.exit(1)
+
home_dot_repo = os.path.expanduser('~/.repoconfig')
gpg_dir = os.path.join(home_dot_repo, 'gnupg')
@@ -164,7 +178,8 @@
help='create a shallow clone with given depth; see git clone')
group.add_option('-g', '--groups',
dest='groups', default='default',
- help='restrict manifest projects to ones with a specified group',
+ help='restrict manifest projects to ones with specified '
+ 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]',
metavar='GROUP')
group.add_option('-p', '--platform',
dest='platform', default="auto",
diff --git a/subcmds/__init__.py b/subcmds/__init__.py
index 1fac802..84efb4d 100644
--- a/subcmds/__init__.py
+++ b/subcmds/__init__.py
@@ -38,8 +38,8 @@
try:
cmd = getattr(mod, clsn)()
except AttributeError:
- raise SyntaxError, '%s/%s does not define class %s' % (
- __name__, py, clsn)
+ raise SyntaxError('%s/%s does not define class %s' % (
+ __name__, py, clsn))
name = name.replace('_', '-')
cmd.NAME = name
diff --git a/subcmds/branches.py b/subcmds/branches.py
index 06d45ab..c2e7c4b 100644
--- a/subcmds/branches.py
+++ b/subcmds/branches.py
@@ -98,14 +98,13 @@
project_cnt = len(projects)
for project in projects:
- for name, b in project.GetBranches().iteritems():
+ for name, b in project.GetBranches().items():
b.project = project
if name not in all_branches:
all_branches[name] = BranchInfo(name)
all_branches[name].add(b)
- names = all_branches.keys()
- names.sort()
+ names = list(sorted(all_branches))
if not names:
print(' (no branches)', file=sys.stderr)
diff --git a/subcmds/forall.py b/subcmds/forall.py
index 4c1c9ff..7d5f779 100644
--- a/subcmds/forall.py
+++ b/subcmds/forall.py
@@ -42,10 +42,14 @@
helpSummary = "Run a shell command in each project"
helpUsage = """
%prog [<project>...] -c <command> [<arg>...]
+%prog -r str1 [str2] ... -c <command> [<arg>...]"
"""
helpDescription = """
Executes the same shell command in each project.
+The -r option allows running the command only on projects matching
+regex or wildcard expression.
+
Output Formatting
-----------------
@@ -103,6 +107,9 @@
setattr(parser.values, option.dest, list(parser.rargs))
while parser.rargs:
del parser.rargs[0]
+ p.add_option('-r', '--regex',
+ dest='regex', action='store_true',
+ help="Execute the command only on projects matching regex or wildcard expression")
p.add_option('-c', '--command',
help='Command (and arguments) to execute',
dest='command',
@@ -166,7 +173,12 @@
rc = 0
first = True
- for project in self.GetProjects(args):
+ if not opt.regex:
+ projects = self.GetProjects(args)
+ else:
+ projects = self.FindProjects(args)
+
+ for project in projects:
env = os.environ.copy()
def setenv(name, val):
if val is None:
diff --git a/subcmds/help.py b/subcmds/help.py
index 7842882..4aa3f86 100644
--- a/subcmds/help.py
+++ b/subcmds/help.py
@@ -34,8 +34,7 @@
def _PrintAllCommands(self):
print('usage: repo COMMAND [ARGS]')
print('The complete list of recognized repo commands are:')
- commandNames = self.commands.keys()
- commandNames.sort()
+ commandNames = list(sorted(self.commands))
maxlen = 0
for name in commandNames:
@@ -55,10 +54,9 @@
def _PrintCommonCommands(self):
print('usage: repo COMMAND [ARGS]')
print('The most commonly used repo commands are:')
- commandNames = [name
- for name in self.commands.keys()
- if self.commands[name].common]
- commandNames.sort()
+ commandNames = list(sorted([name
+ for name, command in self.commands.items()
+ if command.common]))
maxlen = 0
for name in commandNames:
diff --git a/subcmds/info.py b/subcmds/info.py
index 325874b..c10e56c 100644
--- a/subcmds/info.py
+++ b/subcmds/info.py
@@ -163,7 +163,7 @@
all_branches = []
for project in self.GetProjects(args):
br = [project.GetUploadableBranch(x)
- for x in project.GetBranches().keys()]
+ for x in project.GetBranches()]
br = [x for x in br if x]
if self.opt.current_branch:
br = [x for x in br if x.name == project.CurrentBranch]
diff --git a/subcmds/init.py b/subcmds/init.py
index 1131260..29730cc 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -91,8 +91,9 @@
dest='depth',
help='create a shallow clone with given depth; see git clone')
g.add_option('-g', '--groups',
- dest='groups', default='all,-notdefault',
- help='restrict manifest projects to ones with a specified group',
+ dest='groups', default='default',
+ help='restrict manifest projects to ones with specified '
+ 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]',
metavar='GROUP')
g.add_option('-p', '--platform',
dest='platform', default='auto',
@@ -169,7 +170,7 @@
groups = [x for x in groups if x]
groupstr = ','.join(groups)
- if opt.platform == 'auto' and groupstr == 'all,-notdefault,platform-' + platform.system().lower():
+ if opt.platform == 'auto' and groupstr == 'default,platform-' + platform.system().lower():
groupstr = None
m.config.SetString('manifest.groups', groupstr)
diff --git a/subcmds/list.py b/subcmds/list.py
index 0d5c27f..a335824 100644
--- a/subcmds/list.py
+++ b/subcmds/list.py
@@ -14,7 +14,7 @@
# limitations under the License.
from __future__ import print_function
-import re
+import sys
from command import Command, MirrorSafeCommand
@@ -38,6 +38,12 @@
p.add_option('-f', '--fullpath',
dest='fullpath', action='store_true',
help="Display the full work tree path instead of the relative path")
+ p.add_option('-n', '--name-only',
+ dest='name_only', action='store_true',
+ help="Display only the name of the repository")
+ p.add_option('-p', '--path-only',
+ dest='path_only', action='store_true',
+ help="Display only the path of the repository")
def Execute(self, opt, args):
"""List all projects and the associated directories.
@@ -50,6 +56,11 @@
opt: The options.
args: Positional args. Can be a list of projects to list, or empty.
"""
+
+ if opt.fullpath and opt.name_only:
+ print('error: cannot combine -f and -n', file=sys.stderr)
+ sys.exit(1)
+
if not opt.regex:
projects = self.GetProjects(args)
else:
@@ -62,18 +73,12 @@
lines = []
for project in projects:
- lines.append("%s : %s" % (_getpath(project), project.name))
+ if opt.name_only and not opt.path_only:
+ lines.append("%s" % ( project.name))
+ elif opt.path_only and not opt.name_only:
+ lines.append("%s" % (_getpath(project)))
+ else:
+ lines.append("%s : %s" % (_getpath(project), project.name))
lines.sort()
print('\n'.join(lines))
-
- def FindProjects(self, args):
- result = []
- for project in self.GetProjects(''):
- for arg in args:
- pattern = re.compile(r'%s' % arg, re.IGNORECASE)
- if pattern.search(project.name) or pattern.search(project.relpath):
- result.append(project)
- break
- result.sort(key=lambda project: project.relpath)
- return result
diff --git a/subcmds/overview.py b/subcmds/overview.py
index 418459a..eed8cf2 100644
--- a/subcmds/overview.py
+++ b/subcmds/overview.py
@@ -42,7 +42,7 @@
all_branches = []
for project in self.GetProjects(args):
br = [project.GetUploadableBranch(x)
- for x in project.GetBranches().keys()]
+ for x in project.GetBranches()]
br = [x for x in br if x]
if opt.current_branch:
br = [x for x in br if x.name == project.CurrentBranch]
diff --git a/subcmds/stage.py b/subcmds/stage.py
index ff15ee0..2884976 100644
--- a/subcmds/stage.py
+++ b/subcmds/stage.py
@@ -49,7 +49,7 @@
self.Usage()
def _Interactive(self, opt, args):
- all_projects = filter(lambda x: x.IsDirty(), self.GetProjects(args))
+ all_projects = [p for p in self.GetProjects(args) if p.IsDirty()]
if not all_projects:
print('no projects have uncommitted modifications', file=sys.stderr)
return
@@ -98,9 +98,9 @@
_AddI(all_projects[a_index - 1])
continue
- p = filter(lambda x: x.name == a or x.relpath == a, all_projects)
- if len(p) == 1:
- _AddI(p[0])
+ projects = [p for p in all_projects if a in [p.name, p.relpath]]
+ if len(projects) == 1:
+ _AddI(projects[0])
continue
print('Bye.')
diff --git a/subcmds/status.py b/subcmds/status.py
index cce00c8..9810337 100644
--- a/subcmds/status.py
+++ b/subcmds/status.py
@@ -21,10 +21,15 @@
import dummy_threading as _threading
import glob
+try:
+ # For python2
+ import StringIO as io
+except ImportError:
+ # For python3
+ import io
import itertools
import os
import sys
-import StringIO
from color import Coloring
@@ -142,7 +147,7 @@
for project in all_projects:
sem.acquire()
- class BufList(StringIO.StringIO):
+ class BufList(io.StringIO):
def dump(self, ostream):
for entry in self.buflist:
ostream.write(entry)
@@ -182,7 +187,7 @@
try:
os.chdir(self.manifest.topdir)
- outstring = StringIO.StringIO()
+ outstring = io.StringIO()
self._FindOrphans(glob.glob('.*') + \
glob.glob('*'), \
proj_dirs, proj_dirs_parents, outstring)
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 6c903ff..8fb9488 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -24,8 +24,24 @@
import subprocess
import sys
import time
-import urlparse
-import xmlrpclib
+try:
+ # For python3
+ import urllib.parse
+except ImportError:
+ # For python2
+ import imp
+ import urlparse
+ urllib = imp.new_module('urllib')
+ urllib.parse = urlparse
+try:
+ # For python3
+ import xmlrpc.client
+except ImportError:
+ # For python2
+ import imp
+ import xmlrpclib
+ xmlrpc = imp.new_module('xmlrpc')
+ xmlrpc.client = xmlrpclib
try:
import threading as _threading
@@ -228,6 +244,9 @@
# We'll set to true once we've locked the lock.
did_lock = False
+ if not opt.quiet:
+ print('Fetching project %s' % project.name)
+
# Encapsulate everything in a try/except/finally so that:
# - We always set err_event in the case of an exception.
# - We always make sure we call sem.release().
@@ -274,6 +293,8 @@
if self.jobs == 1:
for project in projects:
pm.update()
+ if not opt.quiet:
+ print('Fetching project %s' % project.name)
if project.Sync_NetworkHalf(
quiet=opt.quiet,
current_branch_only=opt.current_branch_only,
@@ -372,6 +393,13 @@
print('\nerror: Exited sync due to gc errors', file=sys.stderr)
sys.exit(1)
+ def _ReloadManifest(self, manifest_name=None):
+ if manifest_name:
+ # Override calls _Unload already
+ self.manifest.Override(manifest_name)
+ else:
+ self.manifest._Unload()
+
def UpdateProjectList(self):
new_project_paths = []
for project in self.GetProjects(None, missing_ok=True):
@@ -486,7 +514,7 @@
file=sys.stderr)
else:
try:
- parse_result = urlparse.urlparse(manifest_server)
+ parse_result = urllib.parse(manifest_server)
if parse_result.hostname:
username, _account, password = \
info.authenticators(parse_result.hostname)
@@ -504,7 +532,7 @@
1)
try:
- server = xmlrpclib.Server(manifest_server)
+ server = xmlrpc.client.Server(manifest_server)
if opt.smart_sync:
p = self.manifest.manifestProject
b = p.GetBranch(p.CurrentBranch)
@@ -513,8 +541,7 @@
branch = branch[len(R_HEADS):]
env = os.environ.copy()
- if (env.has_key('TARGET_PRODUCT') and
- env.has_key('TARGET_BUILD_VARIANT')):
+ if 'TARGET_PRODUCT' in env and 'TARGET_BUILD_VARIANT' in env:
target = '%s-%s' % (env['TARGET_PRODUCT'],
env['TARGET_BUILD_VARIANT'])
[success, manifest_str] = server.GetApprovedManifest(branch, target)
@@ -542,11 +569,11 @@
else:
print('error: %s' % manifest_str, file=sys.stderr)
sys.exit(1)
- except (socket.error, IOError, xmlrpclib.Fault) as e:
+ except (socket.error, IOError, xmlrpc.client.Fault) as e:
print('error: cannot connect to manifest server %s:\n%s'
% (self.manifest.manifest_server, e), file=sys.stderr)
sys.exit(1)
- except xmlrpclib.ProtocolError as e:
+ except xmlrpc.client.ProtocolError as e:
print('error: cannot connect to manifest server %s:\n%d %s'
% (self.manifest.manifest_server, e.errcode, e.errmsg),
file=sys.stderr)
@@ -571,7 +598,7 @@
mp.Sync_LocalHalf(syncbuf)
if not syncbuf.Finish():
sys.exit(1)
- self.manifest._Unload()
+ self._ReloadManifest(opt.manifest_name)
if opt.jobs is None:
self.jobs = self.manifest.default.sync_j
all_projects = self.GetProjects(args,
@@ -596,7 +623,7 @@
# Iteratively fetch missing and/or nested unregistered submodules
previously_missing_set = set()
while True:
- self.manifest._Unload()
+ self._ReloadManifest(opt.manifest_name)
all_projects = self.GetProjects(args,
missing_ok=True,
submodules_ok=opt.fetch_submodules)
diff --git a/subcmds/upload.py b/subcmds/upload.py
index 48ee685..a34938e 100644
--- a/subcmds/upload.py
+++ b/subcmds/upload.py
@@ -23,6 +23,11 @@
from error import HookError, UploadError
from project import RepoHook
+try:
+ input = raw_input
+except NameError:
+ pass
+
UNUSUAL_COMMIT_THRESHOLD = 5
def _ConfirmManyUploads(multiple_branches=False):
@@ -33,7 +38,7 @@
print('ATTENTION: You are uploading an unusually high number of commits.')
print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across '
'branches?)')
- answer = raw_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"
def _die(fmt, *args):