diff options
| -rw-r--r-- | docs/manifest-format.txt | 15 | ||||
| -rw-r--r-- | manifest_xml.py | 24 | ||||
| -rw-r--r-- | project.py | 57 | ||||
| -rw-r--r-- | subcmds/init.py | 49 |
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. | |||
| 310 | Attribute `name`: the manifest to include, specified relative to | 306 | Attribute `name`: the manifest to include, specified relative to |
| 311 | the manifest repository's root. | 307 | the manifest repository's root. |
| 312 | 308 | ||
| 313 | Element projecthook | ||
| 314 | ------------------- | ||
| 315 | |||
| 316 | This element is used to define a per-remote hook git that is | ||
| 317 | fetched and applied to all projects using the remote. The project- | ||
| 318 | hook functionality allows for company/team .git/hooks to be used. | ||
| 319 | The hooks in the supplied project and revision are supplemented to | ||
| 320 | the current repo stock hooks for each project. Supplemented hooks | ||
| 321 | overrule any stock hooks. | ||
| 322 | 309 | ||
| 323 | Local Manifests | 310 | Local 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 | ||
| @@ -69,6 +69,27 @@ def not_rev(r): | |||
| 69 | def sq(r): | 69 | def sq(r): |
| 70 | return "'" + r.replace("'", "'\''") + "'" | 70 | return "'" + r.replace("'", "'\''") + "'" |
| 71 | 71 | ||
| 72 | _project_hook_list = None | ||
| 73 | def _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 | |||
| 72 | class DownloadedChange(object): | 93 | class 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: | |||
| 32 | from color import Coloring | 32 | from color import Coloring |
| 33 | from command import InteractiveCommand, MirrorSafeCommand | 33 | from command import InteractiveCommand, MirrorSafeCommand |
| 34 | from error import ManifestParseError | 34 | from error import ManifestParseError |
| 35 | from project import SyncBuffer, MetaProject | 35 | from project import SyncBuffer |
| 36 | from git_config import GitConfig | 36 | from git_config import GitConfig |
| 37 | from git_command import git_require, MIN_GIT_VERSION | 37 | from 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(): |
