summaryrefslogtreecommitdiffstats
path: root/subcmds/sync.py
diff options
context:
space:
mode:
Diffstat (limited to 'subcmds/sync.py')
-rw-r--r--subcmds/sync.py102
1 files changed, 66 insertions, 36 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py
index b50df099..43d450be 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -14,10 +14,10 @@
14# limitations under the License. 14# limitations under the License.
15 15
16from __future__ import print_function 16from __future__ import print_function
17import json
17import netrc 18import netrc
18from optparse import SUPPRESS_HELP 19from optparse import SUPPRESS_HELP
19import os 20import os
20import pickle
21import re 21import re
22import shutil 22import shutil
23import socket 23import socket
@@ -119,6 +119,11 @@ credentials.
119The -f/--force-broken option can be used to proceed with syncing 119The -f/--force-broken option can be used to proceed with syncing
120other projects if a project sync fails. 120other projects if a project sync fails.
121 121
122The --force-sync option can be used to overwrite existing git
123directories if they have previously been linked to a different
124object direcotry. WARNING: This may cause data to be lost since
125refs may be removed when overwriting.
126
122The --no-clone-bundle option disables any attempt to use 127The --no-clone-bundle option disables any attempt to use
123$URL/clone.bundle to bootstrap a new Git repository from a 128$URL/clone.bundle to bootstrap a new Git repository from a
124resumeable bundle file on a content delivery network. This 129resumeable bundle file on a content delivery network. This
@@ -128,6 +133,13 @@ HTTP client or proxy configuration, but the Git binary works.
128The --fetch-submodules option enables fetching Git submodules 133The --fetch-submodules option enables fetching Git submodules
129of a project from server. 134of a project from server.
130 135
136The -c/--current-branch option can be used to only fetch objects that
137are on the branch specified by a project's revision.
138
139The --optimized-fetch option can be used to only fetch projects that
140are fixed to a sha1 revision if the sha1 revision does not already
141exist locally.
142
131SSH Connections 143SSH Connections
132--------------- 144---------------
133 145
@@ -167,6 +179,11 @@ later is required to fix a server side protocol bug.
167 p.add_option('-f', '--force-broken', 179 p.add_option('-f', '--force-broken',
168 dest='force_broken', action='store_true', 180 dest='force_broken', action='store_true',
169 help="continue sync even if a project fails to sync") 181 help="continue sync even if a project fails to sync")
182 p.add_option('--force-sync',
183 dest='force_sync', action='store_true',
184 help="overwrite an existing git directory if it needs to "
185 "point to a different object directory. WARNING: this "
186 "may cause loss of data")
170 p.add_option('-l', '--local-only', 187 p.add_option('-l', '--local-only',
171 dest='local_only', action='store_true', 188 dest='local_only', action='store_true',
172 help="only update working tree, don't fetch") 189 help="only update working tree, don't fetch")
@@ -203,6 +220,9 @@ later is required to fix a server side protocol bug.
203 p.add_option('--no-tags', 220 p.add_option('--no-tags',
204 dest='no_tags', action='store_true', 221 dest='no_tags', action='store_true',
205 help="don't fetch tags") 222 help="don't fetch tags")
223 p.add_option('--optimized-fetch',
224 dest='optimized_fetch', action='store_true',
225 help='only fetch projects fixed to sha1 if revision does not exist locally')
206 if show_smart: 226 if show_smart:
207 p.add_option('-s', '--smart-sync', 227 p.add_option('-s', '--smart-sync',
208 dest='smart_sync', action='store_true', 228 dest='smart_sync', action='store_true',
@@ -271,8 +291,10 @@ later is required to fix a server side protocol bug.
271 success = project.Sync_NetworkHalf( 291 success = project.Sync_NetworkHalf(
272 quiet=opt.quiet, 292 quiet=opt.quiet,
273 current_branch_only=opt.current_branch_only, 293 current_branch_only=opt.current_branch_only,
294 force_sync=opt.force_sync,
274 clone_bundle=not opt.no_clone_bundle, 295 clone_bundle=not opt.no_clone_bundle,
275 no_tags=opt.no_tags, archive=self.manifest.IsArchive) 296 no_tags=opt.no_tags, archive=self.manifest.IsArchive,
297 optimized_fetch=opt.optimized_fetch)
276 self._fetch_times.Set(project, time.time() - start) 298 self._fetch_times.Set(project, time.time() - start)
277 299
278 # Lock around all the rest of the code, since printing, updating a set 300 # Lock around all the rest of the code, since printing, updating a set
@@ -508,6 +530,9 @@ later is required to fix a server side protocol bug.
508 self.manifest.Override(opt.manifest_name) 530 self.manifest.Override(opt.manifest_name)
509 531
510 manifest_name = opt.manifest_name 532 manifest_name = opt.manifest_name
533 smart_sync_manifest_name = "smart_sync_override.xml"
534 smart_sync_manifest_path = os.path.join(
535 self.manifest.manifestProject.worktree, smart_sync_manifest_name)
511 536
512 if opt.smart_sync or opt.smart_tag: 537 if opt.smart_sync or opt.smart_tag:
513 if not self.manifest.manifest_server: 538 if not self.manifest.manifest_server:
@@ -560,7 +585,10 @@ later is required to fix a server side protocol bug.
560 branch = branch[len(R_HEADS):] 585 branch = branch[len(R_HEADS):]
561 586
562 env = os.environ.copy() 587 env = os.environ.copy()
563 if 'TARGET_PRODUCT' in env and 'TARGET_BUILD_VARIANT' in env: 588 if 'SYNC_TARGET' in env:
589 target = env['SYNC_TARGET']
590 [success, manifest_str] = server.GetApprovedManifest(branch, target)
591 elif 'TARGET_PRODUCT' in env and 'TARGET_BUILD_VARIANT' in env:
564 target = '%s-%s' % (env['TARGET_PRODUCT'], 592 target = '%s-%s' % (env['TARGET_PRODUCT'],
565 env['TARGET_BUILD_VARIANT']) 593 env['TARGET_BUILD_VARIANT'])
566 [success, manifest_str] = server.GetApprovedManifest(branch, target) 594 [success, manifest_str] = server.GetApprovedManifest(branch, target)
@@ -571,17 +599,16 @@ later is required to fix a server side protocol bug.
571 [success, manifest_str] = server.GetManifest(opt.smart_tag) 599 [success, manifest_str] = server.GetManifest(opt.smart_tag)
572 600
573 if success: 601 if success:
574 manifest_name = "smart_sync_override.xml" 602 manifest_name = smart_sync_manifest_name
575 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
576 manifest_name)
577 try: 603 try:
578 f = open(manifest_path, 'w') 604 f = open(smart_sync_manifest_path, 'w')
579 try: 605 try:
580 f.write(manifest_str) 606 f.write(manifest_str)
581 finally: 607 finally:
582 f.close() 608 f.close()
583 except IOError: 609 except IOError as e:
584 print('error: cannot write manifest to %s' % manifest_path, 610 print('error: cannot write manifest to %s:\n%s'
611 % (smart_sync_manifest_path, e),
585 file=sys.stderr) 612 file=sys.stderr)
586 sys.exit(1) 613 sys.exit(1)
587 self._ReloadManifest(manifest_name) 614 self._ReloadManifest(manifest_name)
@@ -598,6 +625,13 @@ later is required to fix a server side protocol bug.
598 % (self.manifest.manifest_server, e.errcode, e.errmsg), 625 % (self.manifest.manifest_server, e.errcode, e.errmsg),
599 file=sys.stderr) 626 file=sys.stderr)
600 sys.exit(1) 627 sys.exit(1)
628 else: # Not smart sync or smart tag mode
629 if os.path.isfile(smart_sync_manifest_path):
630 try:
631 os.remove(smart_sync_manifest_path)
632 except OSError as e:
633 print('error: failed to remove existing smart sync override manifest: %s' %
634 e, file=sys.stderr)
601 635
602 rp = self.manifest.repoProject 636 rp = self.manifest.repoProject
603 rp.PreSync() 637 rp.PreSync()
@@ -611,7 +645,8 @@ later is required to fix a server side protocol bug.
611 if not opt.local_only: 645 if not opt.local_only:
612 mp.Sync_NetworkHalf(quiet=opt.quiet, 646 mp.Sync_NetworkHalf(quiet=opt.quiet,
613 current_branch_only=opt.current_branch_only, 647 current_branch_only=opt.current_branch_only,
614 no_tags=opt.no_tags) 648 no_tags=opt.no_tags,
649 optimized_fetch=opt.optimized_fetch)
615 650
616 if mp.HasChanges: 651 if mp.HasChanges:
617 syncbuf = SyncBuffer(mp.config) 652 syncbuf = SyncBuffer(mp.config)
@@ -674,7 +709,7 @@ later is required to fix a server side protocol bug.
674 for project in all_projects: 709 for project in all_projects:
675 pm.update() 710 pm.update()
676 if project.worktree: 711 if project.worktree:
677 project.Sync_LocalHalf(syncbuf) 712 project.Sync_LocalHalf(syncbuf, force_sync=opt.force_sync)
678 pm.end() 713 pm.end()
679 print(file=sys.stderr) 714 print(file=sys.stderr)
680 if not syncbuf.Finish(): 715 if not syncbuf.Finish():
@@ -762,7 +797,7 @@ class _FetchTimes(object):
762 _ALPHA = 0.5 797 _ALPHA = 0.5
763 798
764 def __init__(self, manifest): 799 def __init__(self, manifest):
765 self._path = os.path.join(manifest.repodir, '.repopickle_fetchtimes') 800 self._path = os.path.join(manifest.repodir, '.repo_fetchtimes.json')
766 self._times = None 801 self._times = None
767 self._seen = set() 802 self._seen = set()
768 803
@@ -781,22 +816,17 @@ class _FetchTimes(object):
781 def _Load(self): 816 def _Load(self):
782 if self._times is None: 817 if self._times is None:
783 try: 818 try:
784 f = open(self._path, 'rb') 819 f = open(self._path)
785 except IOError:
786 self._times = {}
787 return self._times
788 try:
789 try: 820 try:
790 self._times = pickle.load(f) 821 self._times = json.load(f)
791 except IOError: 822 finally:
792 try: 823 f.close()
793 os.remove(self._path) 824 except (IOError, ValueError):
794 except OSError: 825 try:
795 pass 826 os.remove(self._path)
796 self._times = {} 827 except OSError:
797 finally: 828 pass
798 f.close() 829 self._times = {}
799 return self._times
800 830
801 def Save(self): 831 def Save(self):
802 if self._times is None: 832 if self._times is None:
@@ -810,13 +840,13 @@ class _FetchTimes(object):
810 del self._times[name] 840 del self._times[name]
811 841
812 try: 842 try:
813 f = open(self._path, 'wb') 843 f = open(self._path, 'w')
814 try: 844 try:
815 pickle.dump(self._times, f) 845 json.dump(self._times, f, indent=2)
816 except (IOError, OSError, pickle.PickleError): 846 finally:
817 try: 847 f.close()
818 os.remove(self._path) 848 except (IOError, TypeError):
819 except OSError: 849 try:
820 pass 850 os.remove(self._path)
821 finally: 851 except OSError:
822 f.close() 852 pass