From f93c6985ad842dc55c8350b531c51f64d8552c82 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 2 Dec 2013 15:46:03 -0800 Subject: [PATCH] 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 --- scripts/repository/commit_hook.php | 22 ++++++++++--- .../controller/DiffusionServeController.php | 8 +++-- .../engine/DiffusionCommitHookEngine.php | 10 ++++++ .../DiffusionSSHMercurialServeWorkflow.php | 3 +- .../PhabricatorRepositoryPullEngine.php | 31 ++++++++++++++++++- 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/scripts/repository/commit_hook.php b/scripts/repository/commit_hook.php index 86e927f41a..25afb714e5 100755 --- a/scripts/repository/commit_hook.php +++ b/scripts/repository/commit_hook.php @@ -29,11 +29,16 @@ $engine->setRepository($repository); // Figure out which user is writing the commit. -if ($repository->isGit()) { +if ($repository->isGit() || $repository->isHg()) { $username = getenv('PHABRICATOR_USER'); if (!strlen($username)) { 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()) { // NOTE: In Subversion, the entire environment gets wiped so we can't read // PHABRICATOR_USER. Instead, we've set "--tunnel-user" to specify the @@ -50,7 +55,7 @@ if ($repository->isGit()) { $engine->setSubversionTransactionInfo($svn_txn, $svn_repo); } else { - throw new Exceptiont(pht('Unknown repository type.')); + throw new Exception(pht('Unknown repository type.')); } $user = id(new PhabricatorPeopleQuery()) @@ -67,9 +72,16 @@ $engine->setViewer($user); // Read stdin for the hook engine. -$stdin = @file_get_contents('php://stdin'); -if ($stdin === false) { - throw new Exception(pht('Failed to read stdin!')); +if ($repository->isHg()) { + // Mercurial leaves stdin open, so we can't just read it until EOF. + $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); diff --git a/src/applications/diffusion/controller/DiffusionServeController.php b/src/applications/diffusion/controller/DiffusionServeController.php index de7c2e1eb2..6d72184216 100644 --- a/src/applications/diffusion/controller/DiffusionServeController.php +++ b/src/applications/diffusion/controller/DiffusionServeController.php @@ -406,7 +406,9 @@ final class DiffusionServeController extends DiffusionController { return $user; } - private function serveMercurialRequest(PhabricatorRepository $repository) { + private function serveMercurialRequest( + PhabricatorRepository $repository, + PhabricatorUser $viewer) { $request = $this->getRequest(); $bin = Filesystem::resolveBinary('hg'); @@ -414,7 +416,9 @@ final class DiffusionServeController extends DiffusionController { throw new Exception("Unable to find `hg` in PATH!"); } - $env = array(); + $env = array( + 'PHABRICATOR_USER' => $viewer->getUsername(), + ); $input = PhabricatorStartup::getRawInput(); $cmd = $request->getStr('cmd'); diff --git a/src/applications/diffusion/engine/DiffusionCommitHookEngine.php b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php index 282ae16697..7a6855de46 100644 --- a/src/applications/diffusion/engine/DiffusionCommitHookEngine.php +++ b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php @@ -51,6 +51,9 @@ final class DiffusionCommitHookEngine extends Phobject { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $err = $this->executeSubversionHook(); break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + $err = $this->executeMercurialHook(); + break; default: throw new Exception(pht('Unsupported repository type "%s"!', $type)); } @@ -73,6 +76,13 @@ final class DiffusionCommitHookEngine extends Phobject { return 0; } + private function executeMercurialHook() { + + // TODO: Here, too, useful things should be done. + + return 0; + } + private function parseGitUpdates($stdin) { $updates = array(); diff --git a/src/applications/diffusion/ssh/DiffusionSSHMercurialServeWorkflow.php b/src/applications/diffusion/ssh/DiffusionSSHMercurialServeWorkflow.php index 46eee57610..e7697e6083 100644 --- a/src/applications/diffusion/ssh/DiffusionSSHMercurialServeWorkflow.php +++ b/src/applications/diffusion/ssh/DiffusionSSHMercurialServeWorkflow.php @@ -42,7 +42,8 @@ final class DiffusionSSHMercurialServeWorkflow $command = csprintf('hg -R %s serve --stdio', $repository->getLocalPath()); $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); - $future = new ExecFuture('%C', $command); + $future = id(new ExecFuture('%C', $command)) + ->setEnv($this->getEnvironment()); $io_channel = $this->getIOChannel(); $protocol_channel = new DiffusionSSHMercurialWireClientProtocolChannel( diff --git a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php index ab3c759fae..c7e8e0ae7e 100644 --- a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php +++ b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php @@ -87,6 +87,8 @@ final class PhabricatorRepositoryPullEngine $this->installGitHook(); } else if ($is_svn) { $this->installSubversionHook(); + } else if ($is_hg) { + $this->installMercurialHook(); } else { $this->logPull( pht( @@ -335,7 +337,7 @@ final class PhabricatorRepositoryPullEngine $path); } else { $repository->execxRemoteCommand( - 'clone -- %s %s', + 'clone --noupdate -- %s %s', $repository->getRemoteURI(), $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 )---------------------------------- */