Skip to content

Commit 74251b3

Browse files
author
epriestley
committedDec 17, 2013
Support bookmark hook operations in Mercurial
Summary: Ref T4195. Turns bookmark mutations in Mercurial into log objects. Test Plan: Pushed a pile of bookmarks and got logs: {F89313} Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T4195 Differential Revision: https://secure.phabricator.com/D7764
1 parent 6f3a99e commit 74251b3

File tree

4 files changed

+129
-10
lines changed

4 files changed

+129
-10
lines changed
 

‎scripts/repository/commit_hook.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@
3636
pht('usage: %s should be defined!', DiffusionCommitHookEngine::ENV_USER));
3737
}
3838

39-
// TODO: If this is a Mercurial repository, the hook we're responding to
40-
// is available in $argv[2]. It's unclear if we actually need this, or if
41-
// we can block all actions we care about with just pretxnchangegroup.
39+
if ($repository->isHg()) {
40+
// We respond to several different hooks in Mercurial.
41+
$engine->setMercurialHook($argv[2]);
42+
}
4243

4344
} else if ($repository->isSVN()) {
4445
// NOTE: In Subversion, the entire environment gets wiped so we can't read

‎src/applications/diffusion/engine/DiffusionCommitHookEngine.php

+109-6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ final class DiffusionCommitHookEngine extends Phobject {
2424
private $remoteAddress;
2525
private $remoteProtocol;
2626
private $transactionKey;
27+
private $mercurialHook;
2728

2829

2930
/* -( Config )------------------------------------------------------------- */
@@ -97,6 +98,15 @@ public function getViewer() {
9798
return $this->viewer;
9899
}
99100

101+
public function setMercurialHook($mercurial_hook) {
102+
$this->mercurialHook = $mercurial_hook;
103+
return $this;
104+
}
105+
106+
public function getMercurialHook() {
107+
return $this->mercurialHook;
108+
}
109+
100110

101111
/* -( Hook Execution )----------------------------------------------------- */
102112

@@ -239,7 +249,10 @@ private function findGitRefUpdates() {
239249
} else if (preg_match('(^refs/tags/)', $ref_raw)) {
240250
$ref_type = PhabricatorRepositoryPushLog::REFTYPE_TAG;
241251
} else {
242-
$ref_type = PhabricatorRepositoryPushLog::REFTYPE_UNKNOWN;
252+
throw new Exception(
253+
pht(
254+
"Unable to identify the reftype of '%s'. Rejecting push.",
255+
$ref_raw));
243256
}
244257

245258
$ref_update = $this->newPushLog()
@@ -413,6 +426,20 @@ private function findGitContentUpdates(array $ref_updates) {
413426

414427

415428
private function findMercurialRefUpdates() {
429+
$hook = $this->getMercurialHook();
430+
switch ($hook) {
431+
case 'pretxnchangegroup':
432+
return $this->findMercurialChangegroupRefUpdates();
433+
case 'prepushkey':
434+
return $this->findMercurialPushKeyRefUpdates();
435+
case 'pretag':
436+
return $this->findMercurialPreTagRefUpdates();
437+
default:
438+
throw new Exception(pht('Unrecognized hook "%s"!', $hook));
439+
}
440+
}
441+
442+
private function findMercurialChangegroupRefUpdates() {
416443
$hg_node = getenv('HG_NODE');
417444
if (!$hg_node) {
418445
throw new Exception(pht('Expected HG_NODE in environment!'));
@@ -594,6 +621,87 @@ private function findMercurialRefUpdates() {
594621
return $ref_updates;
595622
}
596623

624+
private function findMercurialPushKeyRefUpdates() {
625+
$key_namespace = getenv('HG_NAMESPACE');
626+
627+
if ($key_namespace === 'phases') {
628+
// Mercurial changes commit phases as part of normal push operations. We
629+
// just ignore these, as they don't seem to represent anything
630+
// interesting.
631+
return array();
632+
}
633+
634+
$key_name = getenv('HG_KEY');
635+
636+
$key_old = getenv('HG_OLD');
637+
if (!strlen($key_old)) {
638+
$key_old = null;
639+
}
640+
641+
$key_new = getenv('HG_NEW');
642+
if (!strlen($key_new)) {
643+
$key_new = null;
644+
}
645+
646+
if ($key_namespace !== 'bookmarks') {
647+
throw new Exception(
648+
pht(
649+
"Unknown Mercurial key namespace '%s', with key '%s' (%s -> %s). ".
650+
"Rejecting push.",
651+
$key_namespace,
652+
$key_name,
653+
coalesce($key_old, pht('null')),
654+
coalesce($key_new, pht('null'))));
655+
}
656+
657+
if ($key_old === $key_new) {
658+
// We get a callback when the bookmark doesn't change. Just ignore this,
659+
// as it's a no-op.
660+
return array();
661+
}
662+
663+
$ref_flags = 0;
664+
$merge_base = null;
665+
if ($key_old === null) {
666+
$ref_flags |= PhabricatorRepositoryPushLog::CHANGEFLAG_ADD;
667+
} else if ($key_new === null) {
668+
$ref_flags |= PhabricatorRepositoryPushLog::CHANGEFLAG_DELETE;
669+
} else {
670+
list($merge_base_raw) = $this->getRepository()->execxLocalCommand(
671+
'log --template %s --rev %s',
672+
'{node}',
673+
hgsprintf('ancestor(%s, %s)', $key_old, $key_new));
674+
675+
if (strlen(trim($merge_base_raw))) {
676+
$merge_base = trim($merge_base_raw);
677+
}
678+
679+
if ($merge_base && ($merge_base === $key_old)) {
680+
$ref_flags |= PhabricatorRepositoryPushLog::CHANGEFLAG_APPEND;
681+
} else {
682+
$ref_flags |= PhabricatorRepositoryPushLog::CHANGEFLAG_REWRITE;
683+
}
684+
}
685+
686+
$ref_update = $this->newPushLog()
687+
->setRefType(PhabricatorRepositoryPushLog::REFTYPE_BOOKMARK)
688+
->setRefName($key_name)
689+
->setRefOld(coalesce($key_old, self::EMPTY_HASH))
690+
->setRefNew(coalesce($key_new, self::EMPTY_HASH))
691+
->setChangeFlags($ref_flags);
692+
693+
return array($ref_update);
694+
}
695+
696+
private function findMercurialPreTagRefUpdates() {
697+
return array();
698+
}
699+
700+
private function findMercurialContentUpdates(array $ref_updates) {
701+
// TODO: Implement.
702+
return array();
703+
}
704+
597705
private function parseMercurialCommits($raw) {
598706
$commits_lines = explode("\2", $raw);
599707
$commits_lines = array_filter($commits_lines);
@@ -626,11 +734,6 @@ private function parseMercurialHeads($raw) {
626734
return $heads;
627735
}
628736

629-
private function findMercurialContentUpdates(array $ref_updates) {
630-
// TODO: Implement.
631-
return array();
632-
}
633-
634737

635738
/* -( Subversion )--------------------------------------------------------- */
636739

‎src/applications/repository/engine/PhabricatorRepositoryPullEngine.php

+16
Original file line numberDiff line numberDiff line change
@@ -397,11 +397,27 @@ private function installMercurialHook() {
397397

398398
$data = array();
399399
$data[] = '[hooks]';
400+
401+
// This hook handles normal pushes.
400402
$data[] = csprintf(
401403
'pretxnchangegroup.phabricator = %s %s %s',
402404
$bin,
403405
$repository->getCallsign(),
404406
'pretxnchangegroup');
407+
408+
// This one handles creating bookmarks.
409+
$data[] = csprintf(
410+
'prepushkey.phabricator = %s %s %s',
411+
$bin,
412+
$repository->getCallsign(),
413+
'prepushkey');
414+
415+
// This one handles creating tags.
416+
$data[] = csprintf(
417+
'pretag.phabricator = %s %s %s',
418+
$bin,
419+
$repository->getCallsign(),
420+
'pretag');
405421
$data[] = null;
406422

407423
$data = implode("\n", $data);

‎src/applications/repository/storage/PhabricatorRepositoryPushLog.php

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ final class PhabricatorRepositoryPushLog
1818
const REFTYPE_BOOKMARK = 'bookmark';
1919
const REFTYPE_SVN = 'svn';
2020
const REFTYPE_COMMIT = 'commit';
21-
const REFTYPE_UNKNOWN = 'unknown';
2221

2322
const CHANGEFLAG_ADD = 1;
2423
const CHANGEFLAG_DELETE = 2;

0 commit comments

Comments
 (0)
Failed to load comments.