diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -904,7 +904,6 @@ 'DiffusionLowLevelResolveRefsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php', 'DiffusionMercurialBlameQuery' => 'applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php', 'DiffusionMercurialCommandEngine' => 'applications/diffusion/protocol/DiffusionMercurialCommandEngine.php', - 'DiffusionMercurialCommandEngineTests' => 'applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php', 'DiffusionMercurialFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionMercurialFileContentQuery.php', 'DiffusionMercurialFlagInjectionException' => 'applications/diffusion/exception/DiffusionMercurialFlagInjectionException.php', 'DiffusionMercurialRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionMercurialRawDiffQuery.php', @@ -7042,7 +7041,6 @@ 'DiffusionLowLevelResolveRefsQuery' => 'DiffusionLowLevelQuery', 'DiffusionMercurialBlameQuery' => 'DiffusionBlameQuery', 'DiffusionMercurialCommandEngine' => 'DiffusionCommandEngine', - 'DiffusionMercurialCommandEngineTests' => 'PhabricatorTestCase', 'DiffusionMercurialFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionMercurialFlagInjectionException' => 'Exception', 'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery', diff --git a/src/applications/config/check/PhabricatorBinariesSetupCheck.php b/src/applications/config/check/PhabricatorBinariesSetupCheck.php --- a/src/applications/config/check/PhabricatorBinariesSetupCheck.php +++ b/src/applications/config/check/PhabricatorBinariesSetupCheck.php @@ -120,17 +120,13 @@ break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $bad_versions = array( - // We need 1.9 for HTTP cloning, see T3046. - '< 1.9' => pht( - 'The minimum supported version of Mercurial is 1.9, which was '. - 'released in 2011.'), - '= 2.1' => pht( - 'This version of Mercurial returns a bad exit code '. - 'after a successful pull.'), - '= 2.2' => pht( - 'This version of Mercurial has a significant memory leak, fixed '. - 'in 2.2.1. Pushing fails with this version as well; see %s.', - 'T3046#54922'), + // We need 4.6 for use of `--template` in the `annotate` command, + // along with additional template format keywords `{p1node}` + // (added in 2.4, deprecated in 4.9 in favor of `{p1.node}`), + // see D21679, D21681. + '< 4.6' => pht( + 'The minimum supported version of Mercurial is 4.6, which was '. + 'released in 2018.'), ); break; } diff --git a/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php --- a/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php +++ b/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php @@ -149,15 +149,20 @@ $commit_hash); } + $hg_analyzer = PhutilBinaryAnalyzer::getForBinary('hg'); + if ($hg_analyzer->isMercurialTemplatePnodeAvailable()) { + $hg_log_template = '{node};{p1.node} {p2.node}\\n'; + } else { + $hg_log_template = '{node};{p1node} {p2node}\\n'; + } + list($stdout) = $repository->execxLocalCommand( - 'log --debug --template %s --limit %d --rev %s -- %C', - '{node};{parents}\\n', + 'log --template %s --limit %d --rev %s -- %C', + $hg_log_template, ($offset + $limit), // No '--skip' in Mercurial. $revset_arg, $path_arg); - $stdout = DiffusionMercurialCommandEngine::filterMercurialDebugOutput( - $stdout); $lines = explode("\n", trim($stdout)); $lines = array_slice($lines, $offset); @@ -166,15 +171,6 @@ $last = null; foreach (array_reverse($lines) as $line) { - // In the event additional log output is included in future mercurial - // updates, if the line does not contain any semi-colon then log it and - // ignore it. - if (strpos($line, ';') === false) { - phlog(pht( - 'Unexpected output from mercurial "log --debug" command: %s', - $line)); - continue; - } list($hash, $parents) = explode(';', $line); $parents = trim($parents); if (!$parents) { @@ -186,9 +182,8 @@ } else { $parents = preg_split('/\s+/', $parents); foreach ($parents as $parent) { - list($plocal, $phash) = explode(':', $parent); - if (!preg_match('/^0+$/', $phash)) { - $parent_map[$hash][] = $phash; + if (!preg_match('/^0+$/', $parent)) { + $parent_map[$hash][] = $parent; } } // This may happen for the zeroth commit in repository, both hashes diff --git a/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php b/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php --- a/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php +++ b/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php @@ -54,69 +54,4 @@ return $env; } - /** - * Sanitize output of an `hg` command invoked with the `--debug` flag to make - * it usable. - * - * @param string Output from `hg --debug ...` - * @return string Usable output. - */ - public static function filterMercurialDebugOutput($stdout) { - // When hg commands are run with `--debug` and some config file isn't - // trusted, Mercurial prints out a warning to stdout, twice, after Feb 2011. - // - // http://selenic.com/pipermail/mercurial-devel/2011-February/028541.html - // - // After Jan 2015, it may also fail to write to a revision branch cache. - // - // Separately, it may fail to write to a different branch cache, and may - // encounter issues reading the branch cache. - // - // When Mercurial repositories are hosted on external systems with - // multi-user environments it's possible that the branch cache is computed - // on a revision which does not end up being published. When this happens it - // will recompute the cache but also print out "invalid branch cache". - // - // https://www.mercurial-scm.org/pipermail/mercurial/2014-June/047239.html - // - // When observing a repository which uses largefiles, the debug output may - // also contain extraneous output about largefile changes. - // - // At some point Mercurial added/improved support for pager used when - // command output is large. It includes printing out debug information that - // the pager is being started for a command. This seems to happen despite - // the output of the command being piped/read from another process. - // - // When printing color output Mercurial may run into some issue with the - // terminal info. This should never happen in Phabricator since color - // output should be turned off, however in the event it shows up we should - // filter it out anyways. - - $ignore = array( - 'ignoring untrusted configuration option', - "couldn't write revision branch cache:", - "couldn't write branch cache:", - 'invalid branchheads cache', - 'invalid branch cache', - 'updated patterns: .hglf', - 'starting pager for command', - 'no terminfo entry for', - ); - - foreach ($ignore as $key => $pattern) { - $ignore[$key] = preg_quote($pattern, '/'); - } - - $ignore = '('.implode('|', $ignore).')'; - - $lines = preg_split('/(?<=\n)/', $stdout); - $regex = '/'.$ignore.'.*\n$/'; - - foreach ($lines as $key => $line) { - $lines[$key] = preg_replace($regex, '', $line); - } - - return implode('', $lines); - } - } diff --git a/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php b/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php deleted file mode 100644 --- a/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php +++ /dev/null @@ -1,42 +0,0 @@ -assertEqual('', $filtered_output); - - // The output that should make it through the filtering - $output = - "0b33a9e5ceedba14b03214f743957357d7bb46a9;694". - ":8b39f63eb209dd2bdfd4bd3d0721a9e38d75a6d3". - "-1:0000000000000000000000000000000000000000\n". - "8b39f63eb209dd2bdfd4bd3d0721a9e38d75a6d3;693". - ":165bce9ce4ccc97024ba19ed5a22f6a066fa6844". - "-1:0000000000000000000000000000000000000000\n". - "165bce9ce4ccc97024ba19ed5a22f6a066fa6844;692:". - "2337bc9e3cf212b3b386b5197801b1c81db64920". - "-1:0000000000000000000000000000000000000000\n"; - - $filtered_output = - DiffusionMercurialCommandEngine::filterMercurialDebugOutput($output); - - $this->assertEqual($output, $filtered_output); - } - -} diff --git a/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php b/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php --- a/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php +++ b/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php @@ -6,11 +6,12 @@ $repository = $request->getRepository(); $commit = $request->getCommit(); - // NOTE: We're using "--debug" to make "--changeset" give us the full - // commit hashes. + // NOTE: We're using "--template" to get the full commit hashes. + $template = "{lines % '{node}: {line}'}"; return $repository->getLocalCommandFuture( - 'annotate --debug --changeset --rev %s -- %s', + 'annotate --template %s --changeset --rev %s -- %s', + $template, $commit, $path); } diff --git a/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php b/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php --- a/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php +++ b/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php @@ -47,23 +47,25 @@ private function loadMercurialParents() { $repository = $this->getRepository(); + $hg_analyzer = PhutilBinaryAnalyzer::getForBinary('hg'); + if ($hg_analyzer->isMercurialTemplatePnodeAvailable()) { + $hg_log_template = '{p1.node} {p2.node}'; + } else { + $hg_log_template = '{p1node} {p2node}'; + } + list($stdout) = $repository->execxLocalCommand( - 'log --debug --limit 1 --template={parents} --rev %s', + 'log --limit 1 --template %s --rev %s', + $hg_log_template, $this->identifier); - $stdout = DiffusionMercurialCommandEngine::filterMercurialDebugOutput( - $stdout); - $hashes = preg_split('/\s+/', trim($stdout)); foreach ($hashes as $key => $value) { - // Mercurial parents look like "23:ad9f769d6f786fad9f76d9a" -- we want - // to strip out the local rev part. - list($local, $global) = explode(':', $value); - $hashes[$key] = $global; - - // With --debug we get 40-character hashes but also get the "000000..." - // hash for missing parents; ignore it. - if (preg_match('/^0+$/', $global)) { + $hashes[$key] = $value; + + // We get 40-character hashes but also get the "000000..." hash for + // missing parents; ignore it. + if (preg_match('/^0+$/', $value)) { unset($hashes[$key]); } } diff --git a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php --- a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php +++ b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php @@ -100,55 +100,6 @@ } - public function testFilterMercurialDebugOutput() { - $map = array( - '' => '', - - "quack\n" => "quack\n", - - "ignoring untrusted configuration option x.y = z\nquack\n" => - "quack\n", - - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "quack\n" => - "quack\n", - - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "quack\n" => - "quack\n", - - "quack\n". - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n" => - "quack\n", - - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "duck\n". - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "bread\n". - "ignoring untrusted configuration option x.y = z\n". - "quack\n" => - "duck\nbread\nquack\n", - - "ignoring untrusted configuration option x.y = z\n". - "duckignoring untrusted configuration option x.y = z\n". - "quack" => - 'duckquack', - ); - - foreach ($map as $input => $expect) { - $actual = DiffusionMercurialCommandEngine::filterMercurialDebugOutput( - $input); - $this->assertEqual($expect, $actual, $input); - } - } - public function testRepositoryShortNameValidation() { $good = array( 'sensible-repository',