diff options
-rw-r--r-- | .project | 2 | ||||
-rw-r--r-- | .pydevproject | 2 | ||||
-rw-r--r-- | .pylintrc | 2 | ||||
-rw-r--r-- | command.py | 15 | ||||
-rw-r--r-- | docs/manifest-format.txt | 12 | ||||
-rw-r--r-- | git_config.py | 17 | ||||
-rw-r--r-- | git_refs.py | 9 | ||||
-rwxr-xr-x | main.py | 7 | ||||
-rw-r--r-- | manifest_xml.py | 81 | ||||
-rw-r--r-- | project.py | 69 | ||||
-rwxr-xr-x | repo | 17 | ||||
-rw-r--r-- | subcmds/__init__.py | 4 | ||||
-rw-r--r-- | subcmds/branches.py | 5 | ||||
-rw-r--r-- | subcmds/forall.py | 14 | ||||
-rw-r--r-- | subcmds/help.py | 10 | ||||
-rw-r--r-- | subcmds/info.py | 2 | ||||
-rw-r--r-- | subcmds/init.py | 7 | ||||
-rw-r--r-- | subcmds/list.py | 31 | ||||
-rw-r--r-- | subcmds/overview.py | 2 | ||||
-rw-r--r-- | subcmds/stage.py | 8 | ||||
-rw-r--r-- | subcmds/status.py | 11 | ||||
-rw-r--r-- | subcmds/sync.py | 47 | ||||
-rw-r--r-- | subcmds/upload.py | 7 |
23 files changed, 257 insertions, 124 deletions
@@ -1,6 +1,6 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <projectDescription> | 2 | <projectDescription> |
3 | <name>repo</name> | 3 | <name>git-repo</name> |
4 | <comment></comment> | 4 | <comment></comment> |
5 | <projects> | 5 | <projects> |
6 | </projects> | 6 | </projects> |
diff --git a/.pydevproject b/.pydevproject index 880abd62..27c2485a 100644 --- a/.pydevproject +++ b/.pydevproject | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | <pydev_project> | 4 | <pydev_project> |
5 | <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> | 5 | <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> |
6 | <path>/repo</path> | 6 | <path>/git-repo</path> |
7 | </pydev_pathproperty> | 7 | </pydev_pathproperty> |
8 | <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property> | 8 | <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property> |
9 | <pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> | 9 | <pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> |
@@ -53,7 +53,7 @@ load-plugins= | |||
53 | enable=RP0004 | 53 | enable=RP0004 |
54 | 54 | ||
55 | # Disable the message(s) with the given id(s). | 55 | # Disable the message(s) with the given id(s). |
56 | 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 | 56 | 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 |
57 | 57 | ||
58 | [REPORTS] | 58 | [REPORTS] |
59 | 59 | ||
@@ -136,11 +136,11 @@ class Command(object): | |||
136 | 136 | ||
137 | groups = mp.config.GetString('manifest.groups') | 137 | groups = mp.config.GetString('manifest.groups') |
138 | if not groups: | 138 | if not groups: |
139 | groups = 'all,-notdefault,platform-' + platform.system().lower() | 139 | groups = 'default,platform-' + platform.system().lower() |
140 | groups = [x for x in re.split(r'[,\s]+', groups) if x] | 140 | groups = [x for x in re.split(r'[,\s]+', groups) if x] |
141 | 141 | ||
142 | if not args: | 142 | if not args: |
143 | all_projects_list = all_projects.values() | 143 | all_projects_list = list(all_projects.values()) |
144 | derived_projects = {} | 144 | derived_projects = {} |
145 | for project in all_projects_list: | 145 | for project in all_projects_list: |
146 | if submodules_ok or project.sync_s: | 146 | if submodules_ok or project.sync_s: |
@@ -186,6 +186,17 @@ class Command(object): | |||
186 | result.sort(key=_getpath) | 186 | result.sort(key=_getpath) |
187 | return result | 187 | return result |
188 | 188 | ||
189 | def FindProjects(self, args): | ||
190 | result = [] | ||
191 | patterns = [re.compile(r'%s' % a, re.IGNORECASE) for a in args] | ||
192 | for project in self.GetProjects(''): | ||
193 | for pattern in patterns: | ||
194 | if pattern.search(project.name) or pattern.search(project.relpath): | ||
195 | result.append(project) | ||
196 | break | ||
197 | result.sort(key=lambda project: project.relpath) | ||
198 | return result | ||
199 | |||
189 | # pylint: disable=W0223 | 200 | # pylint: disable=W0223 |
190 | # Pylint warns that the `InteractiveCommand` and `PagedCommand` classes do not | 201 | # Pylint warns that the `InteractiveCommand` and `PagedCommand` classes do not |
191 | # override method `Execute` which is abstract in `Command`. Since that method | 202 | # override method `Execute` which is abstract in `Command`. Since that method |
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt index 0bf09f6f..59f6a2fd 100644 --- a/docs/manifest-format.txt +++ b/docs/manifest-format.txt | |||
@@ -56,6 +56,8 @@ following DTD: | |||
56 | <!ATTLIST project sync-c CDATA #IMPLIED> | 56 | <!ATTLIST project sync-c CDATA #IMPLIED> |
57 | <!ATTLIST project sync-s CDATA #IMPLIED> | 57 | <!ATTLIST project sync-s CDATA #IMPLIED> |
58 | <!ATTLIST project upstream CDATA #IMPLIED> | 58 | <!ATTLIST project upstream CDATA #IMPLIED> |
59 | <!ATTLIST project clone-depth CDATA #IMPLIED> | ||
60 | <!ATTLIST project force-path CDATA #IMPLIED> | ||
59 | 61 | ||
60 | <!ELEMENT annotation (EMPTY)> | 62 | <!ELEMENT annotation (EMPTY)> |
61 | <!ATTLIST annotation name CDATA #REQUIRED> | 63 | <!ATTLIST annotation name CDATA #REQUIRED> |
@@ -222,6 +224,16 @@ Attribute `upstream`: Name of the Git branch in which a sha1 | |||
222 | can be found. Used when syncing a revision locked manifest in | 224 | can be found. Used when syncing a revision locked manifest in |
223 | -c mode to avoid having to sync the entire ref space. | 225 | -c mode to avoid having to sync the entire ref space. |
224 | 226 | ||
227 | Attribute `clone-depth`: Set the depth to use when fetching this | ||
228 | project. If specified, this value will override any value given | ||
229 | to repo init with the --depth option on the command line. | ||
230 | |||
231 | Attribute `force-path`: Set to true to force this project to create the | ||
232 | local mirror repository according to its `path` attribute (if supplied) | ||
233 | rather than the `name` attribute. This attribute only applies to the | ||
234 | local mirrors syncing, it will be ignored when syncing the projects in a | ||
235 | client working directory. | ||
236 | |||
225 | Element annotation | 237 | Element annotation |
226 | ------------------ | 238 | ------------------ |
227 | 239 | ||
diff --git a/git_config.py b/git_config.py index 56cc6a24..9524df9b 100644 --- a/git_config.py +++ b/git_config.py | |||
@@ -14,8 +14,9 @@ | |||
14 | # limitations under the License. | 14 | # limitations under the License. |
15 | 15 | ||
16 | from __future__ import print_function | 16 | from __future__ import print_function |
17 | import cPickle | 17 | |
18 | import os | 18 | import os |
19 | import pickle | ||
19 | import re | 20 | import re |
20 | import subprocess | 21 | import subprocess |
21 | import sys | 22 | import sys |
@@ -262,7 +263,7 @@ class GitConfig(object): | |||
262 | Trace(': unpickle %s', self.file) | 263 | Trace(': unpickle %s', self.file) |
263 | fd = open(self._pickle, 'rb') | 264 | fd = open(self._pickle, 'rb') |
264 | try: | 265 | try: |
265 | return cPickle.load(fd) | 266 | return pickle.load(fd) |
266 | finally: | 267 | finally: |
267 | fd.close() | 268 | fd.close() |
268 | except EOFError: | 269 | except EOFError: |
@@ -271,7 +272,7 @@ class GitConfig(object): | |||
271 | except IOError: | 272 | except IOError: |
272 | os.remove(self._pickle) | 273 | os.remove(self._pickle) |
273 | return None | 274 | return None |
274 | except cPickle.PickleError: | 275 | except pickle.PickleError: |
275 | os.remove(self._pickle) | 276 | os.remove(self._pickle) |
276 | return None | 277 | return None |
277 | 278 | ||
@@ -279,13 +280,13 @@ class GitConfig(object): | |||
279 | try: | 280 | try: |
280 | fd = open(self._pickle, 'wb') | 281 | fd = open(self._pickle, 'wb') |
281 | try: | 282 | try: |
282 | cPickle.dump(cache, fd, cPickle.HIGHEST_PROTOCOL) | 283 | pickle.dump(cache, fd, pickle.HIGHEST_PROTOCOL) |
283 | finally: | 284 | finally: |
284 | fd.close() | 285 | fd.close() |
285 | except IOError: | 286 | except IOError: |
286 | if os.path.exists(self._pickle): | 287 | if os.path.exists(self._pickle): |
287 | os.remove(self._pickle) | 288 | os.remove(self._pickle) |
288 | except cPickle.PickleError: | 289 | except pickle.PickleError: |
289 | if os.path.exists(self._pickle): | 290 | if os.path.exists(self._pickle): |
290 | os.remove(self._pickle) | 291 | os.remove(self._pickle) |
291 | 292 | ||
@@ -537,8 +538,8 @@ class Remote(object): | |||
537 | self.url = self._Get('url') | 538 | self.url = self._Get('url') |
538 | self.review = self._Get('review') | 539 | self.review = self._Get('review') |
539 | self.projectname = self._Get('projectname') | 540 | self.projectname = self._Get('projectname') |
540 | self.fetch = map(RefSpec.FromString, | 541 | self.fetch = list(map(RefSpec.FromString, |
541 | self._Get('fetch', all_keys=True)) | 542 | self._Get('fetch', all_keys=True))) |
542 | self._review_url = None | 543 | self._review_url = None |
543 | 544 | ||
544 | def _InsteadOf(self): | 545 | def _InsteadOf(self): |
@@ -657,7 +658,7 @@ class Remote(object): | |||
657 | self._Set('url', self.url) | 658 | self._Set('url', self.url) |
658 | self._Set('review', self.review) | 659 | self._Set('review', self.review) |
659 | self._Set('projectname', self.projectname) | 660 | self._Set('projectname', self.projectname) |
660 | self._Set('fetch', map(str, self.fetch)) | 661 | self._Set('fetch', list(map(str, self.fetch))) |
661 | 662 | ||
662 | def _Set(self, key, value): | 663 | def _Set(self, key, value): |
663 | key = 'remote.%s.%s' % (self.name, key) | 664 | key = 'remote.%s.%s' % (self.name, key) |
diff --git a/git_refs.py b/git_refs.py index cfeffba9..4dd68769 100644 --- a/git_refs.py +++ b/git_refs.py | |||
@@ -66,7 +66,7 @@ class GitRefs(object): | |||
66 | def _NeedUpdate(self): | 66 | def _NeedUpdate(self): |
67 | Trace(': scan refs %s', self._gitdir) | 67 | Trace(': scan refs %s', self._gitdir) |
68 | 68 | ||
69 | for name, mtime in self._mtime.iteritems(): | 69 | for name, mtime in self._mtime.items(): |
70 | try: | 70 | try: |
71 | if mtime != os.path.getmtime(os.path.join(self._gitdir, name)): | 71 | if mtime != os.path.getmtime(os.path.join(self._gitdir, name)): |
72 | return True | 72 | return True |
@@ -89,7 +89,7 @@ class GitRefs(object): | |||
89 | attempts = 0 | 89 | attempts = 0 |
90 | while scan and attempts < 5: | 90 | while scan and attempts < 5: |
91 | scan_next = {} | 91 | scan_next = {} |
92 | for name, dest in scan.iteritems(): | 92 | for name, dest in scan.items(): |
93 | if dest in self._phyref: | 93 | if dest in self._phyref: |
94 | self._phyref[name] = self._phyref[dest] | 94 | self._phyref[name] = self._phyref[dest] |
95 | else: | 95 | else: |
@@ -108,6 +108,7 @@ class GitRefs(object): | |||
108 | return | 108 | return |
109 | try: | 109 | try: |
110 | for line in fd: | 110 | for line in fd: |
111 | line = str(line) | ||
111 | if line[0] == '#': | 112 | if line[0] == '#': |
112 | continue | 113 | continue |
113 | if line[0] == '^': | 114 | if line[0] == '^': |
@@ -150,6 +151,10 @@ class GitRefs(object): | |||
150 | finally: | 151 | finally: |
151 | fd.close() | 152 | fd.close() |
152 | 153 | ||
154 | try: | ||
155 | ref_id = ref_id.decode() | ||
156 | except AttributeError: | ||
157 | pass | ||
153 | if not ref_id: | 158 | if not ref_id: |
154 | return | 159 | return |
155 | ref_id = ref_id[:-1] | 160 | ref_id = ref_id[:-1] |
@@ -50,6 +50,11 @@ from pager import RunPager | |||
50 | 50 | ||
51 | from subcmds import all_commands | 51 | from subcmds import all_commands |
52 | 52 | ||
53 | try: | ||
54 | input = raw_input | ||
55 | except NameError: | ||
56 | pass | ||
57 | |||
53 | global_options = optparse.OptionParser( | 58 | global_options = optparse.OptionParser( |
54 | usage="repo [-p|--paginate|--no-pager] COMMAND [ARGS]" | 59 | usage="repo [-p|--paginate|--no-pager] COMMAND [ARGS]" |
55 | ) | 60 | ) |
@@ -286,7 +291,7 @@ def _AddPasswordFromUserInput(handler, msg, req): | |||
286 | if user is None: | 291 | if user is None: |
287 | print(msg) | 292 | print(msg) |
288 | try: | 293 | try: |
289 | user = raw_input('User: ') | 294 | user = input('User: ') |
290 | password = getpass.getpass() | 295 | password = getpass.getpass() |
291 | except KeyboardInterrupt: | 296 | except KeyboardInterrupt: |
292 | return | 297 | return |
diff --git a/manifest_xml.py b/manifest_xml.py index 50417c60..cc441dc8 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
@@ -18,7 +18,15 @@ import itertools | |||
18 | import os | 18 | import os |
19 | import re | 19 | import re |
20 | import sys | 20 | import sys |
21 | import urlparse | 21 | try: |
22 | # For python3 | ||
23 | import urllib.parse | ||
24 | except ImportError: | ||
25 | # For python2 | ||
26 | import imp | ||
27 | import urlparse | ||
28 | urllib = imp.new_module('urllib') | ||
29 | urllib.parse = urlparse | ||
22 | import xml.dom.minidom | 30 | import xml.dom.minidom |
23 | 31 | ||
24 | from git_config import GitConfig | 32 | from git_config import GitConfig |
@@ -30,8 +38,8 @@ MANIFEST_FILE_NAME = 'manifest.xml' | |||
30 | LOCAL_MANIFEST_NAME = 'local_manifest.xml' | 38 | LOCAL_MANIFEST_NAME = 'local_manifest.xml' |
31 | LOCAL_MANIFESTS_DIR_NAME = 'local_manifests' | 39 | LOCAL_MANIFESTS_DIR_NAME = 'local_manifests' |
32 | 40 | ||
33 | urlparse.uses_relative.extend(['ssh', 'git']) | 41 | urllib.parse.uses_relative.extend(['ssh', 'git']) |
34 | urlparse.uses_netloc.extend(['ssh', 'git']) | 42 | urllib.parse.uses_netloc.extend(['ssh', 'git']) |
35 | 43 | ||
36 | class _Default(object): | 44 | class _Default(object): |
37 | """Project defaults within the manifest.""" | 45 | """Project defaults within the manifest.""" |
@@ -73,7 +81,7 @@ class _XmlRemote(object): | |||
73 | # ie, if manifestUrl is of the form <hostname:port> | 81 | # ie, if manifestUrl is of the form <hostname:port> |
74 | if manifestUrl.find(':') != manifestUrl.find('/') - 1: | 82 | if manifestUrl.find(':') != manifestUrl.find('/') - 1: |
75 | manifestUrl = 'gopher://' + manifestUrl | 83 | manifestUrl = 'gopher://' + manifestUrl |
76 | url = urlparse.urljoin(manifestUrl, url) | 84 | url = urllib.parse.urljoin(manifestUrl, url) |
77 | url = re.sub(r'^gopher://', '', url) | 85 | url = re.sub(r'^gopher://', '', url) |
78 | if p: | 86 | if p: |
79 | url = 'persistent-' + url | 87 | url = 'persistent-' + url |
@@ -82,8 +90,6 @@ class _XmlRemote(object): | |||
82 | def ToRemoteSpec(self, projectName): | 90 | def ToRemoteSpec(self, projectName): |
83 | url = self.resolvedFetchUrl.rstrip('/') + '/' + projectName | 91 | url = self.resolvedFetchUrl.rstrip('/') + '/' + projectName |
84 | remoteName = self.name | 92 | remoteName = self.name |
85 | if self.remoteAlias: | ||
86 | remoteName = self.remoteAlias | ||
87 | return RemoteSpec(remoteName, url, self.reviewUrl) | 93 | return RemoteSpec(remoteName, url, self.reviewUrl) |
88 | 94 | ||
89 | class XmlManifest(object): | 95 | class XmlManifest(object): |
@@ -164,10 +170,8 @@ class XmlManifest(object): | |||
164 | notice_element.appendChild(doc.createTextNode(indented_notice)) | 170 | notice_element.appendChild(doc.createTextNode(indented_notice)) |
165 | 171 | ||
166 | d = self.default | 172 | d = self.default |
167 | sort_remotes = list(self.remotes.keys()) | ||
168 | sort_remotes.sort() | ||
169 | 173 | ||
170 | for r in sort_remotes: | 174 | for r in sorted(self.remotes): |
171 | self._RemoteToXml(self.remotes[r], doc, root) | 175 | self._RemoteToXml(self.remotes[r], doc, root) |
172 | if self.remotes: | 176 | if self.remotes: |
173 | root.appendChild(doc.createTextNode('')) | 177 | root.appendChild(doc.createTextNode('')) |
@@ -259,12 +263,11 @@ class XmlManifest(object): | |||
259 | e.setAttribute('sync-s', 'true') | 263 | e.setAttribute('sync-s', 'true') |
260 | 264 | ||
261 | if p.subprojects: | 265 | if p.subprojects: |
262 | sort_projects = [subp.name for subp in p.subprojects] | 266 | sort_projects = list(sorted([subp.name for subp in p.subprojects])) |
263 | sort_projects.sort() | ||
264 | output_projects(p, e, sort_projects) | 267 | output_projects(p, e, sort_projects) |
265 | 268 | ||
266 | sort_projects = [key for key in self.projects.keys() | 269 | sort_projects = list(sorted([key for key, value in self.projects.items() |
267 | if not self.projects[key].parent] | 270 | if not value.parent])) |
268 | sort_projects.sort() | 271 | sort_projects.sort() |
269 | output_projects(None, root, sort_projects) | 272 | output_projects(None, root, sort_projects) |
270 | 273 | ||
@@ -388,9 +391,8 @@ class XmlManifest(object): | |||
388 | name = self._reqatt(node, 'name') | 391 | name = self._reqatt(node, 'name') |
389 | fp = os.path.join(include_root, name) | 392 | fp = os.path.join(include_root, name) |
390 | if not os.path.isfile(fp): | 393 | if not os.path.isfile(fp): |
391 | raise ManifestParseError, \ | 394 | raise ManifestParseError("include %s doesn't exist or isn't a file" |
392 | "include %s doesn't exist or isn't a file" % \ | 395 | % (name,)) |
393 | (name,) | ||
394 | try: | 396 | try: |
395 | nodes.extend(self._ParseManifestXml(fp, include_root)) | 397 | nodes.extend(self._ParseManifestXml(fp, include_root)) |
396 | # should isolate this to the exact exception, but that's | 398 | # should isolate this to the exact exception, but that's |
@@ -496,7 +498,7 @@ class XmlManifest(object): | |||
496 | name = None | 498 | name = None |
497 | m_url = m.GetRemote(m.remote.name).url | 499 | m_url = m.GetRemote(m.remote.name).url |
498 | if m_url.endswith('/.git'): | 500 | if m_url.endswith('/.git'): |
499 | raise ManifestParseError, 'refusing to mirror %s' % m_url | 501 | raise ManifestParseError('refusing to mirror %s' % m_url) |
500 | 502 | ||
501 | if self._default and self._default.remote: | 503 | if self._default and self._default.remote: |
502 | url = self._default.remote.resolvedFetchUrl | 504 | url = self._default.remote.resolvedFetchUrl |
@@ -590,7 +592,7 @@ class XmlManifest(object): | |||
590 | 592 | ||
591 | # Figure out minimum indentation, skipping the first line (the same line | 593 | # Figure out minimum indentation, skipping the first line (the same line |
592 | # as the <notice> tag)... | 594 | # as the <notice> tag)... |
593 | minIndent = sys.maxint | 595 | minIndent = sys.maxsize |
594 | lines = notice.splitlines() | 596 | lines = notice.splitlines() |
595 | for line in lines[1:]: | 597 | for line in lines[1:]: |
596 | lstrippedLine = line.lstrip() | 598 | lstrippedLine = line.lstrip() |
@@ -629,25 +631,22 @@ class XmlManifest(object): | |||
629 | if remote is None: | 631 | if remote is None: |
630 | remote = self._default.remote | 632 | remote = self._default.remote |
631 | if remote is None: | 633 | if remote is None: |
632 | raise ManifestParseError, \ | 634 | raise ManifestParseError("no remote for project %s within %s" % |
633 | "no remote for project %s within %s" % \ | 635 | (name, self.manifestFile)) |
634 | (name, self.manifestFile) | ||
635 | 636 | ||
636 | revisionExpr = node.getAttribute('revision') | 637 | revisionExpr = node.getAttribute('revision') |
637 | if not revisionExpr: | 638 | if not revisionExpr: |
638 | revisionExpr = self._default.revisionExpr | 639 | revisionExpr = self._default.revisionExpr |
639 | if not revisionExpr: | 640 | if not revisionExpr: |
640 | raise ManifestParseError, \ | 641 | raise ManifestParseError("no revision for project %s within %s" % |
641 | "no revision for project %s within %s" % \ | 642 | (name, self.manifestFile)) |
642 | (name, self.manifestFile) | ||
643 | 643 | ||
644 | path = node.getAttribute('path') | 644 | path = node.getAttribute('path') |
645 | if not path: | 645 | if not path: |
646 | path = name | 646 | path = name |
647 | if path.startswith('/'): | 647 | if path.startswith('/'): |
648 | raise ManifestParseError, \ | 648 | raise ManifestParseError("project %s path cannot be absolute in %s" % |
649 | "project %s path cannot be absolute in %s" % \ | 649 | (name, self.manifestFile)) |
650 | (name, self.manifestFile) | ||
651 | 650 | ||
652 | rebase = node.getAttribute('rebase') | 651 | rebase = node.getAttribute('rebase') |
653 | if not rebase: | 652 | if not rebase: |
@@ -667,6 +666,16 @@ class XmlManifest(object): | |||
667 | else: | 666 | else: |
668 | sync_s = sync_s.lower() in ("yes", "true", "1") | 667 | sync_s = sync_s.lower() in ("yes", "true", "1") |
669 | 668 | ||
669 | clone_depth = node.getAttribute('clone-depth') | ||
670 | if clone_depth: | ||
671 | try: | ||
672 | clone_depth = int(clone_depth) | ||
673 | if clone_depth <= 0: | ||
674 | raise ValueError() | ||
675 | except ValueError: | ||
676 | raise ManifestParseError('invalid clone-depth %s in %s' % | ||
677 | (clone_depth, self.manifestFile)) | ||
678 | |||
670 | upstream = node.getAttribute('upstream') | 679 | upstream = node.getAttribute('upstream') |
671 | 680 | ||
672 | groups = '' | 681 | groups = '' |
@@ -682,6 +691,10 @@ class XmlManifest(object): | |||
682 | default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath] | 691 | default_groups = ['all', 'name:%s' % name, 'path:%s' % relpath] |
683 | groups.extend(set(default_groups).difference(groups)) | 692 | groups.extend(set(default_groups).difference(groups)) |
684 | 693 | ||
694 | if self.IsMirror and node.hasAttribute('force-path'): | ||
695 | if node.getAttribute('force-path').lower() in ("yes", "true", "1"): | ||
696 | gitdir = os.path.join(self.topdir, '%s.git' % path) | ||
697 | |||
685 | project = Project(manifest = self, | 698 | project = Project(manifest = self, |
686 | name = name, | 699 | name = name, |
687 | remote = remote.ToRemoteSpec(name), | 700 | remote = remote.ToRemoteSpec(name), |
@@ -694,6 +707,7 @@ class XmlManifest(object): | |||
694 | groups = groups, | 707 | groups = groups, |
695 | sync_c = sync_c, | 708 | sync_c = sync_c, |
696 | sync_s = sync_s, | 709 | sync_s = sync_s, |
710 | clone_depth = clone_depth, | ||
697 | upstream = upstream, | 711 | upstream = upstream, |
698 | parent = parent) | 712 | parent = parent) |
699 | 713 | ||
@@ -751,7 +765,8 @@ class XmlManifest(object): | |||
751 | except ManifestParseError: | 765 | except ManifestParseError: |
752 | keep = "true" | 766 | keep = "true" |
753 | if keep != "true" and keep != "false": | 767 | if keep != "true" and keep != "false": |
754 | raise ManifestParseError, "optional \"keep\" attribute must be \"true\" or \"false\"" | 768 | raise ManifestParseError('optional "keep" attribute must be ' |
769 | '"true" or "false"') | ||
755 | project.AddAnnotation(name, value, keep) | 770 | project.AddAnnotation(name, value, keep) |
756 | 771 | ||
757 | def _get_remote(self, node): | 772 | def _get_remote(self, node): |
@@ -761,9 +776,8 @@ class XmlManifest(object): | |||
761 | 776 | ||
762 | v = self._remotes.get(name) | 777 | v = self._remotes.get(name) |
763 | if not v: | 778 | if not v: |
764 | raise ManifestParseError, \ | 779 | raise ManifestParseError("remote %s not defined in %s" % |
765 | "remote %s not defined in %s" % \ | 780 | (name, self.manifestFile)) |
766 | (name, self.manifestFile) | ||
767 | return v | 781 | return v |
768 | 782 | ||
769 | def _reqatt(self, node, attname): | 783 | def _reqatt(self, node, attname): |
@@ -772,7 +786,6 @@ class XmlManifest(object): | |||
772 | """ | 786 | """ |
773 | v = node.getAttribute(attname) | 787 | v = node.getAttribute(attname) |
774 | if not v: | 788 | if not v: |
775 | raise ManifestParseError, \ | 789 | raise ManifestParseError("no %s in <%s> within %s" % |
776 | "no %s in <%s> within %s" % \ | 790 | (attname, node.nodeName, self.manifestFile)) |
777 | (attname, node.nodeName, self.manifestFile) | ||
778 | return v | 791 | return v |
@@ -36,6 +36,11 @@ from trace import IsTrace, Trace | |||
36 | 36 | ||
37 | from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M | 37 | from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M |
38 | 38 | ||
39 | try: | ||
40 | input = raw_input | ||
41 | except NameError: | ||
42 | pass | ||
43 | |||
39 | def _lwrite(path, content): | 44 | def _lwrite(path, content): |
40 | lock = '%s.lock' % path | 45 | lock = '%s.lock' % path |
41 | 46 | ||
@@ -78,7 +83,7 @@ def _ProjectHooks(): | |||
78 | if _project_hook_list is None: | 83 | if _project_hook_list is None: |
79 | d = os.path.abspath(os.path.dirname(__file__)) | 84 | d = os.path.abspath(os.path.dirname(__file__)) |
80 | d = os.path.join(d , 'hooks') | 85 | d = os.path.join(d , 'hooks') |
81 | _project_hook_list = map(lambda x: os.path.join(d, x), os.listdir(d)) | 86 | _project_hook_list = [os.path.join(d, x) for x in os.listdir(d)] |
82 | return _project_hook_list | 87 | return _project_hook_list |
83 | 88 | ||
84 | 89 | ||
@@ -361,7 +366,7 @@ class RepoHook(object): | |||
361 | 'Do you want to allow this script to run ' | 366 | 'Do you want to allow this script to run ' |
362 | '(yes/yes-never-ask-again/NO)? ') % ( | 367 | '(yes/yes-never-ask-again/NO)? ') % ( |
363 | self._GetMustVerb(), self._script_fullpath) | 368 | self._GetMustVerb(), self._script_fullpath) |
364 | response = raw_input(prompt).lower() | 369 | response = input(prompt).lower() |
365 | print() | 370 | print() |
366 | 371 | ||
367 | # User is doing a one-time approval. | 372 | # User is doing a one-time approval. |
@@ -488,6 +493,7 @@ class Project(object): | |||
488 | groups = None, | 493 | groups = None, |
489 | sync_c = False, | 494 | sync_c = False, |
490 | sync_s = False, | 495 | sync_s = False, |
496 | clone_depth = None, | ||
491 | upstream = None, | 497 | upstream = None, |
492 | parent = None, | 498 | parent = None, |
493 | is_derived = False): | 499 | is_derived = False): |
@@ -533,6 +539,7 @@ class Project(object): | |||
533 | self.groups = groups | 539 | self.groups = groups |
534 | self.sync_c = sync_c | 540 | self.sync_c = sync_c |
535 | self.sync_s = sync_s | 541 | self.sync_s = sync_s |
542 | self.clone_depth = clone_depth | ||
536 | self.upstream = upstream | 543 | self.upstream = upstream |
537 | self.parent = parent | 544 | self.parent = parent |
538 | self.is_derived = is_derived | 545 | self.is_derived = is_derived |
@@ -644,7 +651,7 @@ class Project(object): | |||
644 | all_refs = self._allrefs | 651 | all_refs = self._allrefs |
645 | heads = {} | 652 | heads = {} |
646 | 653 | ||
647 | for name, ref_id in all_refs.iteritems(): | 654 | for name, ref_id in all_refs.items(): |
648 | if name.startswith(R_HEADS): | 655 | if name.startswith(R_HEADS): |
649 | name = name[len(R_HEADS):] | 656 | name = name[len(R_HEADS):] |
650 | b = self.GetBranch(name) | 657 | b = self.GetBranch(name) |
@@ -653,7 +660,7 @@ class Project(object): | |||
653 | b.revision = ref_id | 660 | b.revision = ref_id |
654 | heads[name] = b | 661 | heads[name] = b |
655 | 662 | ||
656 | for name, ref_id in all_refs.iteritems(): | 663 | for name, ref_id in all_refs.items(): |
657 | if name.startswith(R_PUB): | 664 | if name.startswith(R_PUB): |
658 | name = name[len(R_PUB):] | 665 | name = name[len(R_PUB):] |
659 | b = heads.get(name) | 666 | b = heads.get(name) |
@@ -672,9 +679,14 @@ class Project(object): | |||
672 | project_groups: "all,group1,group2" | 679 | project_groups: "all,group1,group2" |
673 | manifest_groups: "-group1,group2" | 680 | manifest_groups: "-group1,group2" |
674 | the project will be matched. | 681 | the project will be matched. |
682 | |||
683 | The special manifest group "default" will match any project that | ||
684 | does not have the special project group "notdefault" | ||
675 | """ | 685 | """ |
676 | expanded_manifest_groups = manifest_groups or ['all', '-notdefault'] | 686 | expanded_manifest_groups = manifest_groups or ['default'] |
677 | expanded_project_groups = ['all'] + (self.groups or []) | 687 | expanded_project_groups = ['all'] + (self.groups or []) |
688 | if not 'notdefault' in expanded_project_groups: | ||
689 | expanded_project_groups += ['default'] | ||
678 | 690 | ||
679 | matched = False | 691 | matched = False |
680 | for group in expanded_manifest_groups: | 692 | for group in expanded_manifest_groups: |
@@ -754,10 +766,7 @@ class Project(object): | |||
754 | paths.extend(df.keys()) | 766 | paths.extend(df.keys()) |
755 | paths.extend(do) | 767 | paths.extend(do) |
756 | 768 | ||
757 | paths = list(set(paths)) | 769 | for p in sorted(set(paths)): |
758 | paths.sort() | ||
759 | |||
760 | for p in paths: | ||
761 | try: | 770 | try: |
762 | i = di[p] | 771 | i = di[p] |
763 | except KeyError: | 772 | except KeyError: |
@@ -849,13 +858,13 @@ class Project(object): | |||
849 | all_refs = self._allrefs | 858 | all_refs = self._allrefs |
850 | heads = set() | 859 | heads = set() |
851 | canrm = {} | 860 | canrm = {} |
852 | for name, ref_id in all_refs.iteritems(): | 861 | for name, ref_id in all_refs.items(): |
853 | if name.startswith(R_HEADS): | 862 | if name.startswith(R_HEADS): |
854 | heads.add(name) | 863 | heads.add(name) |
855 | elif name.startswith(R_PUB): | 864 | elif name.startswith(R_PUB): |
856 | canrm[name] = ref_id | 865 | canrm[name] = ref_id |
857 | 866 | ||
858 | for name, ref_id in canrm.iteritems(): | 867 | for name, ref_id in canrm.items(): |
859 | n = name[len(R_PUB):] | 868 | n = name[len(R_PUB):] |
860 | if R_HEADS + n not in heads: | 869 | if R_HEADS + n not in heads: |
861 | self.bare_git.DeleteRef(name, ref_id) | 870 | self.bare_git.DeleteRef(name, ref_id) |
@@ -866,14 +875,14 @@ class Project(object): | |||
866 | heads = {} | 875 | heads = {} |
867 | pubed = {} | 876 | pubed = {} |
868 | 877 | ||
869 | for name, ref_id in self._allrefs.iteritems(): | 878 | for name, ref_id in self._allrefs.items(): |
870 | if name.startswith(R_HEADS): | 879 | if name.startswith(R_HEADS): |
871 | heads[name[len(R_HEADS):]] = ref_id | 880 | heads[name[len(R_HEADS):]] = ref_id |
872 | elif name.startswith(R_PUB): | 881 | elif name.startswith(R_PUB): |
873 | pubed[name[len(R_PUB):]] = ref_id | 882 | pubed[name[len(R_PUB):]] = ref_id |
874 | 883 | ||
875 | ready = [] | 884 | ready = [] |
876 | for branch, ref_id in heads.iteritems(): | 885 | for branch, ref_id in heads.items(): |
877 | if branch in pubed and pubed[branch] == ref_id: | 886 | if branch in pubed and pubed[branch] == ref_id: |
878 | continue | 887 | continue |
879 | if selected_branch and branch != selected_branch: | 888 | if selected_branch and branch != selected_branch: |
@@ -1218,7 +1227,7 @@ class Project(object): | |||
1218 | cmd = ['fetch', remote.name] | 1227 | cmd = ['fetch', remote.name] |
1219 | cmd.append('refs/changes/%2.2d/%d/%d' \ | 1228 | cmd.append('refs/changes/%2.2d/%d/%d' \ |
1220 | % (change_id % 100, change_id, patch_id)) | 1229 | % (change_id % 100, change_id, patch_id)) |
1221 | cmd.extend(map(str, remote.fetch)) | 1230 | cmd.extend(list(map(str, remote.fetch))) |
1222 | if GitCommand(self, cmd, bare=True).Wait() != 0: | 1231 | if GitCommand(self, cmd, bare=True).Wait() != 0: |
1223 | return None | 1232 | return None |
1224 | return DownloadedChange(self, | 1233 | return DownloadedChange(self, |
@@ -1607,7 +1616,7 @@ class Project(object): | |||
1607 | ids = set(all_refs.values()) | 1616 | ids = set(all_refs.values()) |
1608 | tmp = set() | 1617 | tmp = set() |
1609 | 1618 | ||
1610 | for r, ref_id in GitRefs(ref_dir).all.iteritems(): | 1619 | for r, ref_id in GitRefs(ref_dir).all.items(): |
1611 | if r not in all_refs: | 1620 | if r not in all_refs: |
1612 | if r.startswith(R_TAGS) or remote.WritesTo(r): | 1621 | if r.startswith(R_TAGS) or remote.WritesTo(r): |
1613 | all_refs[r] = ref_id | 1622 | all_refs[r] = ref_id |
@@ -1622,13 +1631,10 @@ class Project(object): | |||
1622 | ids.add(ref_id) | 1631 | ids.add(ref_id) |
1623 | tmp.add(r) | 1632 | tmp.add(r) |
1624 | 1633 | ||
1625 | ref_names = list(all_refs.keys()) | ||
1626 | ref_names.sort() | ||
1627 | |||
1628 | tmp_packed = '' | 1634 | tmp_packed = '' |
1629 | old_packed = '' | 1635 | old_packed = '' |
1630 | 1636 | ||
1631 | for r in ref_names: | 1637 | for r in sorted(all_refs): |
1632 | line = '%s %s\n' % (all_refs[r], r) | 1638 | line = '%s %s\n' % (all_refs[r], r) |
1633 | tmp_packed += line | 1639 | tmp_packed += line |
1634 | if r not in tmp: | 1640 | if r not in tmp: |
@@ -1642,7 +1648,10 @@ class Project(object): | |||
1642 | 1648 | ||
1643 | # The --depth option only affects the initial fetch; after that we'll do | 1649 | # The --depth option only affects the initial fetch; after that we'll do |
1644 | # full fetches of changes. | 1650 | # full fetches of changes. |
1645 | depth = self.manifest.manifestProject.config.GetString('repo.depth') | 1651 | if self.clone_depth: |
1652 | depth = self.clone_depth | ||
1653 | else: | ||
1654 | depth = self.manifest.manifestProject.config.GetString('repo.depth') | ||
1646 | if depth and initial: | 1655 | if depth and initial: |
1647 | cmd.append('--depth=%s' % depth) | 1656 | cmd.append('--depth=%s' % depth) |
1648 | 1657 | ||
@@ -1654,11 +1663,13 @@ class Project(object): | |||
1654 | 1663 | ||
1655 | if not current_branch_only: | 1664 | if not current_branch_only: |
1656 | # Fetch whole repo | 1665 | # Fetch whole repo |
1657 | if no_tags: | 1666 | # If using depth then we should not get all the tags since they may |
1667 | # be outside of the depth. | ||
1668 | if no_tags or depth: | ||
1658 | cmd.append('--no-tags') | 1669 | cmd.append('--no-tags') |
1659 | else: | 1670 | else: |
1660 | cmd.append('--tags') | 1671 | cmd.append('--tags') |
1661 | cmd.append((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*')) | 1672 | cmd.append(str((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*'))) |
1662 | elif tag_name is not None: | 1673 | elif tag_name is not None: |
1663 | cmd.append('tag') | 1674 | cmd.append('tag') |
1664 | cmd.append(tag_name) | 1675 | cmd.append(tag_name) |
@@ -1668,7 +1679,7 @@ class Project(object): | |||
1668 | branch = self.upstream | 1679 | branch = self.upstream |
1669 | if branch.startswith(R_HEADS): | 1680 | if branch.startswith(R_HEADS): |
1670 | branch = branch[len(R_HEADS):] | 1681 | branch = branch[len(R_HEADS):] |
1671 | cmd.append((u'+refs/heads/%s:' % branch) + remote.ToLocal('refs/heads/%s' % branch)) | 1682 | cmd.append(str((u'+refs/heads/%s:' % branch) + remote.ToLocal('refs/heads/%s' % branch))) |
1672 | 1683 | ||
1673 | ok = False | 1684 | ok = False |
1674 | for _i in range(2): | 1685 | for _i in range(2): |
@@ -1702,7 +1713,7 @@ class Project(object): | |||
1702 | return ok | 1713 | return ok |
1703 | 1714 | ||
1704 | def _ApplyCloneBundle(self, initial=False, quiet=False): | 1715 | def _ApplyCloneBundle(self, initial=False, quiet=False): |
1705 | if initial and self.manifest.manifestProject.config.GetString('repo.depth'): | 1716 | if initial and (self.manifest.manifestProject.config.GetString('repo.depth') or self.clone_depth): |
1706 | return False | 1717 | return False |
1707 | 1718 | ||
1708 | remote = self.GetRemote(self.remote.name) | 1719 | remote = self.GetRemote(self.remote.name) |
@@ -2099,6 +2110,10 @@ class Project(object): | |||
2099 | line = fd.read() | 2110 | line = fd.read() |
2100 | finally: | 2111 | finally: |
2101 | fd.close() | 2112 | fd.close() |
2113 | try: | ||
2114 | line = line.decode() | ||
2115 | except AttributeError: | ||
2116 | pass | ||
2102 | if line.startswith('ref: '): | 2117 | if line.startswith('ref: '): |
2103 | return line[5:-1] | 2118 | return line[5:-1] |
2104 | return line[:-1] | 2119 | return line[:-1] |
@@ -2192,7 +2207,7 @@ class Project(object): | |||
2192 | if not git_require((1, 7, 2)): | 2207 | if not git_require((1, 7, 2)): |
2193 | raise ValueError('cannot set config on command line for %s()' | 2208 | raise ValueError('cannot set config on command line for %s()' |
2194 | % name) | 2209 | % name) |
2195 | for k, v in config.iteritems(): | 2210 | for k, v in config.items(): |
2196 | cmdv.append('-c') | 2211 | cmdv.append('-c') |
2197 | cmdv.append('%s=%s' % (k, v)) | 2212 | cmdv.append('%s=%s' % (k, v)) |
2198 | cmdv.append(name) | 2213 | cmdv.append(name) |
@@ -2208,6 +2223,10 @@ class Project(object): | |||
2208 | name, | 2223 | name, |
2209 | p.stderr)) | 2224 | p.stderr)) |
2210 | r = p.stdout | 2225 | r = p.stdout |
2226 | try: | ||
2227 | r = r.decode() | ||
2228 | except AttributeError: | ||
2229 | pass | ||
2211 | if r.endswith('\n') and r.index('\n') == len(r) - 1: | 2230 | if r.endswith('\n') and r.index('\n') == len(r) - 1: |
2212 | return r[:-1] | 2231 | return r[:-1] |
2213 | return r | 2232 | return r |
@@ -108,6 +108,7 @@ repodir = '.repo' # name of repo's private directory | |||
108 | S_repo = 'repo' # special repo repository | 108 | S_repo = 'repo' # special repo repository |
109 | S_manifests = 'manifests' # special manifest repository | 109 | S_manifests = 'manifests' # special manifest repository |
110 | REPO_MAIN = S_repo + '/main.py' # main script | 110 | REPO_MAIN = S_repo + '/main.py' # main script |
111 | MIN_PYTHON_VERSION = (2, 6) # minimum supported python version | ||
111 | 112 | ||
112 | 113 | ||
113 | import optparse | 114 | import optparse |
@@ -129,6 +130,19 @@ else: | |||
129 | urllib.request = urllib2 | 130 | urllib.request = urllib2 |
130 | urllib.error = urllib2 | 131 | urllib.error = urllib2 |
131 | 132 | ||
133 | # Python version check | ||
134 | ver = sys.version_info | ||
135 | if ver[0] == 3: | ||
136 | print('error: Python 3 support is not fully implemented in repo yet.\n' | ||
137 | 'Please use Python 2.6 - 2.7 instead.', | ||
138 | file=sys.stderr) | ||
139 | sys.exit(1) | ||
140 | if (ver[0], ver[1]) < MIN_PYTHON_VERSION: | ||
141 | print('error: Python version %s unsupported.\n' | ||
142 | 'Please use Python 2.6 - 2.7 instead.' | ||
143 | % sys.version.split(' ')[0], file=sys.stderr) | ||
144 | sys.exit(1) | ||
145 | |||
132 | home_dot_repo = os.path.expanduser('~/.repoconfig') | 146 | home_dot_repo = os.path.expanduser('~/.repoconfig') |
133 | gpg_dir = os.path.join(home_dot_repo, 'gnupg') | 147 | gpg_dir = os.path.join(home_dot_repo, 'gnupg') |
134 | 148 | ||
@@ -164,7 +178,8 @@ group.add_option('--depth', type='int', default=None, | |||
164 | help='create a shallow clone with given depth; see git clone') | 178 | help='create a shallow clone with given depth; see git clone') |
165 | group.add_option('-g', '--groups', | 179 | group.add_option('-g', '--groups', |
166 | dest='groups', default='default', | 180 | dest='groups', default='default', |
167 | help='restrict manifest projects to ones with a specified group', | 181 | help='restrict manifest projects to ones with specified ' |
182 | 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]', | ||
168 | metavar='GROUP') | 183 | metavar='GROUP') |
169 | group.add_option('-p', '--platform', | 184 | group.add_option('-p', '--platform', |
170 | dest='platform', default="auto", | 185 | dest='platform', default="auto", |
diff --git a/subcmds/__init__.py b/subcmds/__init__.py index 1fac802e..84efb4de 100644 --- a/subcmds/__init__.py +++ b/subcmds/__init__.py | |||
@@ -38,8 +38,8 @@ for py in os.listdir(my_dir): | |||
38 | try: | 38 | try: |
39 | cmd = getattr(mod, clsn)() | 39 | cmd = getattr(mod, clsn)() |
40 | except AttributeError: | 40 | except AttributeError: |
41 | raise SyntaxError, '%s/%s does not define class %s' % ( | 41 | raise SyntaxError('%s/%s does not define class %s' % ( |
42 | __name__, py, clsn) | 42 | __name__, py, clsn)) |
43 | 43 | ||
44 | name = name.replace('_', '-') | 44 | name = name.replace('_', '-') |
45 | cmd.NAME = name | 45 | cmd.NAME = name |
diff --git a/subcmds/branches.py b/subcmds/branches.py index 06d45abe..c2e7c4b9 100644 --- a/subcmds/branches.py +++ b/subcmds/branches.py | |||
@@ -98,14 +98,13 @@ is shown, then the branch appears in all projects. | |||
98 | project_cnt = len(projects) | 98 | project_cnt = len(projects) |
99 | 99 | ||
100 | for project in projects: | 100 | for project in projects: |
101 | for name, b in project.GetBranches().iteritems(): | 101 | for name, b in project.GetBranches().items(): |
102 | b.project = project | 102 | b.project = project |
103 | if name not in all_branches: | 103 | if name not in all_branches: |
104 | all_branches[name] = BranchInfo(name) | 104 | all_branches[name] = BranchInfo(name) |
105 | all_branches[name].add(b) | 105 | all_branches[name].add(b) |
106 | 106 | ||
107 | names = all_branches.keys() | 107 | names = list(sorted(all_branches)) |
108 | names.sort() | ||
109 | 108 | ||
110 | if not names: | 109 | if not names: |
111 | print(' (no branches)', file=sys.stderr) | 110 | print(' (no branches)', file=sys.stderr) |
diff --git a/subcmds/forall.py b/subcmds/forall.py index 4c1c9ff8..7d5f7794 100644 --- a/subcmds/forall.py +++ b/subcmds/forall.py | |||
@@ -42,10 +42,14 @@ class Forall(Command, MirrorSafeCommand): | |||
42 | helpSummary = "Run a shell command in each project" | 42 | helpSummary = "Run a shell command in each project" |
43 | helpUsage = """ | 43 | helpUsage = """ |
44 | %prog [<project>...] -c <command> [<arg>...] | 44 | %prog [<project>...] -c <command> [<arg>...] |
45 | %prog -r str1 [str2] ... -c <command> [<arg>...]" | ||
45 | """ | 46 | """ |
46 | helpDescription = """ | 47 | helpDescription = """ |
47 | Executes the same shell command in each project. | 48 | Executes the same shell command in each project. |
48 | 49 | ||
50 | The -r option allows running the command only on projects matching | ||
51 | regex or wildcard expression. | ||
52 | |||
49 | Output Formatting | 53 | Output Formatting |
50 | ----------------- | 54 | ----------------- |
51 | 55 | ||
@@ -103,6 +107,9 @@ without iterating through the remaining projects. | |||
103 | setattr(parser.values, option.dest, list(parser.rargs)) | 107 | setattr(parser.values, option.dest, list(parser.rargs)) |
104 | while parser.rargs: | 108 | while parser.rargs: |
105 | del parser.rargs[0] | 109 | del parser.rargs[0] |
110 | p.add_option('-r', '--regex', | ||
111 | dest='regex', action='store_true', | ||
112 | help="Execute the command only on projects matching regex or wildcard expression") | ||
106 | p.add_option('-c', '--command', | 113 | p.add_option('-c', '--command', |
107 | help='Command (and arguments) to execute', | 114 | help='Command (and arguments) to execute', |
108 | dest='command', | 115 | dest='command', |
@@ -166,7 +173,12 @@ without iterating through the remaining projects. | |||
166 | rc = 0 | 173 | rc = 0 |
167 | first = True | 174 | first = True |
168 | 175 | ||
169 | for project in self.GetProjects(args): | 176 | if not opt.regex: |
177 | projects = self.GetProjects(args) | ||
178 | else: | ||
179 | projects = self.FindProjects(args) | ||
180 | |||
181 | for project in projects: | ||
170 | env = os.environ.copy() | 182 | env = os.environ.copy() |
171 | def setenv(name, val): | 183 | def setenv(name, val): |
172 | if val is None: | 184 | if val is None: |
diff --git a/subcmds/help.py b/subcmds/help.py index 78428825..4aa3f863 100644 --- a/subcmds/help.py +++ b/subcmds/help.py | |||
@@ -34,8 +34,7 @@ Displays detailed usage information about a command. | |||
34 | def _PrintAllCommands(self): | 34 | def _PrintAllCommands(self): |
35 | print('usage: repo COMMAND [ARGS]') | 35 | print('usage: repo COMMAND [ARGS]') |
36 | print('The complete list of recognized repo commands are:') | 36 | print('The complete list of recognized repo commands are:') |
37 | commandNames = self.commands.keys() | 37 | commandNames = list(sorted(self.commands)) |
38 | commandNames.sort() | ||
39 | 38 | ||
40 | maxlen = 0 | 39 | maxlen = 0 |
41 | for name in commandNames: | 40 | for name in commandNames: |
@@ -55,10 +54,9 @@ Displays detailed usage information about a command. | |||
55 | def _PrintCommonCommands(self): | 54 | def _PrintCommonCommands(self): |
56 | print('usage: repo COMMAND [ARGS]') | 55 | print('usage: repo COMMAND [ARGS]') |
57 | print('The most commonly used repo commands are:') | 56 | print('The most commonly used repo commands are:') |
58 | commandNames = [name | 57 | commandNames = list(sorted([name |
59 | for name in self.commands.keys() | 58 | for name, command in self.commands.items() |
60 | if self.commands[name].common] | 59 | if command.common])) |
61 | commandNames.sort() | ||
62 | 60 | ||
63 | maxlen = 0 | 61 | maxlen = 0 |
64 | for name in commandNames: | 62 | for name in commandNames: |
diff --git a/subcmds/info.py b/subcmds/info.py index 325874b5..c10e56cd 100644 --- a/subcmds/info.py +++ b/subcmds/info.py | |||
@@ -163,7 +163,7 @@ class Info(PagedCommand): | |||
163 | all_branches = [] | 163 | all_branches = [] |
164 | for project in self.GetProjects(args): | 164 | for project in self.GetProjects(args): |
165 | br = [project.GetUploadableBranch(x) | 165 | br = [project.GetUploadableBranch(x) |
166 | for x in project.GetBranches().keys()] | 166 | for x in project.GetBranches()] |
167 | br = [x for x in br if x] | 167 | br = [x for x in br if x] |
168 | if self.opt.current_branch: | 168 | if self.opt.current_branch: |
169 | br = [x for x in br if x.name == project.CurrentBranch] | 169 | br = [x for x in br if x.name == project.CurrentBranch] |
diff --git a/subcmds/init.py b/subcmds/init.py index 11312601..29730cc4 100644 --- a/subcmds/init.py +++ b/subcmds/init.py | |||
@@ -91,8 +91,9 @@ to update the working directory files. | |||
91 | dest='depth', | 91 | dest='depth', |
92 | help='create a shallow clone with given depth; see git clone') | 92 | help='create a shallow clone with given depth; see git clone') |
93 | g.add_option('-g', '--groups', | 93 | g.add_option('-g', '--groups', |
94 | dest='groups', default='all,-notdefault', | 94 | dest='groups', default='default', |
95 | help='restrict manifest projects to ones with a specified group', | 95 | help='restrict manifest projects to ones with specified ' |
96 | 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]', | ||
96 | metavar='GROUP') | 97 | metavar='GROUP') |
97 | g.add_option('-p', '--platform', | 98 | g.add_option('-p', '--platform', |
98 | dest='platform', default='auto', | 99 | dest='platform', default='auto', |
@@ -169,7 +170,7 @@ to update the working directory files. | |||
169 | 170 | ||
170 | groups = [x for x in groups if x] | 171 | groups = [x for x in groups if x] |
171 | groupstr = ','.join(groups) | 172 | groupstr = ','.join(groups) |
172 | if opt.platform == 'auto' and groupstr == 'all,-notdefault,platform-' + platform.system().lower(): | 173 | if opt.platform == 'auto' and groupstr == 'default,platform-' + platform.system().lower(): |
173 | groupstr = None | 174 | groupstr = None |
174 | m.config.SetString('manifest.groups', groupstr) | 175 | m.config.SetString('manifest.groups', groupstr) |
175 | 176 | ||
diff --git a/subcmds/list.py b/subcmds/list.py index 0d5c27f7..a3358245 100644 --- a/subcmds/list.py +++ b/subcmds/list.py | |||
@@ -14,7 +14,7 @@ | |||
14 | # limitations under the License. | 14 | # limitations under the License. |
15 | 15 | ||
16 | from __future__ import print_function | 16 | from __future__ import print_function |
17 | import re | 17 | import sys |
18 | 18 | ||
19 | from command import Command, MirrorSafeCommand | 19 | from command import Command, MirrorSafeCommand |
20 | 20 | ||
@@ -38,6 +38,12 @@ This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'. | |||
38 | p.add_option('-f', '--fullpath', | 38 | p.add_option('-f', '--fullpath', |
39 | dest='fullpath', action='store_true', | 39 | dest='fullpath', action='store_true', |
40 | help="Display the full work tree path instead of the relative path") | 40 | help="Display the full work tree path instead of the relative path") |
41 | p.add_option('-n', '--name-only', | ||
42 | dest='name_only', action='store_true', | ||
43 | help="Display only the name of the repository") | ||
44 | p.add_option('-p', '--path-only', | ||
45 | dest='path_only', action='store_true', | ||
46 | help="Display only the path of the repository") | ||
41 | 47 | ||
42 | def Execute(self, opt, args): | 48 | def Execute(self, opt, args): |
43 | """List all projects and the associated directories. | 49 | """List all projects and the associated directories. |
@@ -50,6 +56,11 @@ This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'. | |||
50 | opt: The options. | 56 | opt: The options. |
51 | args: Positional args. Can be a list of projects to list, or empty. | 57 | args: Positional args. Can be a list of projects to list, or empty. |
52 | """ | 58 | """ |
59 | |||
60 | if opt.fullpath and opt.name_only: | ||
61 | print('error: cannot combine -f and -n', file=sys.stderr) | ||
62 | sys.exit(1) | ||
63 | |||
53 | if not opt.regex: | 64 | if not opt.regex: |
54 | projects = self.GetProjects(args) | 65 | projects = self.GetProjects(args) |
55 | else: | 66 | else: |
@@ -62,18 +73,12 @@ This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'. | |||
62 | 73 | ||
63 | lines = [] | 74 | lines = [] |
64 | for project in projects: | 75 | for project in projects: |
65 | lines.append("%s : %s" % (_getpath(project), project.name)) | 76 | if opt.name_only and not opt.path_only: |
77 | lines.append("%s" % ( project.name)) | ||
78 | elif opt.path_only and not opt.name_only: | ||
79 | lines.append("%s" % (_getpath(project))) | ||
80 | else: | ||
81 | lines.append("%s : %s" % (_getpath(project), project.name)) | ||
66 | 82 | ||
67 | lines.sort() | 83 | lines.sort() |
68 | print('\n'.join(lines)) | 84 | print('\n'.join(lines)) |
69 | |||
70 | def FindProjects(self, args): | ||
71 | result = [] | ||
72 | for project in self.GetProjects(''): | ||
73 | for arg in args: | ||
74 | pattern = re.compile(r'%s' % arg, re.IGNORECASE) | ||
75 | if pattern.search(project.name) or pattern.search(project.relpath): | ||
76 | result.append(project) | ||
77 | break | ||
78 | result.sort(key=lambda project: project.relpath) | ||
79 | return result | ||
diff --git a/subcmds/overview.py b/subcmds/overview.py index 418459ae..eed8cf20 100644 --- a/subcmds/overview.py +++ b/subcmds/overview.py | |||
@@ -42,7 +42,7 @@ are displayed. | |||
42 | all_branches = [] | 42 | all_branches = [] |
43 | for project in self.GetProjects(args): | 43 | for project in self.GetProjects(args): |
44 | br = [project.GetUploadableBranch(x) | 44 | br = [project.GetUploadableBranch(x) |
45 | for x in project.GetBranches().keys()] | 45 | for x in project.GetBranches()] |
46 | br = [x for x in br if x] | 46 | br = [x for x in br if x] |
47 | if opt.current_branch: | 47 | if opt.current_branch: |
48 | br = [x for x in br if x.name == project.CurrentBranch] | 48 | br = [x for x in br if x.name == project.CurrentBranch] |
diff --git a/subcmds/stage.py b/subcmds/stage.py index ff15ee0c..28849764 100644 --- a/subcmds/stage.py +++ b/subcmds/stage.py | |||
@@ -49,7 +49,7 @@ The '%prog' command stages files to prepare the next commit. | |||
49 | self.Usage() | 49 | self.Usage() |
50 | 50 | ||
51 | def _Interactive(self, opt, args): | 51 | def _Interactive(self, opt, args): |
52 | all_projects = filter(lambda x: x.IsDirty(), self.GetProjects(args)) | 52 | all_projects = [p for p in self.GetProjects(args) if p.IsDirty()] |
53 | if not all_projects: | 53 | if not all_projects: |
54 | print('no projects have uncommitted modifications', file=sys.stderr) | 54 | print('no projects have uncommitted modifications', file=sys.stderr) |
55 | return | 55 | return |
@@ -98,9 +98,9 @@ The '%prog' command stages files to prepare the next commit. | |||
98 | _AddI(all_projects[a_index - 1]) | 98 | _AddI(all_projects[a_index - 1]) |
99 | continue | 99 | continue |
100 | 100 | ||
101 | p = filter(lambda x: x.name == a or x.relpath == a, all_projects) | 101 | projects = [p for p in all_projects if a in [p.name, p.relpath]] |
102 | if len(p) == 1: | 102 | if len(projects) == 1: |
103 | _AddI(p[0]) | 103 | _AddI(projects[0]) |
104 | continue | 104 | continue |
105 | print('Bye.') | 105 | print('Bye.') |
106 | 106 | ||
diff --git a/subcmds/status.py b/subcmds/status.py index cce00c81..9810337f 100644 --- a/subcmds/status.py +++ b/subcmds/status.py | |||
@@ -21,10 +21,15 @@ except ImportError: | |||
21 | import dummy_threading as _threading | 21 | import dummy_threading as _threading |
22 | 22 | ||
23 | import glob | 23 | import glob |
24 | try: | ||
25 | # For python2 | ||
26 | import StringIO as io | ||
27 | except ImportError: | ||
28 | # For python3 | ||
29 | import io | ||
24 | import itertools | 30 | import itertools |
25 | import os | 31 | import os |
26 | import sys | 32 | import sys |
27 | import StringIO | ||
28 | 33 | ||
29 | from color import Coloring | 34 | from color import Coloring |
30 | 35 | ||
@@ -142,7 +147,7 @@ the following meanings: | |||
142 | for project in all_projects: | 147 | for project in all_projects: |
143 | sem.acquire() | 148 | sem.acquire() |
144 | 149 | ||
145 | class BufList(StringIO.StringIO): | 150 | class BufList(io.StringIO): |
146 | def dump(self, ostream): | 151 | def dump(self, ostream): |
147 | for entry in self.buflist: | 152 | for entry in self.buflist: |
148 | ostream.write(entry) | 153 | ostream.write(entry) |
@@ -182,7 +187,7 @@ the following meanings: | |||
182 | try: | 187 | try: |
183 | os.chdir(self.manifest.topdir) | 188 | os.chdir(self.manifest.topdir) |
184 | 189 | ||
185 | outstring = StringIO.StringIO() | 190 | outstring = io.StringIO() |
186 | self._FindOrphans(glob.glob('.*') + \ | 191 | self._FindOrphans(glob.glob('.*') + \ |
187 | glob.glob('*'), \ | 192 | glob.glob('*'), \ |
188 | proj_dirs, proj_dirs_parents, outstring) | 193 | proj_dirs, proj_dirs_parents, outstring) |
diff --git a/subcmds/sync.py b/subcmds/sync.py index 6c903ff4..8fb94885 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
@@ -24,8 +24,24 @@ import socket | |||
24 | import subprocess | 24 | import subprocess |
25 | import sys | 25 | import sys |
26 | import time | 26 | import time |
27 | import urlparse | 27 | try: |
28 | import xmlrpclib | 28 | # For python3 |
29 | import urllib.parse | ||
30 | except ImportError: | ||
31 | # For python2 | ||
32 | import imp | ||
33 | import urlparse | ||
34 | urllib = imp.new_module('urllib') | ||
35 | urllib.parse = urlparse | ||
36 | try: | ||
37 | # For python3 | ||
38 | import xmlrpc.client | ||
39 | except ImportError: | ||
40 | # For python2 | ||
41 | import imp | ||
42 | import xmlrpclib | ||
43 | xmlrpc = imp.new_module('xmlrpc') | ||
44 | xmlrpc.client = xmlrpclib | ||
29 | 45 | ||
30 | try: | 46 | try: |
31 | import threading as _threading | 47 | import threading as _threading |
@@ -228,6 +244,9 @@ later is required to fix a server side protocol bug. | |||
228 | # We'll set to true once we've locked the lock. | 244 | # We'll set to true once we've locked the lock. |
229 | did_lock = False | 245 | did_lock = False |
230 | 246 | ||
247 | if not opt.quiet: | ||
248 | print('Fetching project %s' % project.name) | ||
249 | |||
231 | # Encapsulate everything in a try/except/finally so that: | 250 | # Encapsulate everything in a try/except/finally so that: |
232 | # - We always set err_event in the case of an exception. | 251 | # - We always set err_event in the case of an exception. |
233 | # - We always make sure we call sem.release(). | 252 | # - We always make sure we call sem.release(). |
@@ -274,6 +293,8 @@ later is required to fix a server side protocol bug. | |||
274 | if self.jobs == 1: | 293 | if self.jobs == 1: |
275 | for project in projects: | 294 | for project in projects: |
276 | pm.update() | 295 | pm.update() |
296 | if not opt.quiet: | ||
297 | print('Fetching project %s' % project.name) | ||
277 | if project.Sync_NetworkHalf( | 298 | if project.Sync_NetworkHalf( |
278 | quiet=opt.quiet, | 299 | quiet=opt.quiet, |
279 | current_branch_only=opt.current_branch_only, | 300 | current_branch_only=opt.current_branch_only, |
@@ -372,6 +393,13 @@ later is required to fix a server side protocol bug. | |||
372 | print('\nerror: Exited sync due to gc errors', file=sys.stderr) | 393 | print('\nerror: Exited sync due to gc errors', file=sys.stderr) |
373 | sys.exit(1) | 394 | sys.exit(1) |
374 | 395 | ||
396 | def _ReloadManifest(self, manifest_name=None): | ||
397 | if manifest_name: | ||
398 | # Override calls _Unload already | ||
399 | self.manifest.Override(manifest_name) | ||
400 | else: | ||
401 | self.manifest._Unload() | ||
402 | |||
375 | def UpdateProjectList(self): | 403 | def UpdateProjectList(self): |
376 | new_project_paths = [] | 404 | new_project_paths = [] |
377 | for project in self.GetProjects(None, missing_ok=True): | 405 | for project in self.GetProjects(None, missing_ok=True): |
@@ -486,7 +514,7 @@ later is required to fix a server side protocol bug. | |||
486 | file=sys.stderr) | 514 | file=sys.stderr) |
487 | else: | 515 | else: |
488 | try: | 516 | try: |
489 | parse_result = urlparse.urlparse(manifest_server) | 517 | parse_result = urllib.parse(manifest_server) |
490 | if parse_result.hostname: | 518 | if parse_result.hostname: |
491 | username, _account, password = \ | 519 | username, _account, password = \ |
492 | info.authenticators(parse_result.hostname) | 520 | info.authenticators(parse_result.hostname) |
@@ -504,7 +532,7 @@ later is required to fix a server side protocol bug. | |||
504 | 1) | 532 | 1) |
505 | 533 | ||
506 | try: | 534 | try: |
507 | server = xmlrpclib.Server(manifest_server) | 535 | server = xmlrpc.client.Server(manifest_server) |
508 | if opt.smart_sync: | 536 | if opt.smart_sync: |
509 | p = self.manifest.manifestProject | 537 | p = self.manifest.manifestProject |
510 | b = p.GetBranch(p.CurrentBranch) | 538 | b = p.GetBranch(p.CurrentBranch) |
@@ -513,8 +541,7 @@ later is required to fix a server side protocol bug. | |||
513 | branch = branch[len(R_HEADS):] | 541 | branch = branch[len(R_HEADS):] |
514 | 542 | ||
515 | env = os.environ.copy() | 543 | env = os.environ.copy() |
516 | if (env.has_key('TARGET_PRODUCT') and | 544 | if 'TARGET_PRODUCT' in env and 'TARGET_BUILD_VARIANT' in env: |
517 | env.has_key('TARGET_BUILD_VARIANT')): | ||
518 | target = '%s-%s' % (env['TARGET_PRODUCT'], | 545 | target = '%s-%s' % (env['TARGET_PRODUCT'], |
519 | env['TARGET_BUILD_VARIANT']) | 546 | env['TARGET_BUILD_VARIANT']) |
520 | [success, manifest_str] = server.GetApprovedManifest(branch, target) | 547 | [success, manifest_str] = server.GetApprovedManifest(branch, target) |
@@ -542,11 +569,11 @@ later is required to fix a server side protocol bug. | |||
542 | else: | 569 | else: |
543 | print('error: %s' % manifest_str, file=sys.stderr) | 570 | print('error: %s' % manifest_str, file=sys.stderr) |
544 | sys.exit(1) | 571 | sys.exit(1) |
545 | except (socket.error, IOError, xmlrpclib.Fault) as e: | 572 | except (socket.error, IOError, xmlrpc.client.Fault) as e: |
546 | print('error: cannot connect to manifest server %s:\n%s' | 573 | print('error: cannot connect to manifest server %s:\n%s' |
547 | % (self.manifest.manifest_server, e), file=sys.stderr) | 574 | % (self.manifest.manifest_server, e), file=sys.stderr) |
548 | sys.exit(1) | 575 | sys.exit(1) |
549 | except xmlrpclib.ProtocolError as e: | 576 | except xmlrpc.client.ProtocolError as e: |
550 | print('error: cannot connect to manifest server %s:\n%d %s' | 577 | print('error: cannot connect to manifest server %s:\n%d %s' |
551 | % (self.manifest.manifest_server, e.errcode, e.errmsg), | 578 | % (self.manifest.manifest_server, e.errcode, e.errmsg), |
552 | file=sys.stderr) | 579 | file=sys.stderr) |
@@ -571,7 +598,7 @@ later is required to fix a server side protocol bug. | |||
571 | mp.Sync_LocalHalf(syncbuf) | 598 | mp.Sync_LocalHalf(syncbuf) |
572 | if not syncbuf.Finish(): | 599 | if not syncbuf.Finish(): |
573 | sys.exit(1) | 600 | sys.exit(1) |
574 | self.manifest._Unload() | 601 | self._ReloadManifest(opt.manifest_name) |
575 | if opt.jobs is None: | 602 | if opt.jobs is None: |
576 | self.jobs = self.manifest.default.sync_j | 603 | self.jobs = self.manifest.default.sync_j |
577 | all_projects = self.GetProjects(args, | 604 | all_projects = self.GetProjects(args, |
@@ -596,7 +623,7 @@ later is required to fix a server side protocol bug. | |||
596 | # Iteratively fetch missing and/or nested unregistered submodules | 623 | # Iteratively fetch missing and/or nested unregistered submodules |
597 | previously_missing_set = set() | 624 | previously_missing_set = set() |
598 | while True: | 625 | while True: |
599 | self.manifest._Unload() | 626 | self._ReloadManifest(opt.manifest_name) |
600 | all_projects = self.GetProjects(args, | 627 | all_projects = self.GetProjects(args, |
601 | missing_ok=True, | 628 | missing_ok=True, |
602 | submodules_ok=opt.fetch_submodules) | 629 | submodules_ok=opt.fetch_submodules) |
diff --git a/subcmds/upload.py b/subcmds/upload.py index 48ee685c..a34938e5 100644 --- a/subcmds/upload.py +++ b/subcmds/upload.py | |||
@@ -23,6 +23,11 @@ from editor import Editor | |||
23 | from error import HookError, UploadError | 23 | from error import HookError, UploadError |
24 | from project import RepoHook | 24 | from project import RepoHook |
25 | 25 | ||
26 | try: | ||
27 | input = raw_input | ||
28 | except NameError: | ||
29 | pass | ||
30 | |||
26 | UNUSUAL_COMMIT_THRESHOLD = 5 | 31 | UNUSUAL_COMMIT_THRESHOLD = 5 |
27 | 32 | ||
28 | def _ConfirmManyUploads(multiple_branches=False): | 33 | def _ConfirmManyUploads(multiple_branches=False): |
@@ -33,7 +38,7 @@ def _ConfirmManyUploads(multiple_branches=False): | |||
33 | print('ATTENTION: You are uploading an unusually high number of commits.') | 38 | print('ATTENTION: You are uploading an unusually high number of commits.') |
34 | print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across ' | 39 | print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across ' |
35 | 'branches?)') | 40 | 'branches?)') |
36 | answer = raw_input("If you are sure you intend to do this, type 'yes': ").strip() | 41 | answer = input("If you are sure you intend to do this, type 'yes': ").strip() |
37 | return answer == "yes" | 42 | return answer == "yes" |
38 | 43 | ||
39 | def _die(fmt, *args): | 44 | def _die(fmt, *args): |