Revert "Implementation of manifest defined githooks"

This reverts commit 38e4387f8eb8cffd6359d726c38a7c524fef07e3.

A "repo init" followed by "repo sync" is meant to be as safe as
"git clone".  In particular it should not run arbitrary code provided
by the manifest owner.

It would still be nice to have support for manifest-defined git hooks
--- they'd just need a prompt like the upload RepoHook has.  Hopefully
a later change can bring them back.

Change-Id: I5ecd90fb5c2ed64f103d856d1ffcba38a47b062d
Signed-off-by: Jonathan Nieder <jrn@google.com>
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt
index 4b979c7..1aa9396 100644
--- a/docs/manifest-format.txt
+++ b/docs/manifest-format.txt
@@ -31,7 +31,7 @@
 
     <!ELEMENT notice (#PCDATA)>
 
-    <!ELEMENT remote (projecthook?)>
+    <!ELEMENT remote (EMPTY)>
     <!ATTLIST remote name         ID    #REQUIRED>
     <!ATTLIST remote alias        CDATA #IMPLIED>
     <!ATTLIST remote fetch        CDATA #REQUIRED>
@@ -73,10 +73,6 @@
     <!ATTLIST extend-project path CDATA #IMPLIED>
     <!ATTLIST extend-project groups CDATA #IMPLIED>
 
-    <!ELEMENT projecthook (EMPTY)>
-    <!ATTLIST projecthook name CDATA #REQUIRED>
-    <!ATTLIST projecthook revision CDATA #REQUIRED>
-
     <!ELEMENT remove-project (EMPTY)>
     <!ATTLIST remove-project name  CDATA #REQUIRED>
 
@@ -310,15 +306,6 @@
 Attribute `name`: the manifest to include, specified relative to
 the manifest repository's root.
 
-Element projecthook
--------------------
-
-This element is used to define a per-remote hook git that is
-fetched and applied to all projects using the remote. The project-
-hook functionality allows for company/team .git/hooks to be used.
-The hooks in the supplied project and revision are supplemented to
-the current repo stock hooks for each project. Supplemented hooks
-overrule any stock hooks.
 
 Local Manifests
 ===============
diff --git a/manifest_xml.py b/manifest_xml.py
index 9472a08..890c954 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -64,9 +64,7 @@
                fetch=None,
                manifestUrl=None,
                review=None,
-               revision=None,
-               projecthookName=None,
-               projecthookRevision=None):
+               revision=None):
     self.name = name
     self.fetchUrl = fetch
     self.manifestUrl = manifestUrl
@@ -74,8 +72,6 @@
     self.reviewUrl = review
     self.revision = revision
     self.resolvedFetchUrl = self._resolveFetchUrl()
-    self.projecthookName = projecthookName
-    self.projecthookRevision = projecthookRevision
 
   def __eq__(self, other):
     return self.__dict__ == other.__dict__
@@ -171,11 +167,6 @@
       e.setAttribute('review', r.reviewUrl)
     if r.revision is not None:
       e.setAttribute('revision', r.revision)
-    if r.projecthookName is not None:
-      ph = doc.createElement('projecthook')
-      ph.setAttribute('name', r.projecthookName)
-      ph.setAttribute('revision', r.projecthookRevision)
-      e.appendChild(ph)
 
   def _ParseGroups(self, groups):
     return [x for x in re.split(r'[,\s]+', groups) if x]
@@ -638,13 +629,7 @@
     if revision == '':
       revision = None
     manifestUrl = self.manifestProject.config.GetString('remote.origin.url')
