diff options
-rw-r--r-- | error.py | 4 | ||||
-rw-r--r-- | git_command.py | 7 | ||||
-rw-r--r-- | git_config.py | 2 | ||||
-rwxr-xr-x | main.py | 7 | ||||
-rw-r--r-- | manifest_xml.py | 12 | ||||
-rw-r--r-- | project.py | 96 | ||||
-rw-r--r-- | subcmds/cherry_pick.py | 1 | ||||
-rw-r--r-- | subcmds/forall.py | 40 | ||||
-rw-r--r-- | subcmds/init.py | 4 | ||||
-rw-r--r-- | subcmds/sync.py | 34 |
10 files changed, 160 insertions, 47 deletions
@@ -80,7 +80,7 @@ class NoSuchProjectError(Exception): | |||
80 | self.name = name | 80 | self.name = name |
81 | 81 | ||
82 | def __str__(self): | 82 | def __str__(self): |
83 | if self.Name is None: | 83 | if self.name is None: |
84 | return 'in current directory' | 84 | return 'in current directory' |
85 | return self.name | 85 | return self.name |
86 | 86 | ||
@@ -93,7 +93,7 @@ class InvalidProjectGroupsError(Exception): | |||
93 | self.name = name | 93 | self.name = name |
94 | 94 | ||
95 | def __str__(self): | 95 | def __str__(self): |
96 | if self.Name is None: | 96 | if self.name is None: |
97 | return 'in current directory' | 97 | return 'in current directory' |
98 | return self.name | 98 | return self.name |
99 | 99 | ||
diff --git a/git_command.py b/git_command.py index 259fb02c..0893bff7 100644 --- a/git_command.py +++ b/git_command.py | |||
@@ -92,7 +92,10 @@ class _GitCall(object): | |||
92 | def version(self): | 92 | def version(self): |
93 | p = GitCommand(None, ['--version'], capture_stdout=True) | 93 | p = GitCommand(None, ['--version'], capture_stdout=True) |
94 | if p.Wait() == 0: | 94 | if p.Wait() == 0: |
95 | return p.stdout.decode('utf-8') | 95 | if hasattr(p.stdout, 'decode'): |
96 | return p.stdout.decode('utf-8') | ||
97 | else: | ||
98 | return p.stdout | ||
96 | return None | 99 | return None |
97 | 100 | ||
98 | def version_tuple(self): | 101 | def version_tuple(self): |
@@ -263,6 +266,8 @@ class GitCommand(object): | |||
263 | if not buf: | 266 | if not buf: |
264 | s_in.remove(s) | 267 | s_in.remove(s) |
265 | continue | 268 | continue |
269 | if not hasattr(buf, 'encode'): | ||
270 | buf = buf.decode() | ||
266 | if s.std_name == 'stdout': | 271 | if s.std_name == 'stdout': |
267 | self.stdout += buf | 272 | self.stdout += buf |
268 | else: | 273 | else: |
diff --git a/git_config.py b/git_config.py index c4c31e18..8ded7c25 100644 --- a/git_config.py +++ b/git_config.py | |||
@@ -280,7 +280,7 @@ class GitConfig(object): | |||
280 | finally: | 280 | finally: |
281 | fd.close() | 281 | fd.close() |
282 | except (IOError, TypeError): | 282 | except (IOError, TypeError): |
283 | if os.path.exists(self.json): | 283 | if os.path.exists(self._json): |
284 | os.remove(self._json) | 284 | os.remove(self._json) |
285 | 285 | ||
286 | def _ReadGit(self): | 286 | def _ReadGit(self): |
@@ -45,6 +45,7 @@ from command import MirrorSafeCommand | |||
45 | from subcmds.version import Version | 45 | from subcmds.version import Version |
46 | from editor import Editor | 46 | from editor import Editor |
47 | from error import DownloadError | 47 | from error import DownloadError |
48 | from error import InvalidProjectGroupsError | ||
48 | from error import ManifestInvalidRevisionError | 49 | from error import ManifestInvalidRevisionError |
49 | from error import ManifestParseError | 50 | from error import ManifestParseError |
50 | from error import NoManifestException | 51 | from error import NoManifestException |
@@ -173,6 +174,12 @@ class _Repo(object): | |||
173 | else: | 174 | else: |
174 | print('error: no project in current directory', file=sys.stderr) | 175 | print('error: no project in current directory', file=sys.stderr) |
175 | result = 1 | 176 | result = 1 |
177 | except InvalidProjectGroupsError as e: | ||
178 | if e.name: | ||
179 | print('error: project group must be enabled for project %s' % e.name, file=sys.stderr) | ||
180 | else: | ||
181 | print('error: project group must be enabled for the project in the current directory', file=sys.stderr) | ||
182 | result = 1 | ||
176 | finally: | 183 | finally: |
177 | elapsed = time.time() - start | 184 | elapsed = time.time() - start |
178 | hours, remainder = divmod(elapsed, 3600) | 185 | hours, remainder = divmod(elapsed, 3600) |
diff --git a/manifest_xml.py b/manifest_xml.py index cfbd9efa..130e17c2 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
@@ -253,11 +253,13 @@ class XmlManifest(object): | |||
253 | else: | 253 | else: |
254 | value = p.work_git.rev_parse(HEAD + '^0') | 254 | value = p.work_git.rev_parse(HEAD + '^0') |
255 | e.setAttribute('revision', value) | 255 | e.setAttribute('revision', value) |
256 | if peg_rev_upstream and value != p.revisionExpr: | 256 | if peg_rev_upstream: |
257 | # Only save the origin if the origin is not a sha1, and the default | 257 | if p.upstream: |
258 | # isn't our value, and the if the default doesn't already have that | 258 | e.setAttribute('upstream', p.upstream) |
259 | # covered. | 259 | elif value != p.revisionExpr: |
260 | e.setAttribute('upstream', p.revisionExpr) | 260 | # Only save the origin if the origin is not a sha1, and the default |
261 | # isn't our value | ||
262 | e.setAttribute('upstream', p.revisionExpr) | ||
261 | else: | 263 | else: |
262 | revision = self.remotes[remoteName].revision or d.revisionExpr | 264 | revision = self.remotes[remoteName].revision or d.revisionExpr |
263 | if not revision or revision != p.revisionExpr: | 265 | if not revision or revision != p.revisionExpr: |
@@ -16,6 +16,7 @@ from __future__ import print_function | |||
16 | import contextlib | 16 | import contextlib |
17 | import errno | 17 | import errno |
18 | import filecmp | 18 | import filecmp |
19 | import glob | ||
19 | import os | 20 | import os |
20 | import random | 21 | import random |
21 | import re | 22 | import re |
@@ -233,28 +234,60 @@ class _CopyFile(object): | |||
233 | _error('Cannot copy file %s to %s', src, dest) | 234 | _error('Cannot copy file %s to %s', src, dest) |
234 | 235 | ||
235 | class _LinkFile(object): | 236 | class _LinkFile(object): |
236 | def __init__(self, src, dest, abssrc, absdest): | 237 | def __init__(self, git_worktree, src, dest, relsrc, absdest): |
238 | self.git_worktree = git_worktree | ||
237 | self.src = src | 239 | self.src = src |
238 | self.dest = dest | 240 | self.dest = dest |
239 | self.abs_src = abssrc | 241 | self.src_rel_to_dest = relsrc |
240 | self.abs_dest = absdest | 242 | self.abs_dest = absdest |
241 | 243 | ||
242 | def _Link(self): | 244 | def __linkIt(self, relSrc, absDest): |
243 | src = self.abs_src | ||
244 | dest = self.abs_dest | ||
245 | # link file if it does not exist or is out of date | 245 | # link file if it does not exist or is out of date |
246 | if not os.path.islink(dest) or os.readlink(dest) != src: | 246 | if not os.path.islink(absDest) or (os.readlink(absDest) != relSrc): |
247 | try: | 247 | try: |
248 | # remove existing file first, since it might be read-only | 248 | # remove existing file first, since it might be read-only |
249 | if os.path.exists(dest): | 249 | if os.path.exists(absDest): |
250 | os.remove(dest) | 250 | os.remove(absDest) |
251 | else: | 251 | else: |
252 | dest_dir = os.path.dirname(dest) | 252 | dest_dir = os.path.dirname(absDest) |
253 | if not os.path.isdir(dest_dir): | 253 | if not os.path.isdir(dest_dir): |
254 | os.makedirs(dest_dir) | 254 | os.makedirs(dest_dir) |
255 | os.symlink(src, dest) | 255 | os.symlink(relSrc, absDest) |
256 | except IOError: | 256 | except IOError: |
257 | _error('Cannot link file %s to %s', src, dest) | 257 | _error('Cannot link file %s to %s', relSrc, absDest) |
258 | |||
259 | def _Link(self): | ||
260 | """Link the self.rel_src_to_dest and self.abs_dest. Handles wild cards | ||
261 | on the src linking all of the files in the source in to the destination | ||
262 | directory. | ||
263 | """ | ||
264 | # We use the absSrc to handle the situation where the current directory | ||
265 | # is not the root of the repo | ||
266 | absSrc = os.path.join(self.git_worktree, self.src) | ||
267 | if os.path.exists(absSrc): | ||
268 | # Entity exists so just a simple one to one link operation | ||
269 | self.__linkIt(self.src_rel_to_dest, self.abs_dest) | ||
270 | else: | ||
271 | # Entity doesn't exist assume there is a wild card | ||
272 | absDestDir = self.abs_dest | ||
273 | if os.path.exists(absDestDir) and not os.path.isdir(absDestDir): | ||
274 | _error('Link error: src with wildcard, %s must be a directory', | ||
275 | absDestDir) | ||
276 | else: | ||
277 | absSrcFiles = glob.glob(absSrc) | ||
278 | for absSrcFile in absSrcFiles: | ||
279 | # Create a releative path from source dir to destination dir | ||
280 | absSrcDir = os.path.dirname(absSrcFile) | ||
281 | relSrcDir = os.path.relpath(absSrcDir, absDestDir) | ||
282 | |||
283 | # Get the source file name | ||
284 | srcFile = os.path.basename(absSrcFile) | ||
285 | |||
286 | # Now form the final full paths to srcFile. They will be | ||
287 | # absolute for the desintaiton and relative for the srouce. | ||
288 | absDest = os.path.join(absDestDir, srcFile) | ||
289 | relSrc = os.path.join(relSrcDir, srcFile) | ||
290 | self.__linkIt(relSrc, absDest) | ||
258 | 291 | ||
259 | class RemoteSpec(object): | 292 | class RemoteSpec(object): |
260 | def __init__(self, | 293 | def __init__(self, |
@@ -535,7 +568,8 @@ class Project(object): | |||
535 | upstream=None, | 568 | upstream=None, |
536 | parent=None, | 569 | parent=None, |
537 | is_derived=False, | 570 | is_derived=False, |
538 | dest_branch=None): | 571 | dest_branch=None, |
572 | optimized_fetch=False): | ||
539 | """Init a Project object. | 573 | """Init a Project object. |
540 | 574 | ||
541 | Args: | 575 | Args: |
@@ -557,6 +591,8 @@ class Project(object): | |||
557 | is_derived: False if the project was explicitly defined in the manifest; | 591 | is_derived: False if the project was explicitly defined in the manifest; |
558 | True if the project is a discovered submodule. | 592 | True if the project is a discovered submodule. |
559 | dest_branch: The branch to which to push changes for review by default. | 593 | dest_branch: The branch to which to push changes for review by default. |
594 | optimized_fetch: If True, when a project is set to a sha1 revision, only | ||
595 | fetch from the remote if the sha1 is not present locally. | ||
560 | """ | 596 | """ |
561 | self.manifest = manifest | 597 | self.manifest = manifest |
562 | self.name = name | 598 | self.name = name |
@@ -585,6 +621,7 @@ class Project(object): | |||
585 | self.upstream = upstream | 621 | self.upstream = upstream |
586 | self.parent = parent | 622 | self.parent = parent |
587 | self.is_derived = is_derived | 623 | self.is_derived = is_derived |
624 | self.optimized_fetch = optimized_fetch | ||
588 | self.subprojects = [] | 625 | self.subprojects = [] |
589 | 626 | ||
590 | self.snapshots = {} | 627 | self.snapshots = {} |
@@ -1066,7 +1103,8 @@ class Project(object): | |||
1066 | current_branch_only=False, | 1103 | current_branch_only=False, |
1067 | clone_bundle=True, | 1104 | clone_bundle=True, |
1068 | no_tags=False, | 1105 | no_tags=False, |
1069 | archive=False): | 1106 | archive=False, |
1107 | optimized_fetch=False): | ||
1070 | """Perform only the network IO portion of the sync process. | 1108 | """Perform only the network IO portion of the sync process. |
1071 | Local working directory/branch state is not affected. | 1109 | Local working directory/branch state is not affected. |
1072 | """ | 1110 | """ |
@@ -1134,8 +1172,9 @@ class Project(object): | |||
1134 | elif self.manifest.default.sync_c: | 1172 | elif self.manifest.default.sync_c: |
1135 | current_branch_only = True | 1173 | current_branch_only = True |
1136 | 1174 | ||
1137 | has_sha1 = ID_RE.match(self.revisionExpr) and self._CheckForSha1() | 1175 | need_to_fetch = not (optimized_fetch and \ |
1138 | if (not has_sha1 #Need to fetch since we don't already have this revision | 1176 | (ID_RE.match(self.revisionExpr) and self._CheckForSha1())) |
1177 | if (need_to_fetch | ||
1139 | and not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir, | 1178 | and not self._RemoteFetch(initial=is_new, quiet=quiet, alt_dir=alt_dir, |
1140 | current_branch_only=current_branch_only, | 1179 | current_branch_only=current_branch_only, |
1141 | no_tags=no_tags)): | 1180 | no_tags=no_tags)): |
@@ -1358,9 +1397,10 @@ class Project(object): | |||
1358 | 1397 | ||
1359 | def AddLinkFile(self, src, dest, absdest): | 1398 | def AddLinkFile(self, src, dest, absdest): |
1360 | # dest should already be an absolute path, but src is project relative | 1399 | # dest should already be an absolute path, but src is project relative |
1361 | # make src an absolute path | 1400 | # make src relative path to dest |
1362 | abssrc = os.path.join(self.worktree, src) | 1401 | absdestdir = os.path.dirname(absdest) |
1363 | self.linkfiles.append(_LinkFile(src, dest, abssrc, absdest)) | 1402 | relsrc = os.path.relpath(os.path.join(self.worktree, src), absdestdir) |
1403 | self.linkfiles.append(_LinkFile(self.worktree, src, dest, relsrc, absdest)) | ||
1364 | 1404 | ||
1365 | def AddAnnotation(self, name, value, keep): | 1405 | def AddAnnotation(self, name, value, keep): |
1366 | self.annotations.append(_Annotation(name, value, keep)) | 1406 | self.annotations.append(_Annotation(name, value, keep)) |
@@ -1401,7 +1441,7 @@ class Project(object): | |||
1401 | branch = self.GetBranch(name) | 1441 | branch = self.GetBranch(name) |
1402 | branch.remote = self.GetRemote(self.remote.name) | 1442 | branch.remote = self.GetRemote(self.remote.name) |
1403 | branch.merge = self.revisionExpr | 1443 | branch.merge = self.revisionExpr |
1404 | if not branch.merge.startswith('refs/'): | 1444 | if not branch.merge.startswith('refs/') and not ID_RE.match(self.revisionExpr): |
1405 | branch.merge = R_HEADS + self.revisionExpr | 1445 | branch.merge = R_HEADS + self.revisionExpr |
1406 | revid = self.GetRevisionId(all_refs) | 1446 | revid = self.GetRevisionId(all_refs) |
1407 | 1447 | ||
@@ -1841,6 +1881,8 @@ class Project(object): | |||
1841 | cmd.append('--quiet') | 1881 | cmd.append('--quiet') |
1842 | if not self.worktree: | 1882 | if not self.worktree: |
1843 | cmd.append('--update-head-ok') | 1883 | cmd.append('--update-head-ok') |
1884 | if self.manifest.IsMirror: | ||
1885 | cmd.append('--prune') | ||
1844 | cmd.append(name) | 1886 | cmd.append(name) |
1845 | 1887 | ||
1846 | # If using depth then we should not get all the tags since they may | 1888 | # If using depth then we should not get all the tags since they may |
@@ -1860,7 +1902,7 @@ class Project(object): | |||
1860 | 1902 | ||
1861 | if not self.manifest.IsMirror: | 1903 | if not self.manifest.IsMirror: |
1862 | branch = self.revisionExpr | 1904 | branch = self.revisionExpr |
1863 | if is_sha1 and depth: | 1905 | if is_sha1 and depth and git_require((1, 8, 3)): |
1864 | # Shallow checkout of a specific commit, fetch from that commit and not | 1906 | # Shallow checkout of a specific commit, fetch from that commit and not |
1865 | # the heads only as the commit might be deeper in the history. | 1907 | # the heads only as the commit might be deeper in the history. |
1866 | spec.append(branch) | 1908 | spec.append(branch) |
@@ -1905,6 +1947,9 @@ class Project(object): | |||
1905 | # mode, we just tried sync'ing from the upstream field; it doesn't exist, thus | 1947 | # mode, we just tried sync'ing from the upstream field; it doesn't exist, thus |
1906 | # abort the optimization attempt and do a full sync. | 1948 | # abort the optimization attempt and do a full sync. |
1907 | break | 1949 | break |
1950 | elif ret < 0: | ||
1951 | # Git died with a signal, exit immediately | ||
1952 | break | ||
1908 | time.sleep(random.randint(30, 45)) | 1953 | time.sleep(random.randint(30, 45)) |
1909 | 1954 | ||
1910 | if initial: | 1955 | if initial: |
@@ -1920,8 +1965,15 @@ class Project(object): | |||
1920 | # got what we wanted, else trigger a second run of all | 1965 | # got what we wanted, else trigger a second run of all |
1921 | # refs. | 1966 | # refs. |
1922 | if not self._CheckForSha1(): | 1967 | if not self._CheckForSha1(): |
1923 | return self._RemoteFetch(name=name, current_branch_only=False, | 1968 | if not depth: |
1924 | initial=False, quiet=quiet, alt_dir=alt_dir) | 1969 | # Avoid infinite recursion when depth is True (since depth implies |
1970 | # current_branch_only) | ||
1971 | return self._RemoteFetch(name=name, current_branch_only=False, | ||
1972 | initial=False, quiet=quiet, alt_dir=alt_dir) | ||
1973 | if self.clone_depth: | ||
1974 | self.clone_depth = None | ||
1975 | return self._RemoteFetch(name=name, current_branch_only=current_branch_only, | ||
1976 | initial=False, quiet=quiet, alt_dir=alt_dir) | ||
1925 | 1977 | ||
1926 | return ok | 1978 | return ok |
1927 | 1979 | ||
diff --git a/subcmds/cherry_pick.py b/subcmds/cherry_pick.py index 520e4c32..1f7dffdc 100644 --- a/subcmds/cherry_pick.py +++ b/subcmds/cherry_pick.py | |||
@@ -76,6 +76,7 @@ change id will be added. | |||
76 | capture_stdout = True, | 76 | capture_stdout = True, |
77 | capture_stderr = True) | 77 | capture_stderr = True) |
78 | p.stdin.write(new_msg) | 78 | p.stdin.write(new_msg) |
79 | p.stdin.close() | ||
79 | if p.Wait() != 0: | 80 | if p.Wait() != 0: |
80 | print("error: Failed to update commit message", file=sys.stderr) | 81 | print("error: Failed to update commit message", file=sys.stderr) |
81 | sys.exit(1) | 82 | sys.exit(1) |
diff --git a/subcmds/forall.py b/subcmds/forall.py index 88b23fbd..b93cd6d0 100644 --- a/subcmds/forall.py +++ b/subcmds/forall.py | |||
@@ -20,6 +20,7 @@ import multiprocessing | |||
20 | import re | 20 | import re |
21 | import os | 21 | import os |
22 | import select | 22 | import select |
23 | import signal | ||
23 | import sys | 24 | import sys |
24 | import subprocess | 25 | import subprocess |
25 | 26 | ||
@@ -150,11 +151,15 @@ without iterating through the remaining projects. | |||
150 | attributes that we need. | 151 | attributes that we need. |
151 | 152 | ||
152 | """ | 153 | """ |
154 | if not self.manifest.IsMirror: | ||
155 | lrev = project.GetRevisionId() | ||
156 | else: | ||
157 | lrev = None | ||
153 | return { | 158 | return { |
154 | 'name': project.name, | 159 | 'name': project.name, |
155 | 'relpath': project.relpath, | 160 | 'relpath': project.relpath, |
156 | 'remote_name': project.remote.name, | 161 | 'remote_name': project.remote.name, |
157 | 'lrev': project.GetRevisionId(), | 162 | 'lrev': lrev, |
158 | 'rrev': project.revisionExpr, | 163 | 'rrev': project.revisionExpr, |
159 | 'annotations': dict((a.name, a.value) for a in project.annotations), | 164 | 'annotations': dict((a.name, a.value) for a in project.annotations), |
160 | 'gitdir': project.gitdir, | 165 | 'gitdir': project.gitdir, |
@@ -200,6 +205,13 @@ without iterating through the remaining projects. | |||
200 | mirror = self.manifest.IsMirror | 205 | mirror = self.manifest.IsMirror |
201 | rc = 0 | 206 | rc = 0 |
202 | 207 | ||
208 | smart_sync_manifest_name = "smart_sync_override.xml" | ||
209 | smart_sync_manifest_path = os.path.join( | ||
210 | self.manifest.manifestProject.worktree, smart_sync_manifest_name) | ||
211 | |||
212 | if os.path.isfile(smart_sync_manifest_path): | ||
213 | self.manifest.Override(smart_sync_manifest_path) | ||
214 | |||
203 | if not opt.regex: | 215 | if not opt.regex: |
204 | projects = self.GetProjects(args) | 216 | projects = self.GetProjects(args) |
205 | else: | 217 | else: |
@@ -207,14 +219,12 @@ without iterating through the remaining projects. | |||
207 | 219 | ||
208 | os.environ['REPO_COUNT'] = str(len(projects)) | 220 | os.environ['REPO_COUNT'] = str(len(projects)) |
209 | 221 | ||
210 | pool = multiprocessing.Pool(opt.jobs) | 222 | pool = multiprocessing.Pool(opt.jobs, InitWorker) |
211 | try: | 223 | try: |
212 | config = self.manifest.manifestProject.config | 224 | config = self.manifest.manifestProject.config |
213 | results_it = pool.imap( | 225 | results_it = pool.imap( |
214 | DoWorkWrapper, | 226 | DoWorkWrapper, |
215 | ([mirror, opt, cmd, shell, cnt, config, self._SerializeProject(p)] | 227 | self.ProjectArgs(projects, mirror, opt, cmd, shell, config)) |
216 | for cnt, p in enumerate(projects)) | ||
217 | ) | ||
218 | pool.close() | 228 | pool.close() |
219 | for r in results_it: | 229 | for r in results_it: |
220 | rc = rc or r | 230 | rc = rc or r |
@@ -236,12 +246,28 @@ without iterating through the remaining projects. | |||
236 | if rc != 0: | 246 | if rc != 0: |
237 | sys.exit(rc) | 247 | sys.exit(rc) |
238 | 248 | ||
249 | def ProjectArgs(self, projects, mirror, opt, cmd, shell, config): | ||
250 | for cnt, p in enumerate(projects): | ||
251 | try: | ||
252 | project = self._SerializeProject(p) | ||
253 | except Exception as e: | ||
254 | print('Project list error: %r' % e, | ||
255 | file=sys.stderr) | ||
256 | return | ||
257 | except KeyboardInterrupt: | ||
258 | print('Project list interrupted', | ||
259 | file=sys.stderr) | ||
260 | return | ||
261 | yield [mirror, opt, cmd, shell, cnt, config, project] | ||
239 | 262 | ||
240 | class WorkerKeyboardInterrupt(Exception): | 263 | class WorkerKeyboardInterrupt(Exception): |
241 | """ Keyboard interrupt exception for worker processes. """ | 264 | """ Keyboard interrupt exception for worker processes. """ |
242 | pass | 265 | pass |
243 | 266 | ||
244 | 267 | ||
268 | def InitWorker(): | ||
269 | signal.signal(signal.SIGINT, signal.SIG_IGN) | ||
270 | |||
245 | def DoWorkWrapper(args): | 271 | def DoWorkWrapper(args): |
246 | """ A wrapper around the DoWork() method. | 272 | """ A wrapper around the DoWork() method. |
247 | 273 | ||
@@ -263,7 +289,9 @@ def DoWork(project, mirror, opt, cmd, shell, cnt, config): | |||
263 | def setenv(name, val): | 289 | def setenv(name, val): |
264 | if val is None: | 290 | if val is None: |
265 | val = '' | 291 | val = '' |
266 | env[name] = val.encode() | 292 | if hasattr(val, 'encode'): |
293 | val = val.encode() | ||
294 | env[name] = val | ||
267 | 295 | ||
268 | setenv('REPO_PROJECT', project['name']) | 296 | setenv('REPO_PROJECT', project['name']) |
269 | setenv('REPO_PATH', project['relpath']) | 297 | setenv('REPO_PATH', project['relpath']) |
diff --git a/subcmds/init.py b/subcmds/init.py index b73de71c..dbb6ddda 100644 --- a/subcmds/init.py +++ b/subcmds/init.py | |||
@@ -27,7 +27,7 @@ else: | |||
27 | import imp | 27 | import imp |
28 | import urlparse | 28 | import urlparse |
29 | urllib = imp.new_module('urllib') | 29 | urllib = imp.new_module('urllib') |
30 | urllib.parse = urlparse.urlparse | 30 | urllib.parse = urlparse |
31 | 31 | ||
32 | from color import Coloring | 32 | from color import Coloring |
33 | from command import InteractiveCommand, MirrorSafeCommand | 33 | from command import InteractiveCommand, MirrorSafeCommand |
@@ -153,7 +153,7 @@ to update the working directory files. | |||
153 | # server where this git is located, so let's save that here. | 153 | # server where this git is located, so let's save that here. |
154 | mirrored_manifest_git = None | 154 | mirrored_manifest_git = None |
155 | if opt.reference: | 155 | if opt.reference: |
156 | manifest_git_path = urllib.parse(opt.manifest_url).path[1:] | 156 | manifest_git_path = urllib.parse.urlparse(opt.manifest_url).path[1:] |
157 | mirrored_manifest_git = os.path.join(opt.reference, manifest_git_path) | 157 | mirrored_manifest_git = os.path.join(opt.reference, manifest_git_path) |
158 | if not mirrored_manifest_git.endswith(".git"): | 158 | if not mirrored_manifest_git.endswith(".git"): |
159 | mirrored_manifest_git += ".git" | 159 | mirrored_manifest_git += ".git" |
diff --git a/subcmds/sync.py b/subcmds/sync.py index 2bdab3a6..ec333ae7 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
@@ -131,6 +131,10 @@ of a project from server. | |||
131 | The -c/--current-branch option can be used to only fetch objects that | 131 | The -c/--current-branch option can be used to only fetch objects that |
132 | are on the branch specified by a project's revision. | 132 | are on the branch specified by a project's revision. |
133 | 133 | ||
134 | The --optimized-fetch option can be used to only fetch projects that | ||
135 | are fixed to a sha1 revision if the sha1 revision does not already | ||
136 | exist locally. | ||
137 | |||
134 | SSH Connections | 138 | SSH Connections |
135 | --------------- | 139 | --------------- |
136 | 140 | ||
@@ -206,6 +210,9 @@ later is required to fix a server side protocol bug. | |||
206 | p.add_option('--no-tags', | 210 | p.add_option('--no-tags', |
207 | dest='no_tags', action='store_true', | 211 | dest='no_tags', action='store_true', |
208 | help="don't fetch tags") | 212 | help="don't fetch tags") |
213 | p.add_option('--optimized-fetch', | ||
214 | dest='optimized_fetch', action='store_true', | ||
215 | help='only fetch projects fixed to sha1 if revision does not exist locally') | ||
209 | if show_smart: | 216 | if show_smart: |
210 | p.add_option('-s', '--smart-sync', | 217 | p.add_option('-s', '--smart-sync', |
211 | dest='smart_sync', action='store_true', | 218 | dest='smart_sync', action='store_true', |
@@ -275,7 +282,8 @@ later is required to fix a server side protocol bug. | |||
275 | quiet=opt.quiet, | 282 | quiet=opt.quiet, |
276 | current_branch_only=opt.current_branch_only, | 283 | current_branch_only=opt.current_branch_only, |
277 | clone_bundle=not opt.no_clone_bundle, | 284 | clone_bundle=not opt.no_clone_bundle, |
278 | no_tags=opt.no_tags, archive=self.manifest.IsArchive) | 285 | no_tags=opt.no_tags, archive=self.manifest.IsArchive, |
286 | optimized_fetch=opt.optimized_fetch) | ||
279 | self._fetch_times.Set(project, time.time() - start) | 287 | self._fetch_times.Set(project, time.time() - start) |
280 | 288 | ||
281 | # Lock around all the rest of the code, since printing, updating a set | 289 | # Lock around all the rest of the code, since printing, updating a set |
@@ -509,6 +517,9 @@ later is required to fix a server side protocol bug. | |||
509 | self.manifest.Override(opt.manifest_name) | 517 | self.manifest.Override(opt.manifest_name) |
510 | 518 | ||
511 | manifest_name = opt.manifest_name | 519 | manifest_name = opt.manifest_name |
520 | smart_sync_manifest_name = "smart_sync_override.xml" | ||
521 | smart_sync_manifest_path = os.path.join( | ||
522 | self.manifest.manifestProject.worktree, smart_sync_manifest_name) | ||
512 | 523 | ||
513 | if opt.smart_sync or opt.smart_tag: | 524 | if opt.smart_sync or opt.smart_tag: |
514 | if not self.manifest.manifest_server: | 525 | if not self.manifest.manifest_server: |
@@ -575,17 +586,16 @@ later is required to fix a server side protocol bug. | |||
575 | [success, manifest_str] = server.GetManifest(opt.smart_tag) | 586 | [success, manifest_str] = server.GetManifest(opt.smart_tag) |
576 | 587 | ||
577 | if success: | 588 | if success: |
578 | manifest_name = "smart_sync_override.xml" | 589 | manifest_name = smart_sync_manifest_name |
579 | manifest_path = os.path.join(self.manifest.manifestProject.worktree, | ||
580 | manifest_name) | ||
581 | try: | 590 | try: |
582 | f = open(manifest_path, 'w') | 591 | f = open(smart_sync_manifest_path, 'w') |
583 | try: | 592 | try: |
584 | f.write(manifest_str) | 593 | f.write(manifest_str) |
585 | finally: | 594 | finally: |
586 | f.close() | 595 | f.close() |
587 | except IOError: | 596 | except IOError as e: |
588 | print('error: cannot write manifest to %s' % manifest_path, | 597 | print('error: cannot write manifest to %s:\n%s' |
598 | % (smart_sync_manifest_path, e), | ||
589 | file=sys.stderr) | 599 | file=sys.stderr) |
590 | sys.exit(1) | 600 | sys.exit(1) |
591 | self._ReloadManifest(manifest_name) | 601 | self._ReloadManifest(manifest_name) |
@@ -602,6 +612,13 @@ later is required to fix a server side protocol bug. | |||
602 | % (self.manifest.manifest_server, e.errcode, e.errmsg), | 612 | % (self.manifest.manifest_server, e.errcode, e.errmsg), |
603 | file=sys.stderr) | 613 | file=sys.stderr) |
604 | sys.exit(1) | 614 | sys.exit(1) |
615 | else: # Not smart sync or smart tag mode | ||
616 | if os.path.isfile(smart_sync_manifest_path): | ||
617 | try: | ||
618 | os.remove(smart_sync_manifest_path) | ||
619 | except OSError as e: | ||
620 | print('error: failed to remove existing smart sync override manifest: %s' % | ||
621 | e, file=sys.stderr) | ||
605 | 622 | ||
606 | rp = self.manifest.repoProject | 623 | rp = self.manifest.repoProject |
607 | rp.PreSync() | 624 | rp.PreSync() |
@@ -615,7 +632,8 @@ later is required to fix a server side protocol bug. | |||
615 | if not opt.local_only: | 632 | if not opt.local_only: |
616 | mp.Sync_NetworkHalf(quiet=opt.quiet, | 633 | mp.Sync_NetworkHalf(quiet=opt.quiet, |
617 | current_branch_only=opt.current_branch_only, | 634 | current_branch_only=opt.current_branch_only, |
618 | no_tags=opt.no_tags) | 635 | no_tags=opt.no_tags, |
636 | optimized_fetch=opt.optimized_fetch) | ||
619 | 637 | ||
620 | if mp.HasChanges: | 638 | if mp.HasChanges: |
621 | syncbuf = SyncBuffer(mp.config) | 639 | syncbuf = SyncBuffer(mp.config) |