diff options
-rw-r--r-- | docs/manifest-format.txt | 12 | ||||
-rw-r--r-- | git_command.py | 2 | ||||
-rw-r--r-- | git_config.py | 4 | ||||
-rw-r--r-- | git_refs.py | 2 | ||||
-rwxr-xr-x | hooks/commit-msg | 4 | ||||
-rw-r--r-- | manifest_xml.py | 28 | ||||
-rw-r--r-- | project.py | 75 | ||||
-rwxr-xr-x | repo | 36 | ||||
-rw-r--r-- | subcmds/branches.py | 2 | ||||
-rw-r--r-- | subcmds/init.py | 21 | ||||
-rw-r--r-- | subcmds/sync.py | 13 | ||||
-rw-r--r-- | subcmds/upload.py | 5 |
12 files changed, 154 insertions, 50 deletions
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt index dcc90d07..e48b75fe 100644 --- a/docs/manifest-format.txt +++ b/docs/manifest-format.txt | |||
@@ -27,15 +27,15 @@ following DTD: | |||
27 | remove-project*, | 27 | remove-project*, |
28 | project*, | 28 | project*, |
29 | repo-hooks?)> | 29 | repo-hooks?)> |
30 | 30 | ||
31 | <!ELEMENT notice (#PCDATA)> | 31 | <!ELEMENT notice (#PCDATA)> |
32 | 32 | ||
33 | <!ELEMENT remote (EMPTY)> | 33 | <!ELEMENT remote (EMPTY)> |
34 | <!ATTLIST remote name ID #REQUIRED> | 34 | <!ATTLIST remote name ID #REQUIRED> |
35 | <!ATTLIST remote alias CDATA #IMPLIED> | 35 | <!ATTLIST remote alias CDATA #IMPLIED> |
36 | <!ATTLIST remote fetch CDATA #REQUIRED> | 36 | <!ATTLIST remote fetch CDATA #REQUIRED> |
37 | <!ATTLIST remote review CDATA #IMPLIED> | 37 | <!ATTLIST remote review CDATA #IMPLIED> |
38 | 38 | ||
39 | <!ELEMENT default (EMPTY)> | 39 | <!ELEMENT default (EMPTY)> |
40 | <!ATTLIST default remote IDREF #IMPLIED> | 40 | <!ATTLIST default remote IDREF #IMPLIED> |
41 | <!ATTLIST default revision CDATA #IMPLIED> | 41 | <!ATTLIST default revision CDATA #IMPLIED> |
@@ -46,8 +46,8 @@ following DTD: | |||
46 | 46 | ||
47 | <!ELEMENT manifest-server (EMPTY)> | 47 | <!ELEMENT manifest-server (EMPTY)> |
48 | <!ATTLIST url CDATA #REQUIRED> | 48 | <!ATTLIST url CDATA #REQUIRED> |
49 | 49 | ||
50 | <!ELEMENT project (annotation?, | 50 | <!ELEMENT project (annotation*, |
51 | project*)> | 51 | project*)> |
52 | <!ATTLIST project name CDATA #REQUIRED> | 52 | <!ATTLIST project name CDATA #REQUIRED> |
53 | <!ATTLIST project path CDATA #IMPLIED> | 53 | <!ATTLIST project path CDATA #IMPLIED> |
@@ -65,7 +65,7 @@ following DTD: | |||
65 | <!ATTLIST annotation name CDATA #REQUIRED> | 65 | <!ATTLIST annotation name CDATA #REQUIRED> |
66 | <!ATTLIST annotation value CDATA #REQUIRED> | 66 | <!ATTLIST annotation value CDATA #REQUIRED> |
67 | <!ATTLIST annotation keep CDATA "true"> | 67 | <!ATTLIST annotation keep CDATA "true"> |
68 | 68 | ||
69 | <!ELEMENT remove-project (EMPTY)> | 69 | <!ELEMENT remove-project (EMPTY)> |
70 | <!ATTLIST remove-project name CDATA #REQUIRED> | 70 | <!ATTLIST remove-project name CDATA #REQUIRED> |
71 | 71 | ||
diff --git a/git_command.py b/git_command.py index d347dd61..51f5e3c0 100644 --- a/git_command.py +++ b/git_command.py | |||
@@ -86,7 +86,7 @@ class _GitCall(object): | |||
86 | global _git_version | 86 | global _git_version |
87 | 87 | ||
88 | if _git_version is None: | 88 | if _git_version is None: |
89 | ver_str = git.version() | 89 | ver_str = git.version().decode('utf-8') |
90 | if ver_str.startswith('git version '): | 90 | if ver_str.startswith('git version '): |
91 | _git_version = tuple( | 91 | _git_version = tuple( |
92 | map(int, | 92 | map(int, |
diff --git a/git_config.py b/git_config.py index a294a0b6..f6093a25 100644 --- a/git_config.py +++ b/git_config.py | |||
@@ -304,8 +304,8 @@ class GitConfig(object): | |||
304 | d = self._do('--null', '--list') | 304 | d = self._do('--null', '--list') |
305 | if d is None: | 305 | if d is None: |
306 | return c | 306 | return c |
307 | for line in d.rstrip('\0').split('\0'): # pylint: disable=W1401 | 307 | for line in d.decode('utf-8').rstrip('\0').split('\0'): # pylint: disable=W1401 |
308 | # Backslash is not anomalous | 308 | # Backslash is not anomalous |
309 | if '\n' in line: | 309 | if '\n' in line: |
310 | key, val = line.split('\n', 1) | 310 | key, val = line.split('\n', 1) |
311 | else: | 311 | else: |
diff --git a/git_refs.py b/git_refs.py index 4dd68769..3c266061 100644 --- a/git_refs.py +++ b/git_refs.py | |||
@@ -100,7 +100,7 @@ class GitRefs(object): | |||
100 | def _ReadPackedRefs(self): | 100 | def _ReadPackedRefs(self): |
101 | path = os.path.join(self._gitdir, 'packed-refs') | 101 | path = os.path.join(self._gitdir, 'packed-refs') |
102 | try: | 102 | try: |
103 | fd = open(path, 'rb') | 103 | fd = open(path, 'r') |
104 | mtime = os.path.getmtime(path) | 104 | mtime = os.path.getmtime(path) |
105 | except IOError: | 105 | except IOError: |
106 | return | 106 | return |
diff --git a/hooks/commit-msg b/hooks/commit-msg index b37dfaa4..5ca2b112 100755 --- a/hooks/commit-msg +++ b/hooks/commit-msg | |||
@@ -1,5 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # From Gerrit Code Review 2.5.2 | 2 | # From Gerrit Code Review 2.6 |
3 | # | 3 | # |
4 | # Part of Gerrit Code Review (http://code.google.com/p/gerrit/) | 4 | # Part of Gerrit Code Review (http://code.google.com/p/gerrit/) |
5 | # | 5 | # |
@@ -154,7 +154,7 @@ add_ChangeId() { | |||
154 | if (unprinted) { | 154 | if (unprinted) { |
155 | print "Change-Id: I'"$id"'" | 155 | print "Change-Id: I'"$id"'" |
156 | } | 156 | } |
157 | }' "$MSG" > $T && mv $T "$MSG" || rm -f $T | 157 | }' "$MSG" > "$T" && mv "$T" "$MSG" || rm -f "$T" |
158 | } | 158 | } |
159 | _gen_ChangeIdInput() { | 159 | _gen_ChangeIdInput() { |
160 | echo "tree `git write-tree`" | 160 | echo "tree `git write-tree`" |
diff --git a/manifest_xml.py b/manifest_xml.py index 647e89f9..c5f3bcc9 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
@@ -51,6 +51,12 @@ class _Default(object): | |||
51 | sync_c = False | 51 | sync_c = False |
52 | sync_s = False | 52 | sync_s = False |
53 | 53 | ||
54 | def __eq__(self, other): | ||
55 | return self.__dict__ == other.__dict__ | ||
56 | |||
57 | def __ne__(self, other): | ||
58 | return self.__dict__ != other.__dict__ | ||
59 | |||
54 | class _XmlRemote(object): | 60 | class _XmlRemote(object): |
55 | def __init__(self, | 61 | def __init__(self, |
56 | name, | 62 | name, |
@@ -92,7 +98,7 @@ class _XmlRemote(object): | |||
92 | url = self.resolvedFetchUrl.rstrip('/') + '/' + projectName | 98 | url = self.resolvedFetchUrl.rstrip('/') + '/' + projectName |
93 | remoteName = self.name | 99 | remoteName = self.name |
94 | if self.remoteAlias: | 100 | if self.remoteAlias: |
95 | remoteName = self.remoteAlias | 101 | remoteName = self.remoteAlias |
96 | return RemoteSpec(remoteName, url, self.reviewUrl) | 102 | return RemoteSpec(remoteName, url, self.reviewUrl) |
97 | 103 | ||
98 | class XmlManifest(object): | 104 | class XmlManifest(object): |
@@ -228,7 +234,9 @@ class XmlManifest(object): | |||
228 | e.setAttribute('name', name) | 234 | e.setAttribute('name', name) |
229 | if relpath != name: | 235 | if relpath != name: |
230 | e.setAttribute('path', relpath) | 236 | e.setAttribute('path', relpath) |
231 | remoteName = d.remote.remoteAlias or d.remote.name | 237 | remoteName = None |
238 | if d.remote: | ||
239 | remoteName = d.remote.remoteAlias or d.remote.name | ||
232 | if not d.remote or p.remote.name != remoteName: | 240 | if not d.remote or p.remote.name != remoteName: |
233 | e.setAttribute('remote', p.remote.name) | 241 | e.setAttribute('remote', p.remote.name) |
234 | if peg_rev: | 242 | if peg_rev: |
@@ -325,6 +333,10 @@ class XmlManifest(object): | |||
325 | def IsMirror(self): | 333 | def IsMirror(self): |
326 | return self.manifestProject.config.GetBoolean('repo.mirror') | 334 | return self.manifestProject.config.GetBoolean('repo.mirror') |
327 | 335 | ||
336 | @property | ||
337 | def IsArchive(self): | ||
338 | return self.manifestProject.config.GetBoolean('repo.archive') | ||
339 | |||
328 | def _Unload(self): | 340 | def _Unload(self): |
329 | self._loaded = False | 341 | self._loaded = False |
330 | self._projects = {} | 342 | self._projects = {} |
@@ -432,11 +444,13 @@ class XmlManifest(object): | |||
432 | 444 | ||
433 | for node in itertools.chain(*node_list): | 445 | for node in itertools.chain(*node_list): |
434 | if node.nodeName == 'default': | 446 | if node.nodeName == 'default': |
435 | if self._default is not None: | 447 | new_default = self._ParseDefault(node) |
436 | raise ManifestParseError( | 448 | if self._default is None: |
437 | 'duplicate default in %s' % | 449 | self._default = new_default |
438 | (self.manifestFile)) | 450 | elif new_default != self._default: |
439 | self._default = self._ParseDefault(node) | 451 | raise ManifestParseError('duplicate default in %s' % |
452 | (self.manifestFile)) | ||
453 | |||
440 | if self._default is None: | 454 | if self._default is None: |
441 | self._default = _Default() | 455 | self._default = _Default() |
442 | 456 | ||
@@ -23,6 +23,7 @@ import shutil | |||
23 | import stat | 23 | import stat |
24 | import subprocess | 24 | import subprocess |
25 | import sys | 25 | import sys |
26 | import tarfile | ||
26 | import tempfile | 27 | import tempfile |
27 | import time | 28 | import time |
28 | 29 | ||
@@ -82,7 +83,7 @@ def _ProjectHooks(): | |||
82 | """ | 83 | """ |
83 | global _project_hook_list | 84 | global _project_hook_list |
84 | if _project_hook_list is None: | 85 | if _project_hook_list is None: |
85 | d = os.path.abspath(os.path.dirname(__file__)) | 86 | d = os.path.realpath(os.path.abspath(os.path.dirname(__file__))) |
86 | d = os.path.join(d , 'hooks') | 87 | d = os.path.join(d , 'hooks') |
87 | _project_hook_list = [os.path.join(d, x) for x in os.listdir(d)] | 88 | _project_hook_list = [os.path.join(d, x) for x in os.listdir(d)] |
88 | return _project_hook_list | 89 | return _project_hook_list |
@@ -986,15 +987,62 @@ class Project(object): | |||
986 | 987 | ||
987 | ## Sync ## | 988 | ## Sync ## |
988 | 989 | ||
990 | def _ExtractArchive(self, tarpath, path=None): | ||
991 | """Extract the given tar on its current location | ||
992 | |||
993 | Args: | ||
994 | - tarpath: The path to the actual tar file | ||
995 | |||
996 | """ | ||
997 | try: | ||
998 | with tarfile.open(tarpath, 'r') as tar: | ||
999 | tar.extractall(path=path) | ||
1000 | return True | ||
1001 | except (IOError, tarfile.TarError) as e: | ||
1002 | print("error: Cannot extract archive %s: " | ||
1003 | "%s" % (tarpath, str(e)), file=sys.stderr) | ||
1004 | return False | ||
1005 | |||
989 | def Sync_NetworkHalf(self, | 1006 | def Sync_NetworkHalf(self, |
990 | quiet=False, | 1007 | quiet=False, |
991 | is_new=None, | 1008 | is_new=None, |
992 | current_branch_only=False, | 1009 | current_branch_only=False, |
993 | clone_bundle=True, | 1010 | clone_bundle=True, |
994 | no_tags=False): | 1011 | no_tags=False, |
1012 | archive=False): | ||
995 | """Perform only the network IO portion of the sync process. | 1013 | """Perform only the network IO portion of the sync process. |
996 | Local working directory/branch state is not affected. | 1014 | Local working directory/branch state is not affected. |
997 | """ | 1015 | """ |
1016 | if archive and not isinstance(self, MetaProject): | ||
1017 | if self.remote.url.startswith(('http://', 'https://')): | ||
1018 | print("error: %s: Cannot fetch archives from http/https " | ||
1019 | "remotes." % self.name, file=sys.stderr) | ||
1020 | return False | ||
1021 | |||
1022 | name = self.relpath.replace('\\', '/') | ||
1023 | name = name.replace('/', '_') | ||
1024 | tarpath = '%s.tar' % name | ||
1025 | topdir = self.manifest.topdir | ||
1026 | |||
1027 | try: | ||
1028 | self._FetchArchive(tarpath, cwd=topdir) | ||
1029 | except GitError as e: | ||
1030 | print('error: %s' % str(e), file=sys.stderr) | ||
1031 | return False | ||
1032 | |||
1033 | # From now on, we only need absolute tarpath | ||
1034 | tarpath = os.path.join(topdir, tarpath) | ||
1035 | |||
1036 | if not self._ExtractArchive(tarpath, path=topdir): | ||
1037 | return False | ||
1038 | try: | ||
1039 | os.remove(tarpath) | ||
1040 | except OSError as e: | ||
1041 | print("warn: Cannot remove archive %s: " | ||
1042 | "%s" % (tarpath, str(e)), file=sys.stderr) | ||
1043 | self._CopyFiles() | ||
1044 | return True | ||
1045 | |||
998 | if is_new is None: | 1046 | if is_new is None: |
999 | is_new = not self.Exists | 1047 | is_new = not self.Exists |
1000 | if is_new: | 1048 | if is_new: |
@@ -1169,7 +1217,7 @@ class Project(object): | |||
1169 | last_mine = None | 1217 | last_mine = None |
1170 | cnt_mine = 0 | 1218 | cnt_mine = 0 |
1171 | for commit in local_changes: | 1219 | for commit in local_changes: |
1172 | commit_id, committer_email = commit.split(' ', 1) | 1220 | commit_id, committer_email = commit.decode('utf-8').split(' ', 1) |
1173 | if committer_email == self.UserEmail: | 1221 | if committer_email == self.UserEmail: |
1174 | last_mine = commit_id | 1222 | last_mine = commit_id |
1175 | cnt_mine += 1 | 1223 | cnt_mine += 1 |
@@ -1580,6 +1628,19 @@ class Project(object): | |||
1580 | 1628 | ||
1581 | ## Direct Git Commands ## | 1629 | ## Direct Git Commands ## |
1582 | 1630 | ||
1631 | def _FetchArchive(self, tarpath, cwd=None): | ||
1632 | cmd = ['archive', '-v', '-o', tarpath] | ||
1633 | cmd.append('--remote=%s' % self.remote.url) | ||
1634 | cmd.append('--prefix=%s/' % self.relpath) | ||
1635 | cmd.append(self.revisionExpr) | ||
1636 | |||
1637 | command = GitCommand(self, cmd, cwd=cwd, | ||
1638 | capture_stdout=True, | ||
1639 | capture_stderr=True) | ||
1640 | |||
1641 | if command.Wait() != 0: | ||
1642 | raise GitError('git archive %s: %s' % (self.name, command.stderr)) | ||
1643 | |||
1583 | def _RemoteFetch(self, name=None, | 1644 | def _RemoteFetch(self, name=None, |
1584 | current_branch_only=False, | 1645 | current_branch_only=False, |
1585 | initial=False, | 1646 | initial=False, |
@@ -1847,11 +1908,11 @@ class Project(object): | |||
1847 | cookiefile = line[len(prefix):] | 1908 | cookiefile = line[len(prefix):] |
1848 | break | 1909 | break |
1849 | if p.wait(): | 1910 | if p.wait(): |
1850 | line = iter(p.stderr).next() | 1911 | err_msg = p.stderr.read() |
1851 | if ' -print_config' in line: | 1912 | if ' -print_config' in err_msg: |
1852 | pass # Persistent proxy doesn't support -print_config. | 1913 | pass # Persistent proxy doesn't support -print_config. |
1853 | else: | 1914 | else: |
1854 | print(line + p.stderr.read(), file=sys.stderr) | 1915 | print(err_msg, file=sys.stderr) |
1855 | if cookiefile: | 1916 | if cookiefile: |
1856 | return cookiefile | 1917 | return cookiefile |
1857 | except OSError as e: | 1918 | except OSError as e: |
@@ -1971,7 +2032,7 @@ class Project(object): | |||
1971 | self._InitHooks() | 2032 | self._InitHooks() |
1972 | 2033 | ||
1973 | def _InitHooks(self): | 2034 | def _InitHooks(self): |
1974 | hooks = self._gitdir_path('hooks') | 2035 | hooks = os.path.realpath(self._gitdir_path('hooks')) |
1975 | if not os.path.exists(hooks): | 2036 | if not os.path.exists(hooks): |
1976 | os.makedirs(hooks) | 2037 | os.makedirs(hooks) |
1977 | for stock_hook in _ProjectHooks(): | 2038 | for stock_hook in _ProjectHooks(): |
@@ -110,6 +110,7 @@ REPO_MAIN = S_repo + '/main.py' # main script | |||
110 | MIN_PYTHON_VERSION = (2, 6) # minimum supported python version | 110 | MIN_PYTHON_VERSION = (2, 6) # minimum supported python version |
111 | 111 | ||
112 | 112 | ||
113 | import errno | ||
113 | import optparse | 114 | import optparse |
114 | import os | 115 | import os |
115 | import re | 116 | import re |
@@ -138,10 +139,9 @@ def _print(*objects, **kwargs): | |||
138 | # Python version check | 139 | # Python version check |
139 | ver = sys.version_info | 140 | ver = sys.version_info |
140 | if ver[0] == 3: | 141 | if ver[0] == 3: |
141 | _print('error: Python 3 support is not fully implemented in repo yet.\n' | 142 | _print('warning: Python 3 support is currently experimental. YMMV.\n' |
142 | 'Please use Python 2.6 - 2.7 instead.', | 143 | 'Please use Python 2.6 - 2.7 instead.', |
143 | file=sys.stderr) | 144 | file=sys.stderr) |
144 | sys.exit(1) | ||
145 | if (ver[0], ver[1]) < MIN_PYTHON_VERSION: | 145 | if (ver[0], ver[1]) < MIN_PYTHON_VERSION: |
146 | _print('error: Python version %s unsupported.\n' | 146 | _print('error: Python version %s unsupported.\n' |
147 | 'Please use Python 2.6 - 2.7 instead.' | 147 | 'Please use Python 2.6 - 2.7 instead.' |
@@ -181,6 +181,10 @@ group.add_option('--reference', | |||
181 | group.add_option('--depth', type='int', default=None, | 181 | group.add_option('--depth', type='int', default=None, |
182 | dest='depth', | 182 | dest='depth', |
183 | help='create a shallow clone with given depth; see git clone') | 183 | help='create a shallow clone with given depth; see git clone') |
184 | group.add_option('--archive', | ||
185 | dest='archive', action='store_true', | ||
186 | help='checkout an archive instead of a git repository for ' | ||
187 | 'each project. See git archive.') | ||
184 | group.add_option('-g', '--groups', | 188 | group.add_option('-g', '--groups', |
185 | dest='groups', default='default', | 189 | dest='groups', default='default', |
186 | help='restrict manifest projects to ones with specified ' | 190 | help='restrict manifest projects to ones with specified ' |
@@ -240,10 +244,10 @@ def _Init(args): | |||
240 | _print("fatal: invalid branch name '%s'" % branch, file=sys.stderr) | 244 | _print("fatal: invalid branch name '%s'" % branch, file=sys.stderr) |
241 | raise CloneFailure() | 245 | raise CloneFailure() |
242 | 246 | ||
243 | if not os.path.isdir(repodir): | 247 | try: |
244 | try: | 248 | os.mkdir(repodir) |
245 | os.mkdir(repodir) | 249 | except OSError as e: |
246 | except OSError as e: | 250 | if e.errno != errno.EEXIST: |
247 | _print('fatal: cannot make %s directory: %s' | 251 | _print('fatal: cannot make %s directory: %s' |
248 | % (repodir, e.strerror), file=sys.stderr) | 252 | % (repodir, e.strerror), file=sys.stderr) |
249 | # Don't raise CloneFailure; that would delete the | 253 | # Don't raise CloneFailure; that would delete the |
@@ -322,18 +326,18 @@ def NeedSetupGnuPG(): | |||
322 | 326 | ||
323 | 327 | ||
324 | def SetupGnuPG(quiet): | 328 | def SetupGnuPG(quiet): |
325 | if not os.path.isdir(home_dot_repo): | 329 | try: |
326 | try: | 330 | os.mkdir(home_dot_repo) |
327 | os.mkdir(home_dot_repo) | 331 | except OSError as e: |
328 | except OSError as e: | 332 | if e.errno != errno.EEXIST: |
329 | _print('fatal: cannot make %s directory: %s' | 333 | _print('fatal: cannot make %s directory: %s' |
330 | % (home_dot_repo, e.strerror), file=sys.stderr) | 334 | % (home_dot_repo, e.strerror), file=sys.stderr) |
331 | sys.exit(1) | 335 | sys.exit(1) |
332 | 336 | ||
333 | if not os.path.isdir(gpg_dir): | 337 | try: |
334 | try: | 338 | os.mkdir(gpg_dir, stat.S_IRWXU) |
335 | os.mkdir(gpg_dir, stat.S_IRWXU) | 339 | except OSError as e: |
336 | except OSError as e: | 340 | if e.errno != errno.EEXIST: |
337 | _print('fatal: cannot make %s directory: %s' % (gpg_dir, e.strerror), | 341 | _print('fatal: cannot make %s directory: %s' % (gpg_dir, e.strerror), |
338 | file=sys.stderr) | 342 | file=sys.stderr) |
339 | sys.exit(1) | 343 | sys.exit(1) |
@@ -739,7 +743,7 @@ def main(orig_args): | |||
739 | repo_main = my_main | 743 | repo_main = my_main |
740 | 744 | ||
741 | ver_str = '.'.join(map(str, VERSION)) | 745 | ver_str = '.'.join(map(str, VERSION)) |
742 | me = [repo_main, | 746 | me = [sys.executable, repo_main, |
743 | '--repo-dir=%s' % rel_repo_dir, | 747 | '--repo-dir=%s' % rel_repo_dir, |
744 | '--wrapper-version=%s' % ver_str, | 748 | '--wrapper-version=%s' % ver_str, |
745 | '--wrapper-path=%s' % wrapper_path, | 749 | '--wrapper-path=%s' % wrapper_path, |
@@ -747,7 +751,7 @@ def main(orig_args): | |||
747 | me.extend(orig_args) | 751 | me.extend(orig_args) |
748 | me.extend(extra_args) | 752 | me.extend(extra_args) |
749 | try: | 753 | try: |
750 | os.execv(repo_main, me) | 754 | os.execv(sys.executable, me) |
751 | except OSError as e: | 755 | except OSError as e: |
752 | _print("fatal: unable to start %s" % repo_main, file=sys.stderr) | 756 | _print("fatal: unable to start %s" % repo_main, file=sys.stderr) |
753 | _print("fatal: %s" % e, file=sys.stderr) | 757 | _print("fatal: %s" % e, file=sys.stderr) |
diff --git a/subcmds/branches.py b/subcmds/branches.py index c2e7c4b9..f714c1e8 100644 --- a/subcmds/branches.py +++ b/subcmds/branches.py | |||
@@ -139,7 +139,7 @@ is shown, then the branch appears in all projects. | |||
139 | if in_cnt < project_cnt: | 139 | if in_cnt < project_cnt: |
140 | fmt = out.write | 140 | fmt = out.write |
141 | paths = [] | 141 | paths = [] |
142 | if in_cnt < project_cnt - in_cnt: | 142 | if in_cnt < project_cnt - in_cnt: |
143 | in_type = 'in' | 143 | in_type = 'in' |
144 | for b in i.projects: | 144 | for b in i.projects: |
145 | paths.append(b.project.relpath) | 145 | paths.append(b.project.relpath) |
diff --git a/subcmds/init.py b/subcmds/init.py index a44fb7a9..b1fcb69c 100644 --- a/subcmds/init.py +++ b/subcmds/init.py | |||
@@ -99,6 +99,10 @@ to update the working directory files. | |||
99 | g.add_option('--depth', type='int', default=None, | 99 | g.add_option('--depth', type='int', default=None, |
100 | dest='depth', | 100 | dest='depth', |
101 | help='create a shallow clone with given depth; see git clone') | 101 | help='create a shallow clone with given depth; see git clone') |
102 | g.add_option('--archive', | ||
103 | dest='archive', action='store_true', | ||
104 | help='checkout an archive instead of a git repository for ' | ||
105 | 'each project. See git archive.') | ||
102 | g.add_option('-g', '--groups', | 106 | g.add_option('-g', '--groups', |
103 | dest='groups', default='default', | 107 | dest='groups', default='default', |
104 | help='restrict manifest projects to ones with specified ' | 108 | help='restrict manifest projects to ones with specified ' |
@@ -198,6 +202,16 @@ to update the working directory files. | |||
198 | if opt.reference: | 202 | if opt.reference: |
199 | m.config.SetString('repo.reference', opt.reference) | 203 | m.config.SetString('repo.reference', opt.reference) |
200 | 204 | ||
205 | if opt.archive: | ||
206 | if is_new: | ||
207 | m.config.SetString('repo.archive', 'true') | ||
208 | else: | ||
209 | print('fatal: --archive is only supported when initializing a new ' | ||
210 | 'workspace.', file=sys.stderr) | ||
211 | print('Either delete the .repo folder in this workspace, or initialize ' | ||
212 | 'in another location.', file=sys.stderr) | ||
213 | sys.exit(1) | ||
214 | |||
201 | if opt.mirror: | 215 | if opt.mirror: |
202 | if is_new: | 216 | if is_new: |
203 | m.config.SetString('repo.mirror', 'true') | 217 | m.config.SetString('repo.mirror', 'true') |
@@ -366,6 +380,13 @@ to update the working directory files. | |||
366 | if opt.reference: | 380 | if opt.reference: |
367 | opt.reference = os.path.expanduser(opt.reference) | 381 | opt.reference = os.path.expanduser(opt.reference) |
368 | 382 | ||
383 | # Check this here, else manifest will be tagged "not new" and init won't be | ||
384 | # possible anymore without removing the .repo/manifests directory. | ||
385 | if opt.archive and opt.mirror: | ||
386 | print('fatal: --mirror and --archive cannot be used together.', | ||
387 | file=sys.stderr) | ||
388 | sys.exit(1) | ||
389 | |||
369 | self._SyncManifest(opt) | 390 | self._SyncManifest(opt) |
370 | self._LinkManifest(opt.manifest_name) | 391 | self._LinkManifest(opt.manifest_name) |
371 | 392 | ||
diff --git a/subcmds/sync.py b/subcmds/sync.py index d1a06412..5e7385db 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
@@ -272,7 +272,7 @@ later is required to fix a server side protocol bug. | |||
272 | quiet=opt.quiet, | 272 | quiet=opt.quiet, |
273 | current_branch_only=opt.current_branch_only, | 273 | current_branch_only=opt.current_branch_only, |
274 | clone_bundle=not opt.no_clone_bundle, | 274 | clone_bundle=not opt.no_clone_bundle, |
275 | no_tags=opt.no_tags) | 275 | no_tags=opt.no_tags, archive=self.manifest.IsArchive) |
276 | self._fetch_times.Set(project, time.time() - start) | 276 | self._fetch_times.Set(project, time.time() - start) |
277 | 277 | ||
278 | # Lock around all the rest of the code, since printing, updating a set | 278 | # Lock around all the rest of the code, since printing, updating a set |
@@ -315,7 +315,8 @@ later is required to fix a server side protocol bug. | |||
315 | quiet=opt.quiet, | 315 | quiet=opt.quiet, |
316 | current_branch_only=opt.current_branch_only, | 316 | current_branch_only=opt.current_branch_only, |
317 | clone_bundle=not opt.no_clone_bundle, | 317 | clone_bundle=not opt.no_clone_bundle, |
318 | no_tags=opt.no_tags): | 318 | no_tags=opt.no_tags, |
319 | archive=self.manifest.IsArchive): | ||
319 | fetched.add(project.gitdir) | 320 | fetched.add(project.gitdir) |
320 | else: | 321 | else: |
321 | print('error: Cannot fetch %s' % project.name, file=sys.stderr) | 322 | print('error: Cannot fetch %s' % project.name, file=sys.stderr) |
@@ -363,7 +364,9 @@ later is required to fix a server side protocol bug. | |||
363 | pm.end() | 364 | pm.end() |
364 | self._fetch_times.Save() | 365 | self._fetch_times.Save() |
365 | 366 | ||
366 | self._GCProjects(projects) | 367 | if not self.manifest.IsArchive: |
368 | self._GCProjects(projects) | ||
369 | |||
367 | return fetched | 370 | return fetched |
368 | 371 | ||
369 | def _GCProjects(self, projects): | 372 | def _GCProjects(self, projects): |
@@ -671,7 +674,7 @@ later is required to fix a server side protocol bug. | |||
671 | previously_missing_set = missing_set | 674 | previously_missing_set = missing_set |
672 | fetched.update(self._Fetch(missing, opt)) | 675 | fetched.update(self._Fetch(missing, opt)) |
673 | 676 | ||
674 | if self.manifest.IsMirror: | 677 | if self.manifest.IsMirror or self.manifest.IsArchive: |
675 | # bail out now, we have no working tree | 678 | # bail out now, we have no working tree |
676 | return | 679 | return |
677 | 680 | ||
@@ -791,7 +794,7 @@ class _FetchTimes(object): | |||
791 | def _Load(self): | 794 | def _Load(self): |
792 | if self._times is None: | 795 | if self._times is None: |
793 | try: | 796 | try: |
794 | f = open(self._path) | 797 | f = open(self._path, 'rb') |
795 | except IOError: | 798 | except IOError: |
796 | self._times = {} | 799 | self._times = {} |
797 | return self._times | 800 | return self._times |
diff --git a/subcmds/upload.py b/subcmds/upload.py index 9ad55d79..56212408 100644 --- a/subcmds/upload.py +++ b/subcmds/upload.py | |||
@@ -349,8 +349,9 @@ Gerrit Code Review: http://code.google.com/p/gerrit/ | |||
349 | 349 | ||
350 | # Make sure our local branch is not setup to track a different remote branch | 350 | # Make sure our local branch is not setup to track a different remote branch |
351 | merge_branch = self._GetMergeBranch(branch.project) | 351 | merge_branch = self._GetMergeBranch(branch.project) |
352 | full_dest = 'refs/heads/%s' % destination | 352 | if destination: |
353 | if not opt.dest_branch and merge_branch and merge_branch != full_dest: | 353 | full_dest = 'refs/heads/%s' % destination |
354 | if not opt.dest_branch and merge_branch and merge_branch != full_dest: | ||
354 | print('merge branch %s does not match destination branch %s' | 355 | print('merge branch %s does not match destination branch %s' |
355 | % (merge_branch, full_dest)) | 356 | % (merge_branch, full_dest)) |
356 | print('skipping upload.') | 357 | print('skipping upload.') |