@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+129 -10
+4 -3
scripts/repository/commit_hook.php
··· 36 36 pht('usage: %s should be defined!', DiffusionCommitHookEngine::ENV_USER)); 37 37 } 38 38 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 + } 42 43 43 44 } else if ($repository->isSVN()) { 44 45 // NOTE: In Subversion, the entire environment gets wiped so we can't read
+109 -6
src/applications/diffusion/engine/DiffusionCommitHookEngine.php
··· 24 24 private $remoteAddress; 25 25 private $remoteProtocol; 26 26 private $transactionKey; 27 + private $mercurialHook; 27 28 28 29 29 30 /* -( Config )------------------------------------------------------------- */ ··· 95 96 96 97 public function getViewer() { 97 98 return $this->viewer; 99 + } 100 + 101 + public function setMercurialHook($mercurial_hook) { 102 + $this->mercurialHook = $mercurial_hook; 103 + return $this; 104 + } 105 + 106 + public function getMercurialHook() { 107 + return $this->mercurialHook; 98 108 } 99 109 100 110 ··· 239 249 } else if (preg_match('(^refs/tags/)', $ref_raw)) { 240 250 $ref_type = PhabricatorRepositoryPushLog::REFTYPE_TAG; 241 251 } 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)); 243 256 } 244 257 245 258 $ref_update = $this->newPushLog() ··· 413 426 414 427 415 428 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() { 416 443 $hg_node = getenv('HG_NODE'); 417 444 if (!$hg_node) { 418 445 throw new Exception(pht('Expected HG_NODE in environment!')); ··· 594 621 return $ref_updates; 595 622 } 596 623 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 + 597 705 private function parseMercurialCommits($raw) { 598 706 $commits_lines = explode("\2", $raw); 599 707 $commits_lines = array_filter($commits_lines); ··· 624 732 } 625 733 626 734 return $heads; 627 - } 628 - 629 - private function findMercurialContentUpdates(array $ref_updates) { 630 - // TODO: Implement. 631 - return array(); 632 735 } 633 736 634 737
+16
src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
··· 397 397 398 398 $data = array(); 399 399 $data[] = '[hooks]'; 400 + 401 + // This hook handles normal pushes. 400 402 $data[] = csprintf( 401 403 'pretxnchangegroup.phabricator = %s %s %s', 402 404 $bin, 403 405 $repository->getCallsign(), 404 406 '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'); 405 421 $data[] = null; 406 422 407 423 $data = implode("\n", $data);
-1
src/applications/repository/storage/PhabricatorRepositoryPushLog.php
··· 18 18 const REFTYPE_BOOKMARK = 'bookmark'; 19 19 const REFTYPE_SVN = 'svn'; 20 20 const REFTYPE_COMMIT = 'commit'; 21 - const REFTYPE_UNKNOWN = 'unknown'; 22 21 23 22 const CHANGEFLAG_ADD = 1; 24 23 const CHANGEFLAG_DELETE = 2;