Support Mercurial pretxnchangegroup hooks
Summary: Ref T4189. Fixes T2066. Mercurial has a //lot// of hooks so I'm not 100% sure this is all we need to install (we may need separate hooks for tags/bookmarks) but it should cover most of what we're after at least. Test Plan: - `bin/repository pull`'d a Mercurial repo and got a hook install. - Pushed to a Mercurial repository over SSH and HTTP, with good/bad hooks. Saw hooks fire. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T2066, T4189 Differential Revision: https://secure.phabricator.com/D7685
This commit is contained in:
		| @@ -29,11 +29,16 @@ $engine->setRepository($repository); | |||||||
|  |  | ||||||
| // Figure out which user is writing the commit. | // Figure out which user is writing the commit. | ||||||
|  |  | ||||||
| if ($repository->isGit()) { | if ($repository->isGit() || $repository->isHg()) { | ||||||
|   $username = getenv('PHABRICATOR_USER'); |   $username = getenv('PHABRICATOR_USER'); | ||||||
|   if (!strlen($username)) { |   if (!strlen($username)) { | ||||||
|     throw new Exception(pht('usage: PHABRICATOR_USER should be defined!')); |     throw new Exception(pht('usage: PHABRICATOR_USER should be defined!')); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // TODO: If this is a Mercurial repository, the hook we're responding to | ||||||
|  |   // is available in $argv[2]. It's unclear if we actually need this, or if | ||||||
|  |   // we can block all actions we care about with just pretxnchangegroup. | ||||||
|  |  | ||||||
| } else if ($repository->isSVN()) { | } else if ($repository->isSVN()) { | ||||||
|   // NOTE: In Subversion, the entire environment gets wiped so we can't read |   // NOTE: In Subversion, the entire environment gets wiped so we can't read | ||||||
|   // PHABRICATOR_USER. Instead, we've set "--tunnel-user" to specify the |   // PHABRICATOR_USER. Instead, we've set "--tunnel-user" to specify the | ||||||
| @@ -50,7 +55,7 @@ if ($repository->isGit()) { | |||||||
|  |  | ||||||
|   $engine->setSubversionTransactionInfo($svn_txn, $svn_repo); |   $engine->setSubversionTransactionInfo($svn_txn, $svn_repo); | ||||||
| } else { | } else { | ||||||
|   throw new Exceptiont(pht('Unknown repository type.')); |   throw new Exception(pht('Unknown repository type.')); | ||||||
| } | } | ||||||
|  |  | ||||||
| $user = id(new PhabricatorPeopleQuery()) | $user = id(new PhabricatorPeopleQuery()) | ||||||
| @@ -67,9 +72,16 @@ $engine->setViewer($user); | |||||||
|  |  | ||||||
| // Read stdin for the hook engine. | // Read stdin for the hook engine. | ||||||
|  |  | ||||||
| $stdin = @file_get_contents('php://stdin'); | if ($repository->isHg()) { | ||||||
| if ($stdin === false) { |   // Mercurial leaves stdin open, so we can't just read it until EOF. | ||||||
|   throw new Exception(pht('Failed to read stdin!')); |   $stdin = ''; | ||||||
|  | } else { | ||||||
|  |   // Git and Subversion write data into stdin and then close it. Read the | ||||||
|  |   // data. | ||||||
|  |   $stdin = @file_get_contents('php://stdin'); | ||||||
|  |   if ($stdin === false) { | ||||||
|  |     throw new Exception(pht('Failed to read stdin!')); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| $engine->setStdin($stdin); | $engine->setStdin($stdin); | ||||||
|   | |||||||
| @@ -406,7 +406,9 @@ final class DiffusionServeController extends DiffusionController { | |||||||
|     return $user; |     return $user; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private function serveMercurialRequest(PhabricatorRepository $repository) { |   private function serveMercurialRequest( | ||||||
|  |     PhabricatorRepository $repository, | ||||||
|  |     PhabricatorUser $viewer) { | ||||||
|     $request = $this->getRequest(); |     $request = $this->getRequest(); | ||||||
|  |  | ||||||
|     $bin = Filesystem::resolveBinary('hg'); |     $bin = Filesystem::resolveBinary('hg'); | ||||||
| @@ -414,7 +416,9 @@ final class DiffusionServeController extends DiffusionController { | |||||||
|       throw new Exception("Unable to find `hg` in PATH!"); |       throw new Exception("Unable to find `hg` in PATH!"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     $env = array(); |     $env = array( | ||||||
|  |       'PHABRICATOR_USER' => $viewer->getUsername(), | ||||||
|  |     ); | ||||||
|     $input = PhabricatorStartup::getRawInput(); |     $input = PhabricatorStartup::getRawInput(); | ||||||
|  |  | ||||||
|     $cmd = $request->getStr('cmd'); |     $cmd = $request->getStr('cmd'); | ||||||
|   | |||||||
| @@ -51,6 +51,9 @@ final class DiffusionCommitHookEngine extends Phobject { | |||||||
|       case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: |       case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: | ||||||
|         $err = $this->executeSubversionHook(); |         $err = $this->executeSubversionHook(); | ||||||
|         break; |         break; | ||||||
|  |       case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: | ||||||
|  |         $err = $this->executeMercurialHook(); | ||||||
|  |         break; | ||||||
|       default: |       default: | ||||||
|         throw new Exception(pht('Unsupported repository type "%s"!', $type)); |         throw new Exception(pht('Unsupported repository type "%s"!', $type)); | ||||||
|     } |     } | ||||||
| @@ -73,6 +76,13 @@ final class DiffusionCommitHookEngine extends Phobject { | |||||||
|     return 0; |     return 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private function executeMercurialHook() { | ||||||
|  |  | ||||||
|  |     // TODO: Here, too, useful things should be done. | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   private function parseGitUpdates($stdin) { |   private function parseGitUpdates($stdin) { | ||||||
|     $updates = array(); |     $updates = array(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -42,7 +42,8 @@ final class DiffusionSSHMercurialServeWorkflow | |||||||
|     $command = csprintf('hg -R %s serve --stdio', $repository->getLocalPath()); |     $command = csprintf('hg -R %s serve --stdio', $repository->getLocalPath()); | ||||||
|     $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); |     $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); | ||||||
|  |  | ||||||
|     $future = new ExecFuture('%C', $command); |     $future = id(new ExecFuture('%C', $command)) | ||||||
|  |       ->setEnv($this->getEnvironment()); | ||||||
|  |  | ||||||
|     $io_channel = $this->getIOChannel(); |     $io_channel = $this->getIOChannel(); | ||||||
|     $protocol_channel = new DiffusionSSHMercurialWireClientProtocolChannel( |     $protocol_channel = new DiffusionSSHMercurialWireClientProtocolChannel( | ||||||
|   | |||||||
| @@ -87,6 +87,8 @@ final class PhabricatorRepositoryPullEngine | |||||||
|             $this->installGitHook(); |             $this->installGitHook(); | ||||||
|           } else if ($is_svn) { |           } else if ($is_svn) { | ||||||
|             $this->installSubversionHook(); |             $this->installSubversionHook(); | ||||||
|  |           } else if ($is_hg) { | ||||||
|  |             $this->installMercurialHook(); | ||||||
|           } else { |           } else { | ||||||
|             $this->logPull( |             $this->logPull( | ||||||
|               pht( |               pht( | ||||||
| @@ -335,7 +337,7 @@ final class PhabricatorRepositoryPullEngine | |||||||
|         $path); |         $path); | ||||||
|     } else { |     } else { | ||||||
|       $repository->execxRemoteCommand( |       $repository->execxRemoteCommand( | ||||||
|         'clone -- %s %s', |         'clone --noupdate -- %s %s', | ||||||
|         $repository->getRemoteURI(), |         $repository->getRemoteURI(), | ||||||
|         $path); |         $path); | ||||||
|     } |     } | ||||||
| @@ -383,6 +385,33 @@ final class PhabricatorRepositoryPullEngine | |||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * @task hg | ||||||
|  |    */ | ||||||
|  |   private function installMercurialHook() { | ||||||
|  |     $repository = $this->getRepository(); | ||||||
|  |     $path = $repository->getLocalPath().'.hg/hgrc'; | ||||||
|  |  | ||||||
|  |     $root = dirname(phutil_get_library_root('phabricator')); | ||||||
|  |     $bin = $root.'/bin/commit-hook'; | ||||||
|  |  | ||||||
|  |     $data = array(); | ||||||
|  |     $data[] = '[hooks]'; | ||||||
|  |     $data[] = csprintf( | ||||||
|  |       'pretxnchangegroup.phabricator = %s %s %s', | ||||||
|  |       $bin, | ||||||
|  |       $repository->getCallsign(), | ||||||
|  |       'pretxnchangegroup'); | ||||||
|  |     $data[] = null; | ||||||
|  |  | ||||||
|  |     $data = implode("\n", $data); | ||||||
|  |  | ||||||
|  |     $this->log('%s', pht('Installing commit hook config to "%s"...', $path)); | ||||||
|  |  | ||||||
|  |     Filesystem::writeFile($path, $data); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
| /* -(  Pulling Subversion Working Copies  )---------------------------------- */ | /* -(  Pulling Subversion Working Copies  )---------------------------------- */ | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley