summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/manifest-format.txt15
-rw-r--r--manifest_xml.py24
-rw-r--r--project.py57
-rw-r--r--subcmds/init.py49
4 files changed, 28 insertions, 117 deletions
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt
index 4b979c79..1aa93965 100644
--- a/docs/manifest-format.txt
+++ b/docs/manifest-format.txt
@@ -31,7 +31,7 @@ following DTD:
31 31
32 <!ELEMENT notice (#PCDATA)> 32 <!ELEMENT notice (#PCDATA)>
33 33
34 <!ELEMENT remote (projecthook?)> 34 <!ELEMENT remote (EMPTY)>
35 <!ATTLIST remote name ID #REQUIRED> 35 <!ATTLIST remote name ID #REQUIRED>
36 <!ATTLIST remote alias CDATA #IMPLIED> 36 <!ATTLIST remote alias CDATA #IMPLIED>
37 <!ATTLIST remote fetch CDATA #REQUIRED> 37 <!ATTLIST remote fetch CDATA #REQUIRED>
@@ -73,10 +73,6 @@ following DTD:
73 <!ATTLIST extend-project path CDATA #IMPLIED> 73 <!ATTLIST extend-project path CDATA #IMPLIED>
74 <!ATTLIST extend-project groups CDATA #IMPLIED> 74 <!ATTLIST extend-project groups CDATA #IMPLIED>
75 75
76 <!ELEMENT projecthook (EMPTY)>
77 <!ATTLIST projecthook name CDATA #REQUIRED>
78 <!ATTLIST projecthook revision CDATA #REQUIRED>
79
80 <!ELEMENT remove-project (EMPTY)> 76 <!ELEMENT remove-project (EMPTY)>
81 <!ATTLIST remove-project name CDATA #REQUIRED> 77 <!ATTLIST remove-project name CDATA #REQUIRED>
82 78
@@ -310,15 +306,6 @@ target manifest to include - it must be a usable manifest on its own.
310Attribute `name`: the manifest to include, specified relative to 306Attribute `name`: the manifest to include, specified relative to
311the manifest repository's root. 307the manifest repository's root.
312 308
313Element projecthook
314-------------------
315
316This element is used to define a per-remote hook git that is
317fetched and applied to all projects using the remote. The project-
318hook functionality allows for company/team .git/hooks to be used.
319The hooks in the supplied project and revision are supplemented to
320the current repo stock hooks for each project. Supplemented hooks
321overrule any stock hooks.
322 309
323Local Manifests 310Local Manifests
324=============== 311===============
diff --git a/manifest_xml.py b/manifest_xml.py
index 9472a08f..890c954d 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -64,9 +64,7 @@ class _XmlRemote(object):
64 fetch=None, 64 fetch=None,
65 manifestUrl=None, 65 manifestUrl=None,
66 review=None, 66 review=None,
67 revision=None, 67 revision=None):
68 projecthookName=None,
69 projecthookRevision=None):
70 self.name = name 68 self.name = name
71 self.fetchUrl = fetch 69 self.fetchUrl = fetch
72 self.manifestUrl = manifestUrl 70 self.manifestUrl = manifestUrl
@@ -74,8 +72,6 @@ class _XmlRemote(object):
74 self.reviewUrl = review 72 self.reviewUrl = review
75 self.revision = revision 73 self.revision = revision
76 self.resolvedFetchUrl = self._resolveFetchUrl() 74 self.resolvedFetchUrl = self._resolveFetchUrl()
77 self.projecthookName = projecthookName
78 self.projecthookRevision = projecthookRevision
79 75
80 def __eq__(self, other): 76 def __eq__(self, other):
81 return self.__dict__ == other.__dict__ 77 return self.__dict__ == other.__dict__
@@ -171,11 +167,6 @@ class XmlManifest(object):
171 e.setAttribute('review', r.reviewUrl) 167 e.setAttribute('review', r.reviewUrl)
172 if r.revision is not None: 168 if r.revision is not None:
173 e.setAttribute('revision', r.revision) 169 e.setAttribute('revision', r.revision)
174 if r.projecthookName is not None:
175 ph = doc.createElement('projecthook')
176 ph.setAttribute('name', r.projecthookName)
177 ph.setAttribute('revision', r.projecthookRevision)
178 e.appendChild(ph)
179 170
180 def _ParseGroups(self, groups): 171 def _ParseGroups(self, groups):
181 return [x for x in re.split(r'[,\s]+', groups) if x] 172 return [x for x in re.split(r'[,\s]+', groups) if x]
@@ -638,13 +629,7 @@ class XmlManifest(object):
638 if revision == '': 629 if revision == '':
639 revision = None 630 revision = None
640 manifestUrl = self.manifestProject.config.GetString('remote.origin.url') 631 manifestUrl = self.manifestProject.config.GetString('remote.origin.url')
641 projecthookName = None 632 return _XmlRemote(name, alias, fetch, manifestUrl, review, revision)
642 projecthookRevision = None
643 for n in node.childNodes:
644 if n.nodeName == 'projecthook':
645 projecthookName, projecthookRevision = self._ParseProjectHooks(n)
646 break
647 return _XmlRemote(name, alias, fetch, manifestUrl, review, revision, projecthookName, projecthookRevision)
648 633
649 def _ParseDefault(self, node): 634 def _ParseDefault(self, node):
650 """ 635 """
@@ -948,8 +933,3 @@ class XmlManifest(object):
948 diff['added'].append(toProjects[proj]) 933 diff['added'].append(toProjects[proj])
949 934
950 return diff 935 return diff
951
952 def _ParseProjectHooks(self, node):
953 name = self._reqatt(node, 'name')
954 revision = self._reqatt(node, 'revision')
955 return name, revision
diff --git a/project.py b/project.py
index c6a91d05..028deb5f 100644
--- a/project.py
+++ b/project.py
@@ -69,6 +69,27 @@ def not_rev(r):
69def sq(r): 69def sq(r):
70 return "'" + r.replace("'", "'\''") + "'" 70 return "'" + r.replace("'", "'\''") + "'"
71 71
72_project_hook_list = None
73def _ProjectHooks():
74 """List the hooks present in the 'hooks' directory.
75
76 These hooks are project hooks and are copied to the '.git/hooks' directory
77 of all subprojects.
78
79 This function caches the list of hooks (based on the contents of the
80 'repo/hooks' directory) on the first call.
81
82 Returns:
83 A list of absolute paths to all of the files in the hooks directory.
84 """
85 global _project_hook_list
86 if _project_hook_list is None:
87 d = os.path.realpath(os.path.abspath(os.path.dirname(__file__)))
88 d = os.path.join(d, 'hooks')
89 _project_hook_list = [os.path.join(d, x) for x in os.listdir(d)]
90 return _project_hook_list
91
92
72class DownloadedChange(object): 93class DownloadedChange(object):
73 _commit_cache = None 94 _commit_cache = None
74 95
@@ -2085,7 +2106,7 @@ class Project(object):
2085 if GitCommand(self, cmd).Wait() != 0: 2106 if GitCommand(self, cmd).Wait() != 0:
2086 raise GitError('%s merge %s ' % (self.name, head)) 2107 raise GitError('%s merge %s ' % (self.name, head))
2087 2108
2088 def _InitGitDir(self, mirror_git=None, MirrorOverride=False): 2109 def _InitGitDir(self, mirror_git=None):
2089 if not os.path.exists(self.gitdir): 2110 if not os.path.exists(self.gitdir):
2090 2111
2091 # Initialize the bare repository, which contains all of the objects. 2112 # Initialize the bare repository, which contains all of the objects.
@@ -2127,38 +2148,11 @@ class Project(object):
2127 for key in ['user.name', 'user.email']: 2148 for key in ['user.name', 'user.email']:
2128 if m.Has(key, include_defaults=False): 2149 if m.Has(key, include_defaults=False):
2129 self.config.SetString(key, m.GetString(key)) 2150 self.config.SetString(key, m.GetString(key))
2130 if self.manifest.IsMirror and not MirrorOverride: 2151 if self.manifest.IsMirror:
2131 self.config.SetString('core.bare', 'true') 2152 self.config.SetString('core.bare', 'true')
2132 else: 2153 else:
2133 self.config.SetString('core.bare', None) 2154 self.config.SetString('core.bare', None)
2134 2155
2135 def _ProjectHooks(self, remote, repodir):
2136 """List the hooks present in the 'hooks' directory.
2137
2138 These hooks are project hooks and are copied to the '.git/hooks' directory
2139 of all subprojects.
2140
2141 The remote projecthooks supplement/overrule any stockhook making it possible to
2142 have a combination of hooks both from the remote projecthook and
2143 .repo/hooks directories.
2144
2145 Returns:
2146 A list of absolute paths to all of the files in the hooks directory and
2147 projecthooks files, excluding the .git folder.
2148 """
2149 hooks = {}
2150 d = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'hooks')
2151 hooks = dict([(x, os.path.join(d, x)) for x in os.listdir(d)])
2152 if remote is not None:
2153 if remote.projecthookName is not None:
2154 d = os.path.abspath('%s/projecthooks/%s/%s' % (repodir, remote.name, remote.projecthookName))
2155 if os.path.isdir(d):
2156 hooks.update(dict([(x, os.path.join(d, x)) for x in os.listdir(d)]))
2157
2158 if hooks.has_key('.git'):
2159 del hooks['.git']
2160 return hooks.values()
2161
2162 def _UpdateHooks(self): 2156 def _UpdateHooks(self):
2163 if os.path.exists(self.gitdir): 2157 if os.path.exists(self.gitdir):
2164 self._InitHooks() 2158 self._InitHooks()
@@ -2167,10 +2161,7 @@ class Project(object):
2167 hooks = os.path.realpath(self._gitdir_path('hooks')) 2161 hooks = os.path.realpath(self._gitdir_path('hooks'))
2168 if not os.path.exists(hooks): 2162 if not os.path.exists(hooks):
2169 os.makedirs(hooks) 2163 os.makedirs(hooks)
2170 pr = None 2164 for stock_hook in _ProjectHooks():
2171 if self is not self.manifest.manifestProject:
2172 pr = self.manifest.remotes.get(self.remote.name)
2173 for stock_hook in self._ProjectHooks(pr, self.manifest.repodir):
2174 name = os.path.basename(stock_hook) 2165 name = os.path.basename(stock_hook)
2175 2166
2176 if name in ('commit-msg',) and not self.remote.review \ 2167 if name in ('commit-msg',) and not self.remote.review \
diff --git a/subcmds/init.py b/subcmds/init.py
index c5bf2823..b73de71c 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -32,7 +32,7 @@ else:
32from color import Coloring 32from color import Coloring
33from command import InteractiveCommand, MirrorSafeCommand 33from command import InteractiveCommand, MirrorSafeCommand
34from error import ManifestParseError 34from error import ManifestParseError
35from project import SyncBuffer, MetaProject 35from project import SyncBuffer
36from git_config import GitConfig 36from git_config import GitConfig
37from git_command import git_require, MIN_GIT_VERSION 37from git_command import git_require, MIN_GIT_VERSION
38 38
@@ -374,52 +374,6 @@ to update the working directory files.
374 print(' rm -r %s/.repo' % self.manifest.topdir) 374 print(' rm -r %s/.repo' % self.manifest.topdir)
375 print('and try again.') 375 print('and try again.')
376 376
377 def _SyncProjectHooks(self, opt, repodir):
378 """Downloads the defined hooks supplied in the projecthooks element
379
380 """
381 # Always delete projecthooks and re-download for every new init.
382 projecthooksdir = os.path.join(repodir, 'projecthooks')
383 if os.path.exists(projecthooksdir):
384 shutil.rmtree(projecthooksdir)
385 for remotename in self.manifest.remotes:
386 r = self.manifest.remotes.get(remotename)
387 if r.projecthookName is not None and r.projecthookRevision is not None:
388 projecthookurl = r.resolvedFetchUrl.rstrip('/') + '/' + r.projecthookName
389
390 ph = MetaProject(manifest = self.manifest,
391 name = r.projecthookName,
392 gitdir = os.path.join(projecthooksdir,'%s/%s.git' % (remotename, r.projecthookName)),
393 worktree = os.path.join(projecthooksdir,'%s/%s' % (remotename, r.projecthookName)))
394
395 ph.revisionExpr = r.projecthookRevision
396 is_new = not ph.Exists
397
398 if is_new:
399 if not opt.quiet:
400 print('Get projecthook %s' % \
401 GitConfig.ForUser().UrlInsteadOf(projecthookurl), file=sys.stderr)
402 ph._InitGitDir(MirrorOverride=True)
403
404 phr = ph.GetRemote(remotename)
405 phr.name = 'origin'
406 phr.url = projecthookurl
407 phr.ResetFetch()
408 phr.Save()
409
410 if not ph.Sync_NetworkHalf(quiet=opt.quiet, is_new=is_new, clone_bundle=False):
411 print('fatal: cannot obtain projecthook %s' % phr.url, file=sys.stderr)
412
413 # Better delete the git dir if we created it; otherwise next
414 # time (when user fixes problems) we won't go through the "is_new" logic.
415 if is_new:
416 shutil.rmtree(ph.gitdir)
417 sys.exit(1)
418
419 syncbuf = SyncBuffer(ph.config)
420 ph.Sync_LocalHalf(syncbuf)
421 syncbuf.Finish()
422
423 def Execute(self, opt, args): 377 def Execute(self, opt, args):
424 git_require(MIN_GIT_VERSION, fail=True) 378 git_require(MIN_GIT_VERSION, fail=True)
425 379
@@ -435,7 +389,6 @@ to update the working directory files.
435 389
436 self._SyncManifest(opt) 390 self._SyncManifest(opt)
437 self._LinkManifest(opt.manifest_name) 391 self._LinkManifest(opt.manifest_name)
438 self._SyncProjectHooks(opt, self.manifest.repodir)
439 392
440 if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror: 393 if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror:
441 if opt.config_name or self._ShouldConfigureUser(): 394 if opt.config_name or self._ShouldConfigureUser():