summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2008-11-04 07:37:10 -0800
committerShawn O. Pearce <sop@google.com>2008-11-05 18:08:32 -0800
commite284ad1d1a2c6fa0e0ac800e87b2607f9bda339e (patch)
treefcf35ac784ec2e13c78ee3882ccb1fec0ad3d049
parent3e5481999d5f853e19ee5caaaaa968fc4b5176ab (diff)
downloadgit-repo-e284ad1d1a2c6fa0e0ac800e87b2607f9bda339e.tar.gz
Add 'repo init --mirror' to download a complete forrestv1.1
The mirror option downloads a complete forrest (as described by the manifest) and creates a replica of the remote repositories rather than a client working directory. This permits other clients to sync off the mirror site. A mirror can be positioned in a "DMZ", where the mirror executes "repo sync" to obtain changes from the external upstream and clients inside the protected zone operate off the mirror only, and therefore do not require direct git:// access to the external upstream repositories. Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r--git_config.py10
-rw-r--r--manifest.py57
-rw-r--r--project.py36
-rwxr-xr-xrepo5
-rw-r--r--subcmds/init.py16
-rw-r--r--subcmds/sync.py5
6 files changed, 109 insertions, 20 deletions
diff --git a/git_config.py b/git_config.py
index 76031a0e..9d5162e7 100644
--- a/git_config.py
+++ b/git_config.py
@@ -285,12 +285,14 @@ class Remote(object):
285 return True 285 return True
286 return False 286 return False
287 287
288 def ResetFetch(self): 288 def ResetFetch(self, mirror=False):
289 """Set the fetch refspec to its default value. 289 """Set the fetch refspec to its default value.
290 """ 290 """
291 self.fetch = [RefSpec(True, 291 if mirror:
292 'refs/heads/*', 292 dst = 'refs/heads/*'
293 'refs/remotes/%s/*' % self.name)] 293 else:
294 dst = 'refs/remotes/%s/*' % self.name
295 self.fetch = [RefSpec(True, 'refs/heads/*', dst)]
294 296
295 def Save(self): 297 def Save(self):
296 """Save this remote to the configuration. 298 """Save this remote to the configuration.
diff --git a/manifest.py b/manifest.py
index b928cdfe..ea68b682 100644
--- a/manifest.py
+++ b/manifest.py
@@ -88,6 +88,10 @@ class Manifest(object):
88 self._Load() 88 self._Load()
89 return self._default 89 return self._default
90 90
91 @property
92 def IsMirror(self):
93 return self.manifestProject.config.GetBoolean('repo.mirror')
94
91 def _Unload(self): 95 def _Unload(self):
92 self._loaded = False 96 self._loaded = False
93 self._projects = {} 97 self._projects = {}
@@ -114,6 +118,10 @@ class Manifest(object):
114 finally: 118 finally:
115 self.manifestFile = real 119 self.manifestFile = real
116 120
121 if self.IsMirror:
122 self._AddMetaProjectMirror(self.repoProject)
123 self._AddMetaProjectMirror(self.manifestProject)
124
117 self._loaded = True 125 self._loaded = True
118 126
119 def _ParseManifest(self, is_root_file): 127 def _ParseManifest(self, is_root_file):
@@ -157,6 +165,40 @@ class Manifest(object):
157 (project.name, self.manifestFile) 165 (project.name, self.manifestFile)
158 self._projects[project.name] = project 166 self._projects[project.name] = project
159 167
168 def _AddMetaProjectMirror(self, m):
169 name = None
170 m_url = m.GetRemote(m.remote.name).url
171 if m_url.endswith('/.git'):
172 raise ManifestParseError, 'refusing to mirror %s' % m_url
173
174 if self._default and self._default.remote:
175 url = self._default.remote.fetchUrl
176 if not url.endswith('/'):
177 url += '/'
178 if m_url.startswith(url):
179 remote = self._default.remote
180 name = m_url[len(url):]
181
182 if name is None:
183 s = m_url.rindex('/') + 1
184 remote = Remote('origin', fetch = m_url[:s])
185 name = m_url[s:]
186
187 if name.endswith('.git'):
188 name = name[:-4]
189
190 if name not in self._projects:
191 m.PreSync()
192 gitdir = os.path.join(self.topdir, '%s.git' % name)
193 project = Project(manifest = self,
194 name = name,
195 remote = remote,
196 gitdir = gitdir,
197 worktree = None,
198 relpath = None,
199 revision = m.revision)
200 self._projects[project.name] = project
201
160 def _ParseRemote(self, node): 202 def _ParseRemote(self, node):
161 """ 203 """
162 reads a <remote> element from the manifest file 204 reads a <remote> element from the manifest file
@@ -214,8 +256,13 @@ class Manifest(object):
214 "project %s path cannot be absolute in %s" % \ 256 "project %s path cannot be absolute in %s" % \
215 (name, self.manifestFile) 257 (name, self.manifestFile)
216 258
217 worktree = os.path.join(self.topdir, path) 259 if self.IsMirror:
218 gitdir = os.path.join(self.repodir, 'projects/%s.git' % path) 260 relpath = None
261 worktree = None
262 gitdir = os.path.join(self.topdir, '%s.git' % name)
263 else:
264 worktree = os.path.join(self.topdir, path)
265 gitdir = os.path.join(self.repodir, 'projects/%s.git' % path)
219 266
220 project = Project(manifest = self, 267 project = Project(manifest = self,
221 name = name, 268 name = name,
@@ -242,8 +289,10 @@ class Manifest(object):
242 def _ParseCopyFile(self, project, node): 289 def _ParseCopyFile(self, project, node):
243 src = self._reqatt(node, 'src') 290 src = self._reqatt(node, 'src')
244 dest = self._reqatt(node, 'dest') 291 dest = self._reqatt(node, 'dest')
245 # src is project relative, and dest is relative to the top of the tree 292 if not self.IsMirror:
246 project.AddCopyFile(src, os.path.join(self.topdir, dest)) 293 # src is project relative;
294 # dest is relative to the top of the tree
295 project.AddCopyFile(src, os.path.join(self.topdir, dest))
247 296
248 def _get_remote(self, node): 297 def _get_remote(self, node):
249 name = node.getAttribute('remote') 298 name = node.getAttribute('remote')
diff --git a/project.py b/project.py
index 0637f4bf..1cfaaae5 100644
--- a/project.py
+++ b/project.py
@@ -211,7 +211,10 @@ class Project(object):
211 gitdir = self.gitdir, 211 gitdir = self.gitdir,
212 defaults = self.manifest.globalConfig) 212 defaults = self.manifest.globalConfig)
213 213
214 self.work_git = self._GitGetByExec(self, bare=False) 214 if self.worktree:
215 self.work_git = self._GitGetByExec(self, bare=False)
216 else:
217 self.work_git = None
215 self.bare_git = self._GitGetByExec(self, bare=True) 218 self.bare_git = self._GitGetByExec(self, bare=True)
216 219
217 @property 220 @property
@@ -489,14 +492,23 @@ class Project(object):
489 print >>sys.stderr 492 print >>sys.stderr
490 print >>sys.stderr, 'Initializing project %s ...' % self.name 493 print >>sys.stderr, 'Initializing project %s ...' % self.name
491 self._InitGitDir() 494 self._InitGitDir()
495
492 self._InitRemote() 496 self._InitRemote()
493 for r in self.extraRemotes.values(): 497 for r in self.extraRemotes.values():
494 if not self._RemoteFetch(r.name): 498 if not self._RemoteFetch(r.name):
495 return False 499 return False
496 if not self._RemoteFetch(): 500 if not self._RemoteFetch():
497 return False 501 return False
498 self._RepairAndroidImportErrors() 502
499 self._InitMRef() 503 if self.worktree:
504 self._RepairAndroidImportErrors()
505 self._InitMRef()
506 else:
507 self._InitMirrorHead()
508 try:
509 os.remove(os.path.join(self.gitdir, 'FETCH_HEAD'))
510 except OSError:
511 pass
500 return True 512 return True
501 513
502 def PostRepoUpgrade(self): 514 def PostRepoUpgrade(self):
@@ -792,9 +804,11 @@ class Project(object):
792 def _RemoteFetch(self, name=None): 804 def _RemoteFetch(self, name=None):
793 if not name: 805 if not name:
794 name = self.remote.name 806 name = self.remote.name
795 return GitCommand(self, 807 cmd = ['fetch']
796 ['fetch', name], 808 if not self.worktree:
797 bare = True).Wait() == 0 809 cmd.append('--update-head-ok')
810 cmd.append(name)
811 return GitCommand(self, cmd, bare = True).Wait() == 0
798 812
799 def _Checkout(self, rev, quiet=False): 813 def _Checkout(self, rev, quiet=False):
800 cmd = ['checkout'] 814 cmd = ['checkout']
@@ -874,7 +888,10 @@ class Project(object):
874 remote.url = url 888 remote.url = url
875 remote.review = self.remote.reviewUrl 889 remote.review = self.remote.reviewUrl
876 890
877 remote.ResetFetch() 891 if self.worktree:
892 remote.ResetFetch(mirror=False)
893 else:
894 remote.ResetFetch(mirror=True)
878 remote.Save() 895 remote.Save()
879 896
880 for r in self.extraRemotes.values(): 897 for r in self.extraRemotes.values():
@@ -897,6 +914,11 @@ class Project(object):
897 dst = remote.ToLocal(self.revision) 914 dst = remote.ToLocal(self.revision)
898 self.bare_git.symbolic_ref('-m', msg, ref, dst) 915 self.bare_git.symbolic_ref('-m', msg, ref, dst)
899 916
917 def _InitMirrorHead(self):
918 dst = self.GetRemote(self.remote.name).ToLocal(self.revision)
919 msg = 'manifest set to %s' % self.revision
920 self.bare_git.SetHead(dst, message=msg)
921
900 def _InitWorkTree(self): 922 def _InitWorkTree(self):
901 dotgit = os.path.join(self.worktree, '.git') 923 dotgit = os.path.join(self.worktree, '.git')
902 if not os.path.exists(dotgit): 924 if not os.path.exists(dotgit):
diff --git a/repo b/repo
index 9f107a93..bfa4ca3c 100755
--- a/repo
+++ b/repo
@@ -28,7 +28,7 @@ if __name__ == '__main__':
28del magic 28del magic
29 29
30# increment this whenever we make important changes to this script 30# increment this whenever we make important changes to this script
31VERSION = (1, 6) 31VERSION = (1, 7)
32 32
33# increment this if the MAINTAINER_KEYS block is modified 33# increment this if the MAINTAINER_KEYS block is modified
34KEYRING_VERSION = (1,0) 34KEYRING_VERSION = (1,0)
@@ -115,6 +115,9 @@ group.add_option('-b', '--manifest-branch',
115group.add_option('-m', '--manifest-name', 115group.add_option('-m', '--manifest-name',
116 dest='manifest_name', 116 dest='manifest_name',
117 help='initial manifest file', metavar='NAME.xml') 117 help='initial manifest file', metavar='NAME.xml')
118group.add_option('--mirror',
119 dest='mirror', action='store_true',
120 help='mirror the forrest')
118 121
119# Tool 122# Tool
120group = init_optparse.add_option_group('Version options') 123group = init_optparse.add_option_group('Version options')
diff --git a/subcmds/init.py b/subcmds/init.py
index 03f358d1..ad28a611 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -57,6 +57,10 @@ default.xml will be used.
57 g.add_option('-m', '--manifest-name', 57 g.add_option('-m', '--manifest-name',
58 dest='manifest_name', default='default.xml', 58 dest='manifest_name', default='default.xml',
59 help='initial manifest file', metavar='NAME.xml') 59 help='initial manifest file', metavar='NAME.xml')
60 g.add_option('--mirror',
61 dest='mirror', action='store_true',
62 help='mirror the forrest')
63
60 64
61 # Tool 65 # Tool
62 g = p.add_option_group('Version options') 66 g = p.add_option_group('Version options')
@@ -112,6 +116,9 @@ default.xml will be used.
112 r.ResetFetch() 116 r.ResetFetch()
113 r.Save() 117 r.Save()
114 118
119 if opt.mirror:
120 m.config.SetString('repo.mirror', 'true')
121
115 m.Sync_NetworkHalf() 122 m.Sync_NetworkHalf()
116 m.Sync_LocalHalf() 123 m.Sync_LocalHalf()
117 m.StartBranch('default') 124 m.StartBranch('default')
@@ -185,9 +192,14 @@ default.xml will be used.
185 self._SyncManifest(opt) 192 self._SyncManifest(opt)
186 self._LinkManifest(opt.manifest_name) 193 self._LinkManifest(opt.manifest_name)
187 194
188 if os.isatty(0) and os.isatty(1): 195 if os.isatty(0) and os.isatty(1) and not opt.mirror:
189 self._ConfigureUser() 196 self._ConfigureUser()
190 self._ConfigureColor() 197 self._ConfigureColor()
191 198
199 if opt.mirror:
200 type = 'mirror '
201 else:
202 type = ''
203
192 print '' 204 print ''
193 print 'repo initialized in %s' % self.manifest.topdir 205 print 'repo %sinitialized in %s' % (type, self.manifest.topdir)
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 9af12322..8050e515 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -102,8 +102,9 @@ the manifest.
102 self._Fetch(*missing) 102 self._Fetch(*missing)
103 103
104 for project in all: 104 for project in all:
105 if not project.Sync_LocalHalf(): 105 if project.worktree:
106 sys.exit(1) 106 if not project.Sync_LocalHalf():
107 sys.exit(1)
107 108
108 109
109def _VerifyTag(project): 110def _VerifyTag(project):