mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-28 17:52:42 +01:00
Parse 'hg status -C' to show file move/copy sources
Summary: For Mercurial parsing in Diffusion, it looks like the only command we can use to get move/copy information is "hg status -C --rev <rev>", so add a parser for it. Test Plan: Ran unit tests. Reviewers: Makinde, jungejason, nh, tuomaspelkonen, aran Reviewed By: Makinde CC: aran, Makinde Differential Revision: 958
This commit is contained in:
parent
752ef65020
commit
ef0a9cbb79
4 changed files with 65 additions and 7 deletions
|
@ -30,13 +30,15 @@ final class ArcanistMercurialParser {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the output of "hg status".
|
* Parse the output of "hg status". This provides detailed information, you
|
||||||
|
* can get less detailed information with @{method:parseMercurialStatus}. In
|
||||||
|
* particular, this will parse copy sources as per "hg status -C".
|
||||||
*
|
*
|
||||||
* @param string The stdout from running an "hg status" command.
|
* @param string The stdout from running an "hg status" command.
|
||||||
* @return dict Map of paths to ArcanistRepositoryAPI status flags.
|
* @return dict Map of paths to status dictionaries.
|
||||||
* @task parse
|
* @task parse
|
||||||
*/
|
*/
|
||||||
public static function parseMercurialStatus($stdout) {
|
public static function parseMercurialStatusDetails($stdout) {
|
||||||
$result = array();
|
$result = array();
|
||||||
|
|
||||||
$stdout = trim($stdout);
|
$stdout = trim($stdout);
|
||||||
|
@ -44,16 +46,21 @@ final class ArcanistMercurialParser {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$last_path = null;
|
||||||
$lines = explode("\n", $stdout);
|
$lines = explode("\n", $stdout);
|
||||||
foreach ($lines as $line) {
|
foreach ($lines as $line) {
|
||||||
$flags = 0;
|
$flags = 0;
|
||||||
list($code, $path) = explode(' ', $line, 2);
|
if ($line[1] !== ' ') {
|
||||||
|
throw new Exception("Unparsable Mercurial status line '{$line}'.");
|
||||||
|
}
|
||||||
|
$code = $line[0];
|
||||||
|
$path = substr($line, 2);
|
||||||
switch ($code) {
|
switch ($code) {
|
||||||
case 'A':
|
case 'A':
|
||||||
$flags |= ArcanistRepositoryAPI::FLAG_ADDED;
|
$flags |= ArcanistRepositoryAPI::FLAG_ADDED;
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
$flags |= ArcanistRepositoryAPI::FLAG_REMOVED;
|
$flags |= ArcanistRepositoryAPI::FLAG_DELETED;
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
$flags |= ArcanistRepositoryAPI::FLAG_MODIFIED;
|
$flags |= ArcanistRepositoryAPI::FLAG_MODIFIED;
|
||||||
|
@ -71,17 +78,45 @@ final class ArcanistMercurialParser {
|
||||||
case 'I':
|
case 'I':
|
||||||
// This is "ignored" and included only for completeness.
|
// This is "ignored" and included only for completeness.
|
||||||
break;
|
break;
|
||||||
|
case ' ':
|
||||||
|
// This shows the source of a file move, so update the last file we
|
||||||
|
// parsed to set its source.
|
||||||
|
if ($last_path === null) {
|
||||||
|
throw new Exception(
|
||||||
|
"Unexpected copy source in hg status, '{$line}'.");
|
||||||
|
}
|
||||||
|
$result[$last_path]['from'] = $path;
|
||||||
|
continue 2;
|
||||||
default:
|
default:
|
||||||
throw new Exception("Unknown Mercurial status '{$code}'.");
|
throw new Exception("Unknown Mercurial status '{$code}'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[$path] = $flags;
|
$result[$path] = array(
|
||||||
|
'flags' => $flags,
|
||||||
|
'from' => null,
|
||||||
|
);
|
||||||
|
$last_path = $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the output of "hg status". This provides only basic information, you
|
||||||
|
* can get more detailed information by invoking
|
||||||
|
* @{method:parseMercurialStatusDetails}.
|
||||||
|
*
|
||||||
|
* @param string The stdout from running an "hg status" command.
|
||||||
|
* @return dict Map of paths to ArcanistRepositoryAPI status flags.
|
||||||
|
* @task parse
|
||||||
|
*/
|
||||||
|
public static function parseMercurialStatus($stdout) {
|
||||||
|
$result = self::parseMercurialStatusDetails($stdout);
|
||||||
|
return ipull($result, 'flags');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the output of "hg log". This also parses "hg outgoing", "hg parents",
|
* Parse the output of "hg log". This also parses "hg outgoing", "hg parents",
|
||||||
* and other similar commands. This assumes "--style default".
|
* and other similar commands. This assumes "--style default".
|
||||||
|
|
|
@ -8,5 +8,7 @@
|
||||||
|
|
||||||
phutil_require_module('arcanist', 'repository/api/base');
|
phutil_require_module('arcanist', 'repository/api/base');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
phutil_require_source('ArcanistMercurialParser.php');
|
phutil_require_source('ArcanistMercurialParser.php');
|
||||||
|
|
|
@ -20,7 +20,7 @@ final class ArcanistMercurialParserTestCase extends ArcanistPhutilTestCase {
|
||||||
|
|
||||||
public function testParseAll() {
|
public function testParseAll() {
|
||||||
$root = dirname(__FILE__).'/data/';
|
$root = dirname(__FILE__).'/data/';
|
||||||
foreach (Filesystem::listDirectory($root) as $file) {
|
foreach (Filesystem::listDirectory($root, $hidden = false) as $file) {
|
||||||
$this->parseData(
|
$this->parseData(
|
||||||
basename($file),
|
basename($file),
|
||||||
Filesystem::readFile($root.'/'.$file));
|
Filesystem::readFile($root.'/'.$file));
|
||||||
|
@ -64,6 +64,21 @@ final class ArcanistMercurialParserTestCase extends ArcanistPhutilTestCase {
|
||||||
array('changed', 'added', 'removed', 'untracked'),
|
array('changed', 'added', 'removed', 'untracked'),
|
||||||
array_keys($output));
|
array_keys($output));
|
||||||
break;
|
break;
|
||||||
|
case 'status-moves.txt':
|
||||||
|
$output = ArcanistMercurialParser::parseMercurialStatusDetails($data);
|
||||||
|
$this->assertEqual(
|
||||||
|
'move_source',
|
||||||
|
$output['moved_file']['from']);
|
||||||
|
$this->assertEqual(
|
||||||
|
null,
|
||||||
|
$output['changed_file']['from']);
|
||||||
|
$this->assertEqual(
|
||||||
|
'copy_source',
|
||||||
|
$output['copied_file']['from']);
|
||||||
|
$this->assertEqual(
|
||||||
|
null,
|
||||||
|
idx($output, 'copy_source'));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("No test information for test data '{$name}'!");
|
throw new Exception("No test information for test data '{$name}'!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
M changed_file
|
||||||
|
A moved_file
|
||||||
|
move_source
|
||||||
|
R moved_source
|
||||||
|
A copied_file
|
||||||
|
copy_source
|
Loading…
Reference in a new issue