summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--error.py4
-rw-r--r--git_command.py7
-rw-r--r--git_config.py2
-rwxr-xr-xmain.py7
-rw-r--r--manifest_xml.py12
-rw-r--r--project.py96
-rw-r--r--subcmds/cherry_pick.py1
-rw-r--r--subcmds/forall.py40
-rw-r--r--subcmds/init.py4
-rw-r--r--subcmds/sync.py34
10 files changed, 160 insertions, 47 deletions
diff --git a/error.py b/error.py
index ff948f9c..f2a7c4e4 100644
--- a/error.py
+++ b/error.py
@@ -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):
diff --git a/main.py b/main.py
index 47f083df..6736abc9 100755
--- a/main.py
+++ b/main.py
@@ -45,6 +45,7 @@ from command import MirrorSafeCommand
45from subcmds.version import Version 45from subcmds.version import Version
46from editor import Editor 46from editor import Editor
47from error import DownloadError 47from error import DownloadError
48from error import InvalidProjectGroupsError
48from error import ManifestInvalidRevisionError 49from error import ManifestInvalidRevisionError
49from error import ManifestParseError 50from error import ManifestParseError
50from error import NoManifestException 51from 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:
diff --git a/project.py b/project.py
index 003489aa..d0d3b6eb 100644
--- a/project.py
+++ b/project.py
@@ -16,6 +16,7 @@ from __future__ import print_function
16import contextlib 16import contextlib
17import errno 17import errno
18import filecmp 18import filecmp
19import glob
19import os 20import os
20import random 21import random
21import re 22import 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
235class _LinkFile(object): 236class _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
259class RemoteSpec(object): 292class 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
20import re 20import re
21import os 21import os
22import select 22import select
23import signal
23import sys 24import sys
24import subprocess 25import 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
240class WorkerKeyboardInterrupt(Exception): 263class WorkerKeyboardInterrupt(Exception):
241 """ Keyboard interrupt exception for worker processes. """ 264 """ Keyboard interrupt exception for worker processes. """
242 pass 265 pass
243 266
244 267
268def InitWorker():
269 signal.signal(signal.SIGINT, signal.SIG_IGN)
270
245def DoWorkWrapper(args): 271def 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
32from color import Coloring 32from color import Coloring
33from command import InteractiveCommand, MirrorSafeCommand 33from 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.
131The -c/--current-branch option can be used to only fetch objects that 131The -c/--current-branch option can be used to only fetch objects that
132are on the branch specified by a project's revision. 132are on the branch specified by a project's revision.
133 133
134The --optimized-fetch option can be used to only fetch projects that
135are fixed to a sha1 revision if the sha1 revision does not already
136exist locally.
137
134SSH Connections 138SSH 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)