-    projecthookName = None
-    projecthookRevision = None
-    for n in node.childNodes:
-      if n.nodeName == 'projecthook':
-        projecthookName, projecthookRevision = self._ParseProjectHooks(n)
-        break
-    return _XmlRemote(name, alias, fetch, manifestUrl, review, revision, projecthookName, projecthookRevision)
+    return _XmlRemote(name, alias, fetch, manifestUrl, review, revision)
 
   def _ParseDefault(self, node):
     """
@@ -948,8 +933,3 @@
       diff['added'].append(toProjects[proj])
 
     return diff
-
-  def _ParseProjectHooks(self, node):
-    name = self._reqatt(node, 'name')
-    revision = self._reqatt(node, 'revision')
-    return name, revision
diff --git a/project.py b/project.py
index c6a91d0..028deb5 100644
--- a/project.py
+++ b/project.py
@@ -69,6 +69,27 @@
 def sq(r):
   return "'" + r.replace("'", "'\''") + "'"
 
+_project_hook_list = None
+def _ProjectHooks():
+  """List the hooks present in the 'hooks' directory.
+
+  These hooks are project hooks and are copied to the '.git/hooks' directory
+  of all subprojects.
+
+  This function caches the list of hooks (based on the contents of the
+  'repo/hooks' directory) on the first call.
+
+  Returns:
+    A list of absolute paths to all of the files in the hooks directory.
+  """
+  global _project_hook_list
+  if _project_hook_list is None:
+    d = os.path.realpath(os.path.abspath(os.path.dirname(__file__)))
+    d = os.path.join(d, 'hooks')
+    _project_hook_list = [os.path.join(d, x) for x in os.listdir(d)]
+  return _project_hook_list
+
+
 class DownloadedChange(object):
   _commit_cache = None
 
@@ -2085,7 +2106,7 @@
     if GitCommand(self, cmd).Wait() != 0:
       raise GitError('%s merge %s ' % (self.name, head))
 
-  def _InitGitDir(self, mirror_git=None, MirrorOverride=False):
+  def _InitGitDir(self, mirror_git=None):
     if not os.path.exists(self.gitdir):
 
       # Initialize the bare repository, which contains all of the objects.
@@ -2127,38 +2148,11 @@
       for key in ['user.name', 'user.email']:
         if m.Has(key, include_defaults=False):
           self.config.SetString(key, m.GetString(key))
-      if self.manifest.IsMirror and not MirrorOverride:
+      if self.manifest.IsMirror:
         self.config.SetString('core.bare', 'true')
       else:
         self.config.SetString('core.bare', None)
 
-  def _ProjectHooks(self, remote, repodir):
-    """List the hooks present in the 'hooks' directory.
-
-    These hooks are project hooks and are copied to the '.git/hooks' directory
-    of all subprojects.
-
-    The remote projecthooks supplement/overrule any stockhook making it possible to
-    have a combination of hooks both from the remote projecthook and
-    .repo/hooks directories.
-
-    Returns:
-      A list of absolute paths to all of the files in the hooks directory and
-      projecthooks files, excluding the .git folder.
-    """
-    hooks = {}
-    d = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'hooks')
-    hooks = dict([(x, os.path.join(d, x)) for x in os.listdir(d)])
-    if remote is not None:
-      if remote.projecthookName is not None:
-        d = os.path.abspath('%s/projecthooks/%s/%s' % (repodir, remote.name, remote.projecthookName))
-        if os.path.isdir(d):
-          hooks.update(dict([(x, os.path.join(d, x)) for x in os.listdir(d)]))
-
-    if hooks.has_key('.git'):
-      del hooks['.git']
-    return hooks.values()
-
   def _UpdateHooks(self):
     if os.path.exists(self.gitdir):
       self._InitHooks()
@@ -2167,10 +2161,7 @@
     hooks = os.path.realpath(self._gitdir_path('hooks'))
     if not os.path.exists(hooks):
       os.makedirs(hooks)
-    pr = None
-    if self is not self.manifest.manifestProject:
-      pr = self.manifest.remotes.get(self.remote.name)
-    for stock_hook in self._ProjectHooks(pr, self.manifest.repodir):
+    for stock_hook in _ProjectHooks():
       name = os.path.basename(stock_hook)
 
       if name in ('commit-msg',) and not self.remote.review \
diff --git a/subcmds/init.py b/subcmds/init.py
index c5bf282..b73de71 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -32,7 +32,7 @@
 from color import Coloring
 from command import InteractiveCommand, MirrorSafeCommand
 from error import ManifestParseError
-from project import SyncBuffer, MetaProject
+from project import SyncBuffer
 from git_config import GitConfig
 from git_command import git_require, MIN_GIT_VERSION
 
@@ -374,52 +374,6 @@
       print('   rm -r %s/.repo' % self.manifest.topdir)
       print('and try again.')
 
-  def _SyncProjectHooks(self, opt, repodir):
-    """Downloads the defined hooks supplied in the projecthooks element
-
-    """
-    # Always delete projecthooks and re-download for every new init.
-    projecthooksdir = os.path.join(repodir, 'projecthooks')
-    if os.path.exists(projecthooksdir):
-      shutil.rmtree(projecthooksdir)
-    for remotename in self.manifest.remotes:
-      r = self.manifest.remotes.get(remotename)
-      if r.projecthookName is not None and r.projecthookRevision is not None:
-        projecthookurl = r.resolvedFetchUrl.rstrip('/') + '/' + r.projecthookName
-
-        ph = MetaProject(manifest = self.manifest,
-        name = r.projecthookName,
-        gitdir   = os.path.join(projecthooksdir,'%s/%s.git' % (remotename, r.projecthookName)),
-        worktree = os.path.join(projecthooksdir,'%s/%s' % (remotename, r.projecthookName)))
-
-        ph.revisionExpr = r.projecthookRevision
-        is_new = not ph.Exists
-
-        if is_new:
-          if not opt.quiet:
-            print('Get projecthook %s' % \
-              GitConfig.ForUser().UrlInsteadOf(projecthookurl), file=sys.stderr)
-          ph._InitGitDir(MirrorOverride=True)
-
-        phr = ph.GetRemote(remotename)
-        phr.name = 'origin'
-        phr.url = projecthookurl
-        phr.ResetFetch()
-        phr.Save()
-
-        if not ph.Sync_NetworkHalf(quiet=opt.quiet, is_new=is_new, clone_bundle=False):
-          print('fatal: cannot obtain projecthook %s' % phr.url, file=sys.stderr)
-
-          # Better delete the git dir if we created it; otherwise next
-          # time (when user fixes problems) we won't go through the "is_new" logic.
-          if is_new:
-            shutil.rmtree(ph.gitdir)
-          sys.exit(1)
-
-        syncbuf = SyncBuffer(ph.config)
-        ph.Sync_LocalHalf(syncbuf)
-        syncbuf.Finish()
-
   def Execute(self, opt, args):
     git_require(MIN_GIT_VERSION, fail=True)
 
@@ -435,7 +389,6 @@
 
     self._SyncManifest(opt)
     self._LinkManifest(opt.manifest_name)
-    self._SyncProjectHooks(opt, self.manifest.repodir)
 
     if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror:
       if opt.config_name or self._ShouldConfigureUser():