1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-22 14:52:40 +01:00

pht all the things

Summary: `pht`ize almost all strings in rARC.

Test Plan: ¯\_(ツ)_/¯

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: aurelijus, Korvin, epriestley

Differential Revision: https://secure.phabricator.com/D12607
This commit is contained in:
Joshua Spence 2015-05-13 18:05:15 +10:00
parent 9090efcb40
commit d2b38cdf94
110 changed files with 1783 additions and 1150 deletions

View file

@ -46,8 +46,11 @@ class ArcanistConfiguration {
if (isset($workflows_by_name[$name])) { if (isset($workflows_by_name[$name])) {
$other = get_class($workflows_by_name[$name]); $other = get_class($workflows_by_name[$name]);
throw new Exception( throw new Exception(
"Workflows {$class} and {$other} both implement workflows named ". pht(
"{$name}."); 'Workflows %s and %s both implement workflows named %s.',
$class,
$other,
$name));
} }
$workflows_by_name[$name] = $workflow; $workflows_by_name[$name] = $workflow;
@ -109,7 +112,8 @@ class ArcanistConfiguration {
$shell_cmd = substr($full_alias, 1); $shell_cmd = substr($full_alias, 1);
$console->writeLog( $console->writeLog(
"[alias: 'arc %s' -> $ %s]", "[%s: 'arc %s' -> $ %s]",
pht('alias'),
$command, $command,
$shell_cmd); $shell_cmd);
@ -127,7 +131,8 @@ class ArcanistConfiguration {
$workflow = $this->buildWorkflow($new_command); $workflow = $this->buildWorkflow($new_command);
if ($workflow) { if ($workflow) {
$console->writeLog( $console->writeLog(
"[alias: 'arc %s' -> 'arc %s']\n", "[%s: 'arc %s' -> 'arc %s']\n",
pht('alias'),
$command, $command,
$full_alias); $full_alias);
$command = $new_command; $command = $new_command;
@ -168,7 +173,7 @@ class ArcanistConfiguration {
} }
private function raiseUnknownCommand($command, array $maybe = array()) { private function raiseUnknownCommand($command, array $maybe = array()) {
$message = pht("Unknown command '%s'. Try 'arc help'.", $command); $message = pht("Unknown command '%s'. Try '%s'.", $command, 'arc help');
if ($maybe) { if ($maybe) {
$message .= "\n\n".pht('Did you mean:')."\n"; $message .= "\n\n".pht('Did you mean:')."\n";
sort($maybe); sort($maybe);

View file

@ -180,11 +180,13 @@ final class ArcanistConfigurationManager {
} }
if ($mode & 0177) { if ($mode & 0177) {
// Mode should allow only owner access. // Mode should allow only owner access.
$prompt = "File permissions on your ~/.arcrc are too open. ". $prompt = pht(
"Fix them by chmod'ing to 600?"; "File permissions on your %s are too open. ".
"Fix them by chmod'ing to 600?",
'~/.arcrc');
if (!phutil_console_confirm($prompt, $default_no = false)) { if (!phutil_console_confirm($prompt, $default_no = false)) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'Set ~/.arcrc to file mode 600.'); pht('Set %s to file mode 600.', '~/.arcrc'));
} }
execx('chmod 600 %s', $user_config_path); execx('chmod 600 %s', $user_config_path);
@ -200,7 +202,7 @@ final class ArcanistConfigurationManager {
$user_config = phutil_json_decode($user_config_data); $user_config = phutil_json_decode($user_config_data);
} catch (PhutilJSONParserException $ex) { } catch (PhutilJSONParserException $ex) {
throw new PhutilProxyException( throw new PhutilProxyException(
"Your '~/.arcrc' file is not a valid JSON file.", pht("Your '%s' file is not a valid JSON file.", '~/.arcrc'),
$ex); $ex);
} }
} else { } else {
@ -236,7 +238,7 @@ final class ArcanistConfigurationManager {
public function setUserConfigurationFileLocation($custom_arcrc) { public function setUserConfigurationFileLocation($custom_arcrc) {
if (!Filesystem::pathExists($custom_arcrc)) { if (!Filesystem::pathExists($custom_arcrc)) {
throw new Exception( throw new Exception(
'Custom arcrc file was specified, but it was not found!'); pht('Custom %s file was specified, but it was not found!', 'arcrc'));
} }
$this->customArcrcFilename = $custom_arcrc; $this->customArcrcFilename = $custom_arcrc;
@ -318,8 +320,12 @@ final class ArcanistConfigurationManager {
foreach ($options as $opt) { foreach ($options as $opt) {
$opt_config = preg_split('/=/', $opt, 2); $opt_config = preg_split('/=/', $opt, 2);
if (count($opt_config) !== 2) { if (count($opt_config) !== 2) {
throw new ArcanistUsageException("Argument was '{$opt}', but must be ". throw new ArcanistUsageException(
"'name=value'. For example, history.immutable=true"); pht(
"Argument was '%s', but must be '%s'. For example, %s",
$opt,
'name=value',
'history.immutable=true'));
} }
list($key, $value) = $opt_config; list($key, $value) = $opt_config;

View file

@ -86,7 +86,7 @@ final class ArcanistSettings {
'help' => pht( 'help' => pht(
'The name of the default branch to land changes onto when '. 'The name of the default branch to land changes onto when '.
'`%s` is run.', '`%s` is run.',
'arc land'), 'arc land'),
'example' => '"develop"', 'example' => '"develop"',
), ),
'arc.land.update.default' => array( 'arc.land.update.default' => array(

View file

@ -53,7 +53,7 @@ final class ArcanistBritishTestCase extends ArcanistTestCase {
$this->assertEqual( $this->assertEqual(
$expect, $expect,
$result, $result,
"Correction of {$input} against: {$commands}"); pht('Correction of %s against: %s', $input, $commands));
} }
public function testArgumentCompletion() { public function testArgumentCompletion() {
@ -91,7 +91,7 @@ final class ArcanistBritishTestCase extends ArcanistTestCase {
$this->assertEqual( $this->assertEqual(
$expect, $expect,
$result, $result,
"Correction of {$input} against: {$arguments}"); pht('Correction of %s against: %s', $input, $arguments));
} }
} }

View file

@ -26,7 +26,7 @@ final class ArcanistDiffUtils {
$diff_options = "-L 'Old Value' -L 'New Value'") { $diff_options = "-L 'Old Value' -L 'New Value'") {
if ((string)$old === (string)$new) { if ((string)$old === (string)$new) {
$new .= "\n(Old and new values are identical.)"; $new .= "\n".pht('(Old and new values are identical.)');
} }
$file_old = new TempFile(); $file_old = new TempFile();

View file

@ -21,7 +21,7 @@ final class ArcanistDifferentialRevisionStatus {
self::IN_PREPARATION => pht('In Preparation'), self::IN_PREPARATION => pht('In Preparation'),
); );
return idx($map, coalesce($status, '?'), 'Unknown'); return idx($map, coalesce($status, '?'), pht('Unknown'));
} }
} }

View file

@ -7,7 +7,7 @@
final class ArcanistUserAbortException extends ArcanistUsageException { final class ArcanistUserAbortException extends ArcanistUsageException {
public function __construct() { public function __construct() {
parent::__construct('User aborted the workflow.'); parent::__construct(pht('User aborted the workflow.'));
} }
} }

View file

@ -57,7 +57,7 @@ final class ArcanistHgClientChannel extends PhutilProtocolChannel {
*/ */
protected function encodeMessage($argv) { protected function encodeMessage($argv) {
if (!is_array($argv) || count($argv) !== 2) { if (!is_array($argv) || count($argv) !== 2) {
throw new Exception('Message should be <channel, data>.'); throw new Exception(pht('Message should be %s.', '<channel, data>'));
} }
$channel = head($argv); $channel = head($argv);

View file

@ -163,7 +163,10 @@ final class ArcanistHgProxyClient {
if ($errno || !$socket) { if ($errno || !$socket) {
throw new Exception( throw new Exception(
"Unable to connect socket! Error #{$errno}: {$errstr}"); pht(
'Unable to connect socket! Error #%d: %s',
$errno,
$errstr));
} }
$channel = new PhutilSocketChannel($socket); $channel = new PhutilSocketChannel($socket);

View file

@ -168,7 +168,7 @@ final class ArcanistHgProxyServer {
$hg = $this->startMercurialProcess(); $hg = $this->startMercurialProcess();
$clients = array(); $clients = array();
$this->log(null, 'Listening'); $this->log(null, pht('Listening'));
$this->idleSince = time(); $this->idleSince = time();
while (true) { while (true) {
// Wait for activity on any active clients, the Mercurial process, or // Wait for activity on any active clients, the Mercurial process, or
@ -181,7 +181,7 @@ final class ArcanistHgProxyServer {
)); ));
if (!$hg->update()) { if (!$hg->update()) {
throw new Exception('Server exited unexpectedly!'); throw new Exception(pht('Server exited unexpectedly!'));
} }
// Accept any new clients. // Accept any new clients.
@ -190,7 +190,7 @@ final class ArcanistHgProxyServer {
$key = last_key($clients); $key = last_key($clients);
$client->setName($key); $client->setName($key);
$this->log($client, 'Connected'); $this->log($client, pht('Connected'));
$this->idleSince = time(); $this->idleSince = time();
// Check if we've hit the client limit. If there's a configured // Check if we've hit the client limit. If there's a configured
@ -216,7 +216,7 @@ final class ArcanistHgProxyServer {
continue; continue;
} }
$this->log($client, 'Disconnected'); $this->log($client, pht('Disconnected'));
unset($clients[$key]); unset($clients[$key]);
// If we have a client limit and we've served that many clients, exit. // If we have a client limit and we've served that many clients, exit.
@ -224,7 +224,7 @@ final class ArcanistHgProxyServer {
if ($this->clientLimit) { if ($this->clientLimit) {
if ($this->lifetimeClientCount >= $this->clientLimit) { if ($this->lifetimeClientCount >= $this->clientLimit) {
if (!$clients) { if (!$clients) {
$this->log(null, 'Exiting (Client Limit)'); $this->log(null, pht('Exiting (Client Limit)'));
return; return;
} }
} }
@ -236,11 +236,11 @@ final class ArcanistHgProxyServer {
if ($this->idleLimit) { if ($this->idleLimit) {
$remaining = $this->idleLimit - (time() - $this->idleSince); $remaining = $this->idleLimit - (time() - $this->idleSince);
if ($remaining <= 0) { if ($remaining <= 0) {
$this->log(null, 'Exiting (Idle Limit)'); $this->log(null, pht('Exiting (Idle Limit)'));
return; return;
} }
if ($remaining <= 5) { if ($remaining <= 5) {
$this->log(null, 'Exiting in '.$remaining.' seconds'); $this->log(null, pht('Exiting in %d seconds', $remaining));
} }
} }
} }
@ -312,7 +312,7 @@ final class ArcanistHgProxyServer {
// Log the elapsed time. // Log the elapsed time.
$t_end = microtime(true); $t_end = microtime(true);
$t = 1000000 * ($t_end - $t_start); $t = 1000000 * ($t_end - $t_start);
$this->log($client, '< '.number_format($t, 0).'us'); $this->log($client, pht('< %sus', number_format($t, 0)));
$this->idleSince = time(); $this->idleSince = time();
@ -349,12 +349,15 @@ final class ArcanistHgProxyServer {
if ($errno || !$socket) { if ($errno || !$socket) {
throw new Exception( throw new Exception(
"Unable to start socket! Error #{$errno}: {$errstr}"); pht(
'Unable to start socket! Error #%d: %s',
$errno,
$errstr));
} }
$ok = stream_set_blocking($socket, 0); $ok = stream_set_blocking($socket, 0);
if ($ok === false) { if ($ok === false) {
throw new Exception('Unable to set socket nonblocking!'); throw new Exception(pht('Unable to set socket nonblocking!'));
} }
return $socket; return $socket;
@ -438,9 +441,15 @@ final class ArcanistHgProxyServer {
} }
if ($client) { if ($client) {
$message = '[Client '.$client->getName().'] '.$message; $message = sprintf(
'[%s] %s',
pht('Client %s', $client->getName()),
$message);
} else { } else {
$message = '[Server] '.$message; $message = sprintf(
'[%s] %s',
pht('Server'),
$message);
} }
echo $message."\n"; echo $message."\n";
@ -461,7 +470,7 @@ final class ArcanistHgProxyServer {
$pid = pcntl_fork(); $pid = pcntl_fork();
if ($pid === -1) { if ($pid === -1) {
throw new Exception('Unable to fork!'); throw new Exception(pht('Unable to fork!'));
} else if ($pid) { } else if ($pid) {
// We're the parent; exit. First, drop our reference to the socket so // We're the parent; exit. First, drop our reference to the socket so
// our __destruct() doesn't tear it down; the child will tear it down // our __destruct() doesn't tear it down; the child will tear it down

View file

@ -86,7 +86,8 @@ final class ArcanistHgServerChannel extends PhutilProtocolChannel {
*/ */
protected function encodeMessage($argv) { protected function encodeMessage($argv) {
if (!is_array($argv)) { if (!is_array($argv)) {
throw new Exception('Message to Mercurial server should be an array.'); throw new Exception(
pht('Message to Mercurial server should be an array.'));
} }
$command = head($argv); $command = head($argv);

View file

@ -49,8 +49,10 @@ final class ArcanistLintPatcher {
list($err) = exec_manual('mv -f %s %s', $lint, $path); list($err) = exec_manual('mv -f %s %s', $lint, $path);
if ($err) { if ($err) {
throw new Exception( throw new Exception(
"Unable to overwrite path `{$path}', patched version was left ". pht(
"at `{$lint}'."); "Unable to overwrite path '%s', patched version was left at '%s'.",
$path,
$lint));
} }
foreach ($this->applyMessages as $message) { foreach ($this->applyMessages as $message) {
@ -114,7 +116,7 @@ final class ArcanistLintPatcher {
} }
if ($line_num >= count($this->lineOffsets)) { if ($line_num >= count($this->lineOffsets)) {
throw new Exception("Data has fewer than `{$line}' lines."); throw new Exception(pht('Data has fewer than %d lines.', $line));
} }
return idx($this->lineOffsets, $line_num); return idx($this->lineOffsets, $line_num);

View file

@ -13,11 +13,11 @@ final class ArcanistLintSeverity {
public static function getLintSeverities() { public static function getLintSeverities() {
return array( return array(
self::SEVERITY_ADVICE => 'Advice', self::SEVERITY_ADVICE => pht('Advice'),
self::SEVERITY_AUTOFIX => 'Auto-Fix', self::SEVERITY_AUTOFIX => pht('Auto-Fix'),
self::SEVERITY_WARNING => 'Warning', self::SEVERITY_WARNING => pht('Warning'),
self::SEVERITY_ERROR => 'Error', self::SEVERITY_ERROR => pht('Error'),
self::SEVERITY_DISABLED => 'Disabled', self::SEVERITY_DISABLED => pht('Disabled'),
); );
} }
@ -25,7 +25,7 @@ final class ArcanistLintSeverity {
$map = self::getLintSeverities(); $map = self::getLintSeverities();
if (!array_key_exists($severity_code, $map)) { if (!array_key_exists($severity_code, $map)) {
throw new Exception("Unknown lint severity '{$severity_code}'!"); throw new Exception(pht("Unknown lint severity '%s'!", $severity_code));
} }
return $map[$severity_code]; return $map[$severity_code];

View file

@ -168,7 +168,7 @@ abstract class ArcanistLintEngine {
final public function run() { final public function run() {
$linters = $this->buildLinters(); $linters = $this->buildLinters();
if (!$linters) { if (!$linters) {
throw new ArcanistNoEffectException('No linters to run.'); throw new ArcanistNoEffectException(pht('No linters to run.'));
} }
foreach ($linters as $key => $linter) { foreach ($linters as $key => $linter) {
@ -189,7 +189,7 @@ abstract class ArcanistLintEngine {
} }
if (!$have_paths) { if (!$have_paths) {
throw new ArcanistNoEffectException('No paths are lintable.'); throw new ArcanistNoEffectException(pht('No paths are lintable.'));
} }
$versions = array($this->getCacheVersion()); $versions = array($this->getCacheVersion());
@ -272,7 +272,9 @@ abstract class ArcanistLintEngine {
} }
if ($exceptions) { if ($exceptions) {
throw new PhutilAggregateException('Some linters failed:', $exceptions); throw new PhutilAggregateException(
pht('Some linters failed:'),
$exceptions);
} }
return $this->results; return $this->results;

View file

@ -132,8 +132,9 @@ abstract class ArcanistBaseXHPASTLinter extends ArcanistFutureLinter {
throw new Exception( throw new Exception(
pht( pht(
'Imbalanced calls to shared futures: each call to '. 'Imbalanced calls to shared futures: each call to '.
'buildSharedFutures() for a path must be paired with a call to '. '%s for a path must be paired with a call to %s.',
'releaseSharedFutures().')); 'buildSharedFutures()',
'releaseSharedFutures()'));
} }
$this->refcount[$path]--; $this->refcount[$path]--;

View file

@ -62,12 +62,14 @@ final class ArcanistCSharpLinter extends ArcanistLinter {
foreach ($map as $code => $severity) { foreach ($map as $code => $severity) {
if (substr($code, 0, 2) === 'SA' && $severity == 'disabled') { if (substr($code, 0, 2) === 'SA' && $severity == 'disabled') {
throw new Exception( throw new Exception(
"In order to keep StyleCop integration with IDEs and other tools ". pht(
"consistent with Arcanist results, you aren't permitted to ". "In order to keep StyleCop integration with IDEs and other tools ".
"disable StyleCop rules within '.arclint'. ". "consistent with Arcanist results, you aren't permitted to ".
"Instead configure the severity using the StyleCop settings dialog ". "disable StyleCop rules within '%s'. Instead configure the ".
"(usually accessible from within your IDE). StyleCop settings ". "severity using the StyleCop settings dialog (usually accessible ".
"for your project will be used when linting for Arcanist."); "from within your IDE). StyleCop settings for your project will ".
"be used when linting for Arcanist.",
'.arclint'));
} }
} }
return parent::setCustomSeverityMap($map); return parent::setCustomSeverityMap($map);
@ -92,7 +94,8 @@ final class ArcanistCSharpLinter extends ArcanistLinter {
} else if (Filesystem::binaryExists('mono')) { } else if (Filesystem::binaryExists('mono')) {
$this->runtimeEngine = 'mono '; $this->runtimeEngine = 'mono ';
} else { } else {
throw new Exception('Unable to find Mono and you are not on Windows!'); throw new Exception(
pht('Unable to find Mono and you are not on Windows!'));
} }
// Determine cslint path. // Determine cslint path.
@ -102,7 +105,7 @@ final class ArcanistCSharpLinter extends ArcanistLinter {
} else if (Filesystem::binaryExists('cslint.exe')) { } else if (Filesystem::binaryExists('cslint.exe')) {
$this->cslintEngine = 'cslint.exe'; $this->cslintEngine = 'cslint.exe';
} else { } else {
throw new Exception('Unable to locate cslint.'); throw new Exception(pht('Unable to locate %s.', 'cslint'));
} }
// Determine cslint version. // Determine cslint version.
@ -112,18 +115,27 @@ final class ArcanistCSharpLinter extends ArcanistLinter {
list($err, $stdout, $stderr) = $ver_future->resolve(); list($err, $stdout, $stderr) = $ver_future->resolve();
if ($err !== 0) { if ($err !== 0) {
throw new Exception( throw new Exception(
'You are running an old version of cslint. Please '. pht(
'upgrade to version '.self::SUPPORTED_VERSION.'.'); 'You are running an old version of %s. Please '.
'upgrade to version %s.',
'cslint',
self::SUPPORTED_VERSION));
} }
$ver = (int)$stdout; $ver = (int)$stdout;
if ($ver < self::SUPPORTED_VERSION) { if ($ver < self::SUPPORTED_VERSION) {
throw new Exception( throw new Exception(
'You are running an old version of cslint. Please '. pht(
'upgrade to version '.self::SUPPORTED_VERSION.'.'); 'You are running an old version of %s. Please '.
'upgrade to version %s.',
'cslint',
self::SUPPORTED_VERSION));
} else if ($ver > self::SUPPORTED_VERSION) { } else if ($ver > self::SUPPORTED_VERSION) {
throw new Exception( throw new Exception(
'Arcanist does not support this version of cslint (it is '. pht(
'newer). You can try upgrading Arcanist with `arc upgrade`.'); 'Arcanist does not support this version of %s (it is newer). '.
'You can try upgrading Arcanist with `%s`.',
'cslint',
'arc upgrade'));
} }
$this->loaded = true; $this->loaded = true;

View file

@ -14,7 +14,9 @@ final class ArcanistCppcheckLinter extends ArcanistExternalLinter {
} }
public function getInfoDescription() { public function getInfoDescription() {
return pht('Use `cppcheck` to perform static analysis on C/C++ code.'); return pht(
'Use `%s` to perform static analysis on C/C++ code.',
'cppcheck');
} }
public function getLinterName() { public function getLinterName() {
@ -49,7 +51,9 @@ final class ArcanistCppcheckLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install Cppcheck using `apt-get install cppcheck` or similar.'); return pht(
'Install Cppcheck using `%s` or similar.',
'apt-get install cppcheck');
} }
protected function getMandatoryFlags() { protected function getMandatoryFlags() {

View file

@ -25,8 +25,10 @@ final class ArcanistCpplintLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install cpplint.py using `wget http://google-styleguide.'. return pht(
'googlecode.com/svn/trunk/cpplint/cpplint.py`.'); 'Install cpplint.py using `%s`.',
'wget http://google-styleguide.googlecode.com'.
'/svn/trunk/cpplint/cpplint.py');
} }
protected function getDefaultFlags() { protected function getDefaultFlags() {

View file

@ -16,8 +16,9 @@ final class ArcanistFlake8Linter extends ArcanistExternalLinter {
public function getInfoDescription() { public function getInfoDescription() {
return pht( return pht(
'Uses `flake8` to run several linters (PyFlakes, pep8, and a McCabe '. 'Uses `%s` to run several linters (PyFlakes, pep8, and a McCabe '.
'complexity checker) on Python source files.'); 'complexity checker) on Python source files.',
'flake8');
} }
public function getLinterName() { public function getLinterName() {
@ -55,7 +56,7 @@ final class ArcanistFlake8Linter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install flake8 using `easy_install flake8`.'); return pht('Install flake8 using `%s`.', 'easy_install flake8');
} }
protected function parseLinterOutput($path, $err, $stdout, $stderr) { protected function parseLinterOutput($path, $err, $stdout, $stderr) {

View file

@ -11,8 +11,8 @@ final class ArcanistGeneratedLinter extends ArcanistLinter {
public function getInfoDescription() { public function getInfoDescription() {
return pht( return pht(
'Disables lint for files that are marked as "%s", indicating that they '. 'Disables lint for files that are marked as "%s", '.
'contain generated code.', 'indicating that they contain generated code.',
'@'.'generated'); '@'.'generated');
} }

View file

@ -27,7 +27,9 @@ final class ArcanistGoLintLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install Golint using `go get github.com/golang/lint/golint`.'); return pht(
'Install Golint using `%s`.',
'go get github.com/golang/lint/golint');
} }
public function shouldExpectCommandErrors() { public function shouldExpectCommandErrors() {

View file

@ -30,7 +30,7 @@ final class ArcanistHLintLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install hlint with `cabal install hlint`.'); return pht('Install hlint with `%s`.', 'cabal install hlint');
} }
protected function getMandatoryFlags() { protected function getMandatoryFlags() {
@ -50,7 +50,6 @@ final class ArcanistHLintLinter extends ArcanistExternalLinter {
} }
protected function parseLinterOutput($path, $err, $stdout, $stderr) { protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$json = phutil_json_decode($stdout); $json = phutil_json_decode($stdout);
$messages = array(); $messages = array();
foreach ($json as $fix) { foreach ($json as $fix) {
@ -71,13 +70,17 @@ final class ArcanistHLintLinter extends ArcanistExternalLinter {
all necessary notes too. */ all necessary notes too. */
$notes = ''; $notes = '';
foreach ($fix['note'] as $note) { foreach ($fix['note'] as $note) {
$notes .= ' **NOTE**: '.trim($note, '"').'.'; $notes .= phutil_console_format(
' **%s**: %s.',
pht('NOTE'),
trim($note, '"'));
} }
$message->setDescription( $message->setDescription(
pht( pht(
'In module `%s`, declaration `%s`.%s', 'In module `%s`, declaration `%s`.',
$fix['module'], $fix['decl'], $notes)); $fix['module'],
$fix['decl']).$notes);
switch ($fix['severity']) { switch ($fix['severity']) {
case 'Error': case 'Error':

View file

@ -17,7 +17,9 @@ final class ArcanistJSHintLinter extends ArcanistExternalLinter {
} }
public function getInfoDescription() { public function getInfoDescription() {
return pht('Use `jshint` to detect issues with JavaScript source files.'); return pht(
'Use `%s` to detect issues with JavaScript source files.',
'jshint');
} }
public function getLinterName() { public function getLinterName() {
@ -70,7 +72,7 @@ final class ArcanistJSHintLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install JSHint using `npm install -g jshint`.'); return pht('Install JSHint using `%s`.', 'npm install -g jshint');
} }
protected function getMandatoryFlags() { protected function getMandatoryFlags() {

View file

@ -14,7 +14,7 @@ final class ArcanistJSONLintLinter extends ArcanistExternalLinter {
} }
public function getInfoDescription() { public function getInfoDescription() {
return pht('Use `jsonlint` to detect syntax errors in JSON files.'); return pht('Use `%s` to detect syntax errors in JSON files.', 'jsonlint');
} }
public function getLinterName() { public function getLinterName() {
@ -44,7 +44,7 @@ final class ArcanistJSONLintLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install jsonlint using `npm install -g jsonlint`.'); return pht('Install jsonlint using `%s`.', 'npm install -g jsonlint');
} }
protected function getMandatoryFlags() { protected function getMandatoryFlags() {

View file

@ -14,7 +14,9 @@ final class ArcanistJscsLinter extends ArcanistExternalLinter {
} }
public function getInfoDescription() { public function getInfoDescription() {
return pht('Use `jscs` to detect issues with Javascript source files.'); return pht(
'Use `%s` to detect issues with Javascript source files.',
'jscs');
} }
public function getLinterName() { public function getLinterName() {
@ -42,7 +44,7 @@ final class ArcanistJscsLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install JSCS using `npm install -g jscs`.'); return pht('Install JSCS using `%s`.', 'npm install -g jscs');
} }
protected function getMandatoryFlags() { protected function getMandatoryFlags() {
@ -66,7 +68,7 @@ final class ArcanistJscsLinter extends ArcanistExternalLinter {
$options = array( $options = array(
'jscs.config' => array( 'jscs.config' => array(
'type' => 'optional string', 'type' => 'optional string',
'help' => pht('Pass in a custom jscsrc file path.'), 'help' => pht('Pass in a custom %s file path.', 'jscsrc'),
), ),
'jscs.preset' => array( 'jscs.preset' => array(
'type' => 'optional string', 'type' => 'optional string',

View file

@ -20,7 +20,7 @@ final class ArcanistLesscLinter extends ArcanistExternalLinter {
private $strictUnits = false; private $strictUnits = false;
public function getInfoName() { public function getInfoName() {
return pht('Less'); return 'Less';
} }
public function getInfoURI() { public function getInfoURI() {
@ -29,8 +29,10 @@ final class ArcanistLesscLinter extends ArcanistExternalLinter {
public function getInfoDescription() { public function getInfoDescription() {
return pht( return pht(
'Use the `--lint` mode provided by `lessc` to detect errors in Less '. 'Use the `%s` mode provided by `%s` to detect errors in '.
'source files.'); 'Less source files.',
'--lint',
'lessc');
} }
public function getLinterName() { public function getLinterName() {
@ -98,7 +100,7 @@ final class ArcanistLesscLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install lessc using `npm install -g less`.'); return pht('Install lessc using `%s`.', 'npm install -g less');
} }
protected function getMandatoryFlags() { protected function getMandatoryFlags() {
@ -154,9 +156,10 @@ final class ArcanistLesscLinter extends ArcanistExternalLinter {
break; break;
default: default:
throw new RuntimeException(pht( throw new RuntimeException(
'Unrecognized lint message code "%s".', pht(
$code)); 'Unrecognized lint message code "%s".',
$code));
} }
$code = $this->getLintCodeFromLinterConfigurationKey($matches['name']); $code = $this->getLintCodeFromLinterConfigurationKey($matches['name']);

View file

@ -382,7 +382,7 @@ abstract class ArcanistLinter {
if (isset($map[$code])) { if (isset($map[$code])) {
return $map[$code]; return $map[$code];
} }
return 'Unknown lint message!'; return pht('Unknown lint message!');
} }
final protected function addLintMessage(ArcanistLintMessage $message) { final protected function addLintMessage(ArcanistLintMessage $message) {
@ -511,10 +511,10 @@ abstract class ArcanistLinter {
public function setLinterConfigurationValue($key, $value) { public function setLinterConfigurationValue($key, $value) {
$sev_map = array( $sev_map = array(
'error' => ArcanistLintSeverity::SEVERITY_ERROR, 'error' => ArcanistLintSeverity::SEVERITY_ERROR,
'warning' => ArcanistLintSeverity::SEVERITY_WARNING, 'warning' => ArcanistLintSeverity::SEVERITY_WARNING,
'autofix' => ArcanistLintSeverity::SEVERITY_AUTOFIX, 'autofix' => ArcanistLintSeverity::SEVERITY_AUTOFIX,
'advice' => ArcanistLintSeverity::SEVERITY_ADVICE, 'advice' => ArcanistLintSeverity::SEVERITY_ADVICE,
'disabled' => ArcanistLintSeverity::SEVERITY_DISABLED, 'disabled' => ArcanistLintSeverity::SEVERITY_DISABLED,
); );
@ -566,7 +566,7 @@ abstract class ArcanistLinter {
return; return;
} }
throw new Exception("Incomplete implementation: {$key}!"); throw new Exception(pht('Incomplete implementation: %s!', $key));
} }
protected function canCustomizeLintSeverities() { protected function canCustomizeLintSeverities() {
@ -637,9 +637,10 @@ abstract class ArcanistLinter {
pht('Deprecation Warning'), pht('Deprecation Warning'),
pht( pht(
'Configuration option "%s" is deprecated. Generally, linters should '. 'Configuration option "%s" is deprecated. Generally, linters should '.
'now be configured using an `.arclint` file. See "Arcanist User '. 'now be configured using an `%s` file. See "Arcanist User '.
'Guide: Lint" in the documentation for more information.', 'Guide: Lint" in the documentation for more information.',
$key)); $key,
'.arclint'));
return $result; return $result;
} }

View file

@ -67,7 +67,7 @@ final class ArcanistPEP8Linter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install PEP8 using `easy_install pep8`.'); return pht('Install PEP8 using `%s`.', 'easy_install pep8');
} }
protected function parseLinterOutput($path, $err, $stdout, $stderr) { protected function parseLinterOutput($path, $err, $stdout, $stderr) {

View file

@ -94,7 +94,7 @@ final class ArcanistPhpLinter extends ArcanistExternalLinter {
return self::LINT_FATAL_ERROR; return self::LINT_FATAL_ERROR;
default: default:
throw new Exception(pht('Unrecognized lint message code "%s"', $code)); throw new Exception(pht('Unrecognized lint message code: "%s"', $code));
} }
} }

View file

@ -30,7 +30,7 @@ final class ArcanistPhpcsLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install PHPCS with `pear install PHP_CodeSniffer`.'); return pht('Install PHPCS with `%s`.', 'pear install PHP_CodeSniffer');
} }
public function getLinterConfigurationOptions() { public function getLinterConfigurationOptions() {
@ -152,7 +152,10 @@ final class ArcanistPhpcsLinter extends ArcanistExternalLinter {
protected function getLintCodeFromLinterConfigurationKey($code) { protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('/^PHPCS\\.(E|W)\\./', $code)) { if (!preg_match('/^PHPCS\\.(E|W)\\./', $code)) {
throw new Exception( throw new Exception(
"Invalid severity code '{$code}', should begin with 'PHPCS.'."); pht(
"Invalid severity code '%s', should begin with '%s.'.",
$code,
'PHPCS'));
} }
return $code; return $code;
} }

View file

@ -39,16 +39,13 @@ final class ArcanistPhutilXHPASTLinter extends ArcanistBaseXHPASTLinter {
public function getLintNameMap() { public function getLintNameMap() {
return array( return array(
self::LINT_ARRAY_COMBINE => pht( self::LINT_ARRAY_COMBINE => pht(
'%s Unreliable', '%s Unreliable', 'array_combine()'),
'array_combine()'),
self::LINT_DEPRECATED_FUNCTION => pht( self::LINT_DEPRECATED_FUNCTION => pht(
'Use of Deprecated Function'), 'Use of Deprecated Function'),
self::LINT_UNSAFE_DYNAMIC_STRING => pht( self::LINT_UNSAFE_DYNAMIC_STRING => pht(
'Unsafe Usage of Dynamic String'), 'Unsafe Usage of Dynamic String'),
self::LINT_RAGGED_CLASSTREE_EDGE => pht( self::LINT_RAGGED_CLASSTREE_EDGE => pht(
'Class Not %s Or %s', 'Class Not %s Or %s', 'abstract', 'final'),
'abstract',
'final'),
); );
} }

View file

@ -50,7 +50,7 @@ final class ArcanistPyFlakesLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install pyflakes with `pip install pyflakes`.'); return pht('Install pyflakes with `%s`.', 'pip install pyflakes');
} }
protected function parseLinterOutput($path, $err, $stdout, $stderr) { protected function parseLinterOutput($path, $err, $stdout, $stderr) {

View file

@ -63,10 +63,13 @@ final class ArcanistPyLintLinter extends ArcanistLinter {
if (!$error_regexp && !$warning_regexp && !$advice_regexp) { if (!$error_regexp && !$warning_regexp && !$advice_regexp) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"You are invoking the PyLint linter but have not configured any of ". pht(
"'lint.pylint.codes.error', 'lint.pylint.codes.warning', or ". "You are invoking the PyLint linter but have not configured any of ".
"'lint.pylint.codes.advice'. Consult the documentation for ". "'%s', '%s', or '%s'. Consult the documentation for %s.",
"ArcanistPyLintLinter."); 'lint.pylint.codes.error',
'lint.pylint.codes.warning',
'lint.pylint.codes.advice',
__CLASS__));
} }
$code_map = array( $code_map = array(
@ -109,10 +112,13 @@ final class ArcanistPyLintLinter extends ArcanistLinter {
list($err) = exec_manual('which %s', $pylint_bin); list($err) = exec_manual('which %s', $pylint_bin);
if ($err) { if ($err) {
throw new ArcanistMissingLinterException( throw new ArcanistMissingLinterException(
"PyLint does not appear to be installed on this system. Install it ". pht(
"(e.g., with 'sudo easy_install pylint') or configure ". "PyLint does not appear to be installed on this system. Install ".
"'lint.pylint.prefix' in your .arcconfig to point to the directory ". "it (e.g., with '%s') or configure '%s' in your %s to point to ".
"where it resides."); "the directory where it resides.",
'sudo easy_install pylint',
'lint.pylint.prefix',
'.arcconfig'));
} }
} }

View file

@ -99,9 +99,9 @@ final class ArcanistRuboCopLinter extends ArcanistExternalLinter {
return $messages; return $messages;
} }
/* /**
Take the string from RuboCop's severity terminology and return an * Take the string from RuboCop's severity terminology and return an
ArcanistLintSeverity * @{class:ArcanistLintSeverity}.
*/ */
protected function getDefaultMessageSeverity($code) { protected function getDefaultMessageSeverity($code) {
switch ($code) { switch ($code) {

View file

@ -14,7 +14,9 @@ final class ArcanistRubyLinter extends ArcanistExternalLinter {
} }
public function getInfoDescription() { public function getInfoDescription() {
return pht('Use `ruby` to check for syntax errors in Ruby source files.'); return pht(
'Use `%s` to check for syntax errors in Ruby source files.',
'ruby');
} }
public function getLinterName() { public function getLinterName() {
@ -47,7 +49,7 @@ final class ArcanistRubyLinter extends ArcanistExternalLinter {
} }
public function getInstallInstructions() { public function getInstallInstructions() {
return pht('Install `ruby` from <http://www.ruby-lang.org/>.'); return pht('Install `%s` from <%s>.', 'ruby', 'http://www.ruby-lang.org/');
} }
protected function getMandatoryFlags() { protected function getMandatoryFlags() {

View file

@ -256,7 +256,7 @@ final class ArcanistScriptAndRegexLinter extends ArcanistLinter {
'code' => idx($match, 'code', $this->getLinterName()), 'code' => idx($match, 'code', $this->getLinterName()),
'severity' => $this->getMatchSeverity($match), 'severity' => $this->getMatchSeverity($match),
'name' => idx($match, 'name', 'Lint'), 'name' => idx($match, 'name', 'Lint'),
'description' => idx($match, 'message', 'Undefined Lint Message'), 'description' => idx($match, 'message', pht('Undefined Lint Message')),
); );
$original = idx($match, 'original'); $original = idx($match, 'original');

View file

@ -45,7 +45,7 @@ final class ArcanistXMLLinter extends ArcanistLinter {
->setLine($error->line) ->setLine($error->line)
->setChar($error->column ? $error->column : null) ->setChar($error->column ? $error->column : null)
->setCode($this->getLintMessageFullCode($error->code)) ->setCode($this->getLintMessageFullCode($error->code))
->setName('LibXML Error') ->setName(pht('LibXML Error'))
->setDescription(trim($error->message)); ->setDescription(trim($error->message));
switch ($error->level) { switch ($error->level) {

View file

@ -4,7 +4,7 @@ final class ArcanistCppcheckLinterTestCase
extends ArcanistExternalLinterTestCase { extends ArcanistExternalLinterTestCase {
public function testLinter() { public function testLinter() {
return $this->executeTestsInDirectory(dirname(__FILE__).'/cppcheck/'); $this->executeTestsInDirectory(dirname(__FILE__).'/cppcheck/');
} }
} }

View file

@ -4,7 +4,7 @@ final class ArcanistCpplintLinterTestCase
extends ArcanistExternalLinterTestCase { extends ArcanistExternalLinterTestCase {
public function testLinter() { public function testLinter() {
return $this->executeTestsInDirectory(dirname(__FILE__).'/cpplint/'); $this->executeTestsInDirectory(dirname(__FILE__).'/cpplint/');
} }
} }

View file

@ -47,7 +47,10 @@ abstract class ArcanistLinterTestCase extends ArcanistPhutilTestCase {
$this->assertTrue( $this->assertTrue(
($test_count > 0), ($test_count > 0),
pht('Expected to find some .lint-test tests in directory %s!', $root)); pht(
'Expected to find some %s tests in directory %s!',
'.lint-test',
$root));
} }
private function lintFile($file, ArcanistLinter $linter) { private function lintFile($file, ArcanistLinter $linter) {

View file

@ -3,7 +3,7 @@
final class ArcanistNoLintLinterTestCase extends ArcanistLinterTestCase { final class ArcanistNoLintLinterTestCase extends ArcanistLinterTestCase {
public function testLinter() { public function testLinter() {
return $this->executeTestsInDirectory(dirname(__FILE__).'/nolint/'); $this->executeTestsInDirectory(dirname(__FILE__).'/nolint/');
} }
} }

View file

@ -5,7 +5,7 @@ final class ArcanistPhutilXHPASTLinterTestCase extends ArcanistLinterTestCase {
public function testLinter() { public function testLinter() {
$linter = new ArcanistPhutilXHPASTLinter(); $linter = new ArcanistPhutilXHPASTLinter();
$linter->setDeprecatedFunctions(array( $linter->setDeprecatedFunctions(array(
'deprecated_function' => 'This function is most likely deprecated.', 'deprecated_function' => pht('This function is most likely deprecated.'),
)); ));
$this->executeTestsInDirectory(dirname(__FILE__).'/phlxhp/', $linter); $this->executeTestsInDirectory(dirname(__FILE__).'/phlxhp/', $linter);

View file

@ -4,7 +4,7 @@ final class ArcanistPyLintLinterTestCase
extends ArcanistExternalLinterTestCase { extends ArcanistExternalLinterTestCase {
public function testLinter() { public function testLinter() {
return $this->executeTestsInDirectory(dirname(__FILE__).'/pylint/'); $this->executeTestsInDirectory(dirname(__FILE__).'/pylint/');
} }
} }

View file

@ -44,7 +44,9 @@ final class ArcanistConsoleLintRenderer extends ArcanistLintRenderer {
idx($location, 'path', $path). idx($location, 'path', $path).
(!empty($location['line']) ? ":{$location['line']}" : ''); (!empty($location['line']) ? ":{$location['line']}" : '');
} }
$description .= "\nOther locations: ".implode(', ', $locations); $description .= "\n".pht(
'Other locations: %s',
implode(', ', $locations));
} }
$text[] = phutil_console_format( $text[] = phutil_console_format(
@ -60,7 +62,11 @@ final class ArcanistConsoleLintRenderer extends ArcanistLintRenderer {
} }
if ($text) { if ($text) {
$prefix = phutil_console_format("**>>>** Lint for __%s__:\n\n\n", $path); $prefix = phutil_console_format(
"**>>>** %s\n\n\n",
pht(
'Lint for %s:',
phutil_console_format('__%s__', $path)));
return $prefix.implode("\n", $text); return $prefix.implode("\n", $text);
} else { } else {
return null; return null;
@ -234,7 +240,9 @@ final class ArcanistConsoleLintRenderer extends ArcanistLintRenderer {
public function renderOkayResult() { public function renderOkayResult() {
return phutil_console_format( return phutil_console_format(
"<bg:green>** OKAY **</bg> No lint warnings.\n"); "<bg:green>** %s **</bg> %s\n",
pht('OKAY'),
pht('No lint warnings.'));
} }
} }

View file

@ -24,7 +24,9 @@ final class ArcanistSummaryLintRenderer extends ArcanistLintRenderer {
public function renderOkayResult() { public function renderOkayResult() {
return phutil_console_format( return phutil_console_format(
"<bg:green>** OKAY **</bg> No lint warnings.\n"); "<bg:green>** %s **</bg> %s\n",
pht('OKAY'),
pht('No lint warnings.'));
} }
} }

View file

@ -22,8 +22,10 @@ final class ArcanistBaseCommitParser {
foreach ($spec as $rule) { foreach ($spec as $rule) {
if (strpos($rule, ':') === false) { if (strpos($rule, ':') === false) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Rule '{$rule}' is invalid, it must have a type and name like ". pht(
"'arc:upstream'."); "Rule '%s' is invalid, it must have a type and name like '%s'.",
$rule,
'arc:upstream'));
} }
} }
@ -61,16 +63,16 @@ final class ArcanistBaseCommitParser {
$source = head($this->try); $source = head($this->try);
if (!idx($specs, $source)) { if (!idx($specs, $source)) {
$this->log("No rules left from source '{$source}'."); $this->log(pht("No rules left from source '%s'.", $source));
array_shift($this->try); array_shift($this->try);
continue; continue;
} }
$this->log("Trying rules from source '{$source}'."); $this->log(pht("Trying rules from source '%s'.", $source));
$rules = &$specs[$source]; $rules = &$specs[$source];
while ($rule = array_shift($rules)) { while ($rule = array_shift($rules)) {
$this->log("Trying rule '{$rule}'."); $this->log(pht("Trying rule '%s'.", $rule));
$commit = $this->resolveRule($rule, $source); $commit = $this->resolveRule($rule, $source);
@ -78,7 +80,10 @@ final class ArcanistBaseCommitParser {
// If a rule returns false, it means to go to the next ruleset. // If a rule returns false, it means to go to the next ruleset.
break; break;
} else if ($commit !== null) { } else if ($commit !== null) {
$this->log("Resolved commit '{$commit}' from rule '{$rule}'."); $this->log(pht(
"Resolved commit '%s' from rule '%s'.",
$commit,
$rule));
return $commit; return $commit;
} }
} }
@ -105,8 +110,11 @@ final class ArcanistBaseCommitParser {
return $this->resolveArcRule($rule, $name, $source); return $this->resolveArcRule($rule, $name, $source);
default: default:
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Base commit rule '{$rule}' (from source '{$source}') ". pht(
"is not a recognized rule."); "Base commit rule '%s' (from source '%s') ".
"is not a recognized rule.",
$rule,
$source));
} }
} }
@ -120,12 +128,12 @@ final class ArcanistBaseCommitParser {
switch ($name) { switch ($name) {
case 'verbose': case 'verbose':
$this->verbose = true; $this->verbose = true;
$this->log('Enabled verbose mode.'); $this->log(pht('Enabled verbose mode.'));
break; break;
case 'prompt': case 'prompt':
$reason = 'it is what you typed when prompted.'; $reason = pht('it is what you typed when prompted.');
$this->api->setBaseCommitExplanation($reason); $this->api->setBaseCommitExplanation($reason);
return phutil_console_prompt('Against which commit?'); return phutil_console_prompt(pht('Against which commit?'));
case 'local': case 'local':
case 'user': case 'user':
case 'project': case 'project':
@ -133,17 +141,17 @@ final class ArcanistBaseCommitParser {
case 'system': case 'system':
// Push the other source on top of the list. // Push the other source on top of the list.
array_unshift($this->try, $name); array_unshift($this->try, $name);
$this->log("Switching to source '{$name}'."); $this->log(pht("Switching to source '%s'.", $name));
return false; return false;
case 'yield': case 'yield':
// Cycle this source to the end of the list. // Cycle this source to the end of the list.
$this->try[] = array_shift($this->try); $this->try[] = array_shift($this->try);
$this->log("Yielding processing of rules from '{$source}'."); $this->log(pht("Yielding processing of rules from '%s'.", $source));
return false; return false;
case 'halt': case 'halt':
// Dump the whole stack. // Dump the whole stack.
$this->try = array(); $this->try = array();
$this->log('Halting all rule processing.'); $this->log(pht('Halting all rule processing.'));
return false; return false;
case 'skip': case 'skip':
return null; return null;
@ -171,8 +179,11 @@ final class ArcanistBaseCommitParser {
} }
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Base commit rule '{$rule}' (from source '{$source}') ". pht(
"is not a recognized rule."); "Base commit rule '%s' (from source '%s') ".
"is not a recognized rule.",
$rule,
$source));
} }
} }
@ -183,7 +194,7 @@ final class ArcanistBaseCommitParser {
); );
$new_name = idx($updated, $name); $new_name = idx($updated, $name);
if ($new_name) { if ($new_name) {
$this->log("translating legacy name '$name' to '$new_name'"); $this->log(pht("Translating legacy name '%s' to '%s'", $name, $new_name));
return $new_name; return $new_name;
} }
return $name; return $name;

View file

@ -124,7 +124,7 @@ final class ArcanistBundle {
return phutil_is_windows() ? "\r\n" : "\n"; return phutil_is_windows() ? "\r\n" : "\n";
default: default:
throw new Exception( throw new Exception(
"Unknown patch type '{$patch_type}'!"); pht("Unknown patch type '%s'!", $patch_type));
} }
} }
@ -373,7 +373,9 @@ final class ArcanistBundle {
if (!$decompose_okay) { if (!$decompose_okay) {
throw new Exception( throw new Exception(
'Failed to decompose multicopy changeset in order to generate diff.'); pht(
'Failed to decompose multicopy changeset in '.
'order to generate diff.'));
} }
} }
@ -687,9 +689,11 @@ final class ArcanistBundle {
if ($this->conduit) { if ($this->conduit) {
if ($name) { if ($name) {
$console->writeErr("Downloading binary data for '%s'...\n", $name); $console->writeErr(
"%s\n",
pht("Downloading binary data for '%s'...", $name));
} else { } else {
$console->writeErr("Downloading binary data...\n"); $console->writeErr("%s\n", pht('Downloading binary data...'));
} }
$data_base64 = $this->conduit->callMethodSynchronous( $data_base64 = $this->conduit->callMethodSynchronous(
'file.download', 'file.download',
@ -699,7 +703,7 @@ final class ArcanistBundle {
return base64_decode($data_base64); return base64_decode($data_base64);
} }
throw new Exception("Nowhere to load blob '{$phid}' from!"); throw new Exception(pht("Nowhere to load blob '%s' from!", $phid));
} }
private function buildBinaryChange(ArcanistDiffChange $change, $old_binary) { private function buildBinaryChange(ArcanistDiffChange $change, $old_binary) {
@ -773,9 +777,10 @@ final class ArcanistBundle {
if (!function_exists('gzcompress')) { if (!function_exists('gzcompress')) {
throw new Exception( throw new Exception(
'This patch has binary data. The PHP zlib extension is required to '. pht(
'apply patches with binary data to git. Install the PHP zlib '. 'This patch has binary data. The PHP zlib extension is required to '.
'extension to continue.'); 'apply patches with binary data to git. Install the PHP zlib '.
'extension to continue.'));
} }
// See emit_binary_diff_body() in diff.c for git's implementation. // See emit_binary_diff_body() in diff.c for git's implementation.

View file

@ -165,7 +165,7 @@ final class ArcanistDiffParser {
$origin->setType(ArcanistDiffChangeType::TYPE_COPY_AWAY); $origin->setType(ArcanistDiffChangeType::TYPE_COPY_AWAY);
break; break;
default: default:
throw new Exception("Bad origin state {$type}."); throw new Exception(pht('Bad origin state %s.', $type));
} }
$type = $origin->getType(); $type = $origin->getType();
@ -179,7 +179,7 @@ final class ArcanistDiffParser {
$change->setType(ArcanistDiffChangeType::TYPE_COPY_HERE); $change->setType(ArcanistDiffChangeType::TYPE_COPY_HERE);
break; break;
default: default:
throw new Exception("Bad origin state {$type}."); throw new Exception(pht('Bad origin state %s.', $type));
} }
} }
@ -188,7 +188,7 @@ final class ArcanistDiffParser {
public function parseDiff($diff) { public function parseDiff($diff) {
if (!strlen(trim($diff))) { if (!strlen(trim($diff))) {
throw new Exception("Can't parse an empty diff!"); throw new Exception(pht("Can't parse an empty diff!"));
} }
// Detect `git-format-patch`, by looking for a "---" line somewhere in // Detect `git-format-patch`, by looking for a "---" line somewhere in
@ -274,11 +274,16 @@ final class ArcanistDiffParser {
if ($failed_parse) { if ($failed_parse) {
$this->didFailParse( $this->didFailParse(
"Expected a hunk header, like 'Index: /path/to/file.ext' (svn), ". pht(
"'Property changes on: /path/to/file.ext' (svn properties), ". "Expected a hunk header, like '%s' (svn), '%s' (svn properties), ".
"'commit 59bcc3ad6775562f845953cf01624225' (git show), ". "'%s' (git show), '%s' (git diff), '%s' (unified diff), or ".
"'diff --git' (git diff), '--- filename' (unified diff), or ". "'%s' (hg diff or patch).",
"'diff -r' (hg diff or patch)."); 'Index: /path/to/file.ext',
'Property changes on: /path/to/file.ext',
'commit 59bcc3ad6775562f845953cf01624225',
'diff --git',
'--- filename',
'diff -r'));
} }
if (isset($match['type'])) { if (isset($match['type'])) {
@ -332,7 +337,9 @@ final class ArcanistDiffParser {
$line, $line,
$match); $match);
if (!$ok) { if (!$ok) {
$this->didFailParse("Expected '+++ filename' in unified diff."); $this->didFailParse(pht(
"Expected '%s' in unified diff.",
'+++ filename'));
} }
$change->setCurrentPath($match[1]); $change->setCurrentPath($match[1]);
$line = $this->nextLine(); $line = $this->nextLine();
@ -347,7 +354,7 @@ final class ArcanistDiffParser {
$this->parseIndexHunk($change); $this->parseIndexHunk($change);
break; break;
default: default:
$this->didFailParse('Unknown diff type.'); $this->didFailParse(pht('Unknown diff type.'));
break; break;
} }
} while ($this->getLine() !== null); } while ($this->getLine() !== null);
@ -380,12 +387,12 @@ final class ArcanistDiffParser {
$line = $this->getLine(); $line = $this->getLine();
if (!preg_match('/^Author: /', $line)) { if (!preg_match('/^Author: /', $line)) {
$this->didFailParse("Expected 'Author:'."); $this->didFailParse(pht("Expected 'Author:'."));
} }
$line = $this->nextLine(); $line = $this->nextLine();
if (!preg_match('/^Date: /', $line)) { if (!preg_match('/^Date: /', $line)) {
$this->didFailParse("Expected 'Date:'."); $this->didFailParse(pht("Expected 'Date:'."));
} }
while (($line = $this->nextLineTrimmed()) !== null) { while (($line = $this->nextLineTrimmed()) !== null) {
@ -410,7 +417,7 @@ final class ArcanistDiffParser {
protected function parsePropertyHunk(ArcanistDiffChange $change) { protected function parsePropertyHunk(ArcanistDiffChange $change) {
$line = $this->getLineTrimmed(); $line = $this->getLineTrimmed();
if (!preg_match('/^_+$/', $line)) { if (!preg_match('/^_+$/', $line)) {
$this->didFailParse("Expected '______________________'."); $this->didFailParse(pht("Expected '%s'.", '______________________'));
} }
$line = $this->nextLine(); $line = $this->nextLine();
@ -430,7 +437,7 @@ final class ArcanistDiffParser {
$matches); $matches);
if (!$ok) { if (!$ok) {
$this->didFailParse( $this->didFailParse(
"Expected 'Name', 'Added', 'Deleted', or 'Modified'."); pht("Expected 'Name', 'Added', 'Deleted', or 'Modified'."));
} }
$op = $matches[1]; $op = $matches[1];
@ -476,13 +483,17 @@ final class ArcanistDiffParser {
} }
if ($trimline && $trimline[0] == '+') { if ($trimline && $trimline[0] == '+') {
if ($op == 'Deleted') { if ($op == 'Deleted') {
$this->didFailParse('Unexpected "+" section in property deletion.'); $this->didFailParse(pht(
'Unexpected "%s" section in property deletion.',
'+'));
} }
$target = 'new'; $target = 'new';
$line = substr($trimline, $prop_index); $line = substr($trimline, $prop_index);
} else if ($trimline && $trimline[0] == '-') { } else if ($trimline && $trimline[0] == '-') {
if ($op == 'Added') { if ($op == 'Added') {
$this->didFailParse('Unexpected "-" section in property addition.'); $this->didFailParse(pht(
'Unexpected "%s" section in property addition.',
'-'));
} }
$target = 'old'; $target = 'old';
$line = substr($trimline, $prop_index); $line = substr($trimline, $prop_index);
@ -523,7 +534,7 @@ final class ArcanistDiffParser {
protected function setIsGit($git) { protected function setIsGit($git) {
if ($this->isGit !== null && $this->isGit != $git) { if ($this->isGit !== null && $this->isGit != $git) {
throw new Exception('Git status has changed!'); throw new Exception(pht('Git status has changed!'));
} }
$this->isGit = $git; $this->isGit = $git;
return $this; return $this;
@ -682,7 +693,9 @@ final class ArcanistDiffParser {
if ($is_svn) { if ($is_svn) {
$ok = preg_match('/^=+\s*$/', $line); $ok = preg_match('/^=+\s*$/', $line);
if (!$ok) { if (!$ok) {
$this->didFailParse("Expected '=======================' divider line."); $this->didFailParse(pht(
"Expected '%s' divider line.",
'======================='));
} else { } else {
// Adding an empty file in SVN can produce an empty line here. // Adding an empty file in SVN can produce an empty line here.
$line = $this->nextNonemptyLine(); $line = $this->nextNonemptyLine();
@ -803,7 +816,8 @@ final class ArcanistDiffParser {
$line = $this->getLine(); $line = $this->getLine();
if (!preg_match('/^literal /', $line)) { if (!preg_match('/^literal /', $line)) {
$this->didFailParse("Expected 'literal NNNN' to start git binary patch."); $this->didFailParse(
pht("Expected '%s' to start git binary patch.", 'literal NNNN'));
} }
do { do {
$line = $this->nextLineTrimmed(); $line = $this->nextLineTrimmed();
@ -814,7 +828,8 @@ final class ArcanistDiffParser {
$this->nextNonemptyLine(); $this->nextNonemptyLine();
return; return;
} else if (!preg_match('/^[a-zA-Z]/', $line)) { } else if (!preg_match('/^[a-zA-Z]/', $line)) {
$this->didFailParse('Expected base85 line length character (a-zA-Z).'); $this->didFailParse(
pht('Expected base85 line length character (a-zA-Z).'));
} }
} while (true); } while (true);
} }
@ -843,7 +858,9 @@ final class ArcanistDiffParser {
if (!$ok) { if (!$ok) {
$this->didFailParse( $this->didFailParse(
"Expected hunk target '+++ path/to/file.ext (revision N)'."); pht(
"Expected hunk target '%s'.",
'+++ path/to/file.ext (revision N)'));
} }
$this->nextLine(); $this->nextLine();
@ -887,12 +904,14 @@ final class ArcanistDiffParser {
$line = $this->nextNonemptyLine(); $line = $this->nextNonemptyLine();
$ok = preg_match('/^Property changes on:/', $line); $ok = preg_match('/^Property changes on:/', $line);
if (!$ok) { if (!$ok) {
$this->didFailParse('Confused by empty line'); $this->didFailParse(pht('Confused by empty line'));
} }
$line = $this->nextLine(); $line = $this->nextLine();
return $this->parsePropertyHunk($change); return $this->parsePropertyHunk($change);
} }
$this->didFailParse("Expected hunk header '@@ -NN,NN +NN,NN @@'."); $this->didFailParse(pht(
"Expected hunk header '%s'.",
'@@ -NN,NN +NN,NN @@'));
} }
$hunk->setOldOffset($matches[1]); $hunk->setOldOffset($matches[1]);
@ -930,7 +949,7 @@ final class ArcanistDiffParser {
case '\\': case '\\':
if (!preg_match('@\\ No newline at end of file@', $line)) { if (!preg_match('@\\ No newline at end of file@', $line)) {
$this->didFailParse( $this->didFailParse(
"Expected '\ No newline at end of file'."); pht("Expected '\ No newline at end of file'."));
} }
if ($new_len) { if ($new_len) {
$real[] = $line; $real[] = $line;
@ -975,7 +994,7 @@ final class ArcanistDiffParser {
} }
if ($old_len || $new_len) { if ($old_len || $new_len) {
$this->didFailParse('Found the wrong number of hunk lines.'); $this->didFailParse(pht('Found the wrong number of hunk lines.'));
} }
$corpus = implode('', $real); $corpus = implode('', $real);
@ -991,8 +1010,10 @@ final class ArcanistDiffParser {
$corpus = phutil_utf8_convert($corpus, 'UTF-8', $try_encoding); $corpus = phutil_utf8_convert($corpus, 'UTF-8', $try_encoding);
if (!phutil_is_utf8($corpus)) { if (!phutil_is_utf8($corpus)) {
throw new Exception( throw new Exception(
"Failed to convert a hunk from '{$try_encoding}' to UTF-8. ". pht(
"Check that the specified encoding is correct."); "Failed to convert a hunk from '%s' to UTF-8. ".
"Check that the specified encoding is correct.",
$try_encoding));
} }
} }
} }
@ -1362,11 +1383,13 @@ final class ArcanistDiffParser {
if (!$matches) { if (!$matches) {
throw new Exception( throw new Exception(
"Input diff contains ambiguous line 'diff --git {$paths}'. This line ". pht(
"is ambiguous because there are spaces in the file names, so the ". "Input diff contains ambiguous line '%s'. This line is ambiguous ".
"parser can not determine where the file names begin and end. To ". "because there are spaces in the file names, so the parser can not ".
"resolve this ambiguity, use standard prefixes ('a/' and 'b/') when ". "determine where the file names begin and end. To resolve this ".
"generating diffs."); "ambiguity, use standard prefixes ('a/' and 'b/') when ".
"generating diffs.",
"diff --git {$paths}"));
} }
$old = $matches['old']; $old = $matches['old'];

View file

@ -20,7 +20,11 @@ final class ArcanistBundleTestCase extends ArcanistTestCase {
$this->assertEqual( $this->assertEqual(
1, 1,
$err, $err,
"Expect `diff` to find changes between '{$old}' and '{$new}'."); pht(
"Expect `%s` to find changes between '%s' and '%s'.",
'diff',
$old,
$new));
return $stdout; return $stdout;
} }
@ -36,7 +40,7 @@ final class ArcanistBundleTestCase extends ArcanistTestCase {
*/ */
public function testGitRepository() { public function testGitRepository() {
if (phutil_is_windows()) { if (phutil_is_windows()) {
$this->assertSkipped('This test is not supported under Windows.'); $this->assertSkipped(pht('This test is not supported under Windows.'));
} }
$archive = dirname(__FILE__).'/bundle.git.tgz'; $archive = dirname(__FILE__).'/bundle.git.tgz';
@ -111,8 +115,11 @@ final class ArcanistBundleTestCase extends ArcanistTestCase {
} else { } else {
Filesystem::writeFile($expect_path.'.real', $patch); Filesystem::writeFile($expect_path.'.real', $patch);
throw new Exception( throw new Exception(
"Expected patch and actual patch for {$commit_hash} differ. ". pht(
"Wrote actual patch to '{$expect_path}.real'."); "Expected patch and actual patch for %s differ. ".
"Wrote actual patch to '%s.real'.",
$commit_hash,
$expect_path));
} }
try { try {
@ -125,8 +132,8 @@ final class ArcanistBundleTestCase extends ArcanistTestCase {
Filesystem::writeFile($temp, $patch); Filesystem::writeFile($temp, $patch);
PhutilConsole::getConsole()->writeErr( PhutilConsole::getConsole()->writeErr(
"Wrote failing patch to '%s'.\n", "%s\n",
$temp); pht("Wrote failing patch to '%s'.", $temp));
throw $ex; throw $ex;
} }
@ -137,7 +144,7 @@ final class ArcanistBundleTestCase extends ArcanistTestCase {
$this->assertEqual( $this->assertEqual(
$tree_hash, $tree_hash,
$result_hash, $result_hash,
"Commit {$commit_hash}: {$subject}"); pht('Commit %s: %s', $commit_hash, $subject));
} }
} }
@ -569,11 +576,11 @@ final class ArcanistBundleTestCase extends ArcanistTestCase {
case '228d7be4840313ed805c25c15bba0f7b188af3e6': case '228d7be4840313ed805c25c15bba0f7b188af3e6':
// "Add a text file." // "Add a text file."
// This commit is never reached because we skip the 0th commit junk. // This commit is never reached because we skip the 0th commit junk.
$this->assertTrue(true, 'This is never reached.'); $this->assertTrue(true, pht('This is never reached.'));
break; break;
default: default:
throw new Exception( throw new Exception(
"Commit {$commit} has no change assertions!"); pht('Commit %s has no change assertions!', $commit));
} }
} }

View file

@ -602,7 +602,7 @@ EOTEXT
$this->assertEqual('file with spaces.txt', $change->getOldPath()); $this->assertEqual('file with spaces.txt', $change->getOldPath());
break; break;
default: default:
throw new Exception("No test block for diff file {$diff_file}."); throw new Exception(pht('No test block for diff file %s.', $diff_file));
break; break;
} }
} }
@ -625,7 +625,7 @@ EOTEXT
$this->assertEqual( $this->assertEqual(
$expect, $expect,
ArcanistDiffParser::stripGitPathPrefix($input), ArcanistDiffParser::stripGitPathPrefix($input),
"Strip git prefix from '{$input}'."); pht("Strip git prefix from '%s'.", $input));
} }
} }
@ -663,7 +663,7 @@ EOTEXT
$this->assertEqual( $this->assertEqual(
$expect, $expect,
$result, $result,
"Split: {$input}"); pht('Split: %s', $input));
} }
@ -680,7 +680,7 @@ EOTEXT
} }
$this->assertTrue( $this->assertTrue(
($caught instanceof Exception), ($caught instanceof Exception),
"Ambiguous: {$input}"); pht('Ambiguous: %s', $input));
} }
} }

View file

@ -292,14 +292,14 @@ final class ArcanistDiffChange {
public function getSymlinkTarget() { public function getSymlinkTarget() {
if ($this->getFileType() != ArcanistDiffChangeType::FILE_SYMLINK) { if ($this->getFileType() != ArcanistDiffChangeType::FILE_SYMLINK) {
throw new Exception('Not a symlink!'); throw new Exception(pht('Not a symlink!'));
} }
$hunks = $this->getHunks(); $hunks = $this->getHunks();
$hunk = reset($hunks); $hunk = reset($hunks);
$corpus = $hunk->getCorpus(); $corpus = $hunk->getCorpus();
$match = null; $match = null;
if (!preg_match('/^\+(?:link )?(.*)$/m', $corpus, $match)) { if (!preg_match('/^\+(?:link )?(.*)$/m', $corpus, $match)) {
throw new Exception('Failed to extract link target!'); throw new Exception(pht('Failed to extract link target!'));
} }
return trim($match[1]); return trim($match[1]);
} }

View file

@ -94,19 +94,24 @@ final class ArcanistDiffChangeType {
} }
public static function getFullNameForChangeType($type) { public static function getFullNameForChangeType($type) {
static $types = array( static $types = null;
self::TYPE_ADD => 'Added',
self::TYPE_CHANGE => 'Modified', if ($types === null) {
self::TYPE_DELETE => 'Deleted', $types = array(
self::TYPE_MOVE_AWAY => 'Moved Away', self::TYPE_ADD => pht('Added'),
self::TYPE_COPY_AWAY => 'Copied Away', self::TYPE_CHANGE => pht('Modified'),
self::TYPE_MOVE_HERE => 'Moved Here', self::TYPE_DELETE => pht('Deleted'),
self::TYPE_COPY_HERE => 'Copied Here', self::TYPE_MOVE_AWAY => pht('Moved Away'),
self::TYPE_MULTICOPY => 'Deleted After Multiple Copy', self::TYPE_COPY_AWAY => pht('Copied Away'),
self::TYPE_MESSAGE => 'Commit Message', self::TYPE_MOVE_HERE => pht('Moved Here'),
self::TYPE_CHILD => 'Contents Modified', self::TYPE_COPY_HERE => pht('Copied Here'),
); self::TYPE_MULTICOPY => pht('Deleted After Multiple Copy'),
return idx($types, coalesce($type, '?'), 'Unknown'); self::TYPE_MESSAGE => pht('Commit Message'),
self::TYPE_CHILD => pht('Contents Modified'),
);
}
return idx($types, coalesce($type, '?'), pht('Unknown'));
} }
} }

View file

@ -83,7 +83,7 @@ final class ArcanistDiffHunk {
case 'cover': case 'cover':
return $cover_map; return $cover_map;
default: default:
throw new Exception("Unknown line change type '{$type}'."); throw new Exception(pht("Unknown line change type '%s'.", $type));
} }
} }

View file

@ -92,8 +92,9 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
if ($this->repositoryHasNoCommits) { if ($this->repositoryHasNoCommits) {
// Zero commits. // Zero commits.
throw new Exception( throw new Exception(
"You can't get local commit information for a repository with no ". pht(
"commits."); "You can't get local commit information for a repository with no ".
"commits."));
} else if ($this->getBaseCommit() == self::GIT_MAGIC_ROOT_COMMIT) { } else if ($this->getBaseCommit() == self::GIT_MAGIC_ROOT_COMMIT) {
// One commit. // One commit.
$against = 'HEAD'; $against = 'HEAD';
@ -200,7 +201,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
if ($symbolic_commit !== null) { if ($symbolic_commit !== null) {
if ($symbolic_commit == self::GIT_MAGIC_ROOT_COMMIT) { if ($symbolic_commit == self::GIT_MAGIC_ROOT_COMMIT) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
'you explicitly specified the empty tree.'); pht('you explicitly specified the empty tree.'));
return $symbolic_commit; return $symbolic_commit;
} }
@ -210,19 +211,24 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$this->getHeadCommit()); $this->getHeadCommit());
if ($err) { if ($err) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Unable to find any git commit named '{$symbolic_commit}' in ". pht(
"this repository."); "Unable to find any git commit named '%s' in this repository.",
$symbolic_commit));
} }
if ($this->symbolicHeadCommit === null) { if ($this->symbolicHeadCommit === null) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the merge-base of the explicitly specified base commit ". pht(
"'{$symbolic_commit}' and HEAD."); "it is the merge-base of the explicitly specified base commit ".
"'%s' and HEAD.",
$symbolic_commit));
} else { } else {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the merge-base of the explicitly specified base commit ". pht(
"'{$symbolic_commit}' and the explicitly specified head ". "it is the merge-base of the explicitly specified base commit ".
"commit '{$this->symbolicHeadCommit}'."); "'%s' and the explicitly specified head commit '%s'.",
$symbolic_commit,
$this->symbolicHeadCommit));
} }
return trim($merge_base); return trim($merge_base);
@ -239,11 +245,10 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
} }
if ($this->repositoryHasNoCommits) { if ($this->repositoryHasNoCommits) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(pht('the repository has no commits.'));
'the repository has no commits.');
} else { } else {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
'the repository has only one commit.'); pht('the repository has only one commit.'));
} }
return self::GIT_MAGIC_ROOT_COMMIT; return self::GIT_MAGIC_ROOT_COMMIT;
@ -254,9 +259,10 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$base = $this->resolveBaseCommit(); $base = $this->resolveBaseCommit();
if (!$base) { if (!$base) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"None of the rules in your 'base' configuration matched a valid ". pht(
"commit. Adjust rules or specify which commit you want to use ". "None of the rules in your 'base' configuration matched a valid ".
"explicitly."); "commit. Adjust rules or specify which commit you want to use ".
"explicitly."));
} }
return $base; return $base;
} }
@ -268,9 +274,12 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$default_relative = $working_copy->getProjectConfig( $default_relative = $working_copy->getProjectConfig(
'git.default-relative-commit'); 'git.default-relative-commit');
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the merge-base of '{$default_relative}' and HEAD, as ". pht(
"specified in 'git.default-relative-commit' in '.arcconfig'. This ". "it is the merge-base of '%s' and HEAD, as specified in '%s' in ".
"setting overrides other settings."); "'%s'. This setting overrides other settings.",
$default_relative,
'git.default-relative-commit',
'.arcconfig'));
} }
if (!$default_relative) { if (!$default_relative) {
@ -281,8 +290,10 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
if (!$err) { if (!$err) {
$default_relative = trim($upstream); $default_relative = trim($upstream);
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the merge-base of '{$default_relative}' (the Git upstream ". pht(
"of the current branch) HEAD."); "it is the merge-base of '%s' (the Git upstream ".
"of the current branch) HEAD.",
$default_relative));
} }
} }
@ -291,8 +302,10 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$default_relative = trim($default_relative); $default_relative = trim($default_relative);
if ($default_relative) { if ($default_relative) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the merge-base of '{$default_relative}' and HEAD, as ". pht(
"specified in '.git/arc/default-relative-commit'."); "it is the merge-base of '%s' and HEAD, as specified in '%s'.",
$default_relative,
'.git/arc/default-relative-commit'));
} }
} }
@ -303,23 +316,30 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
echo phutil_console_format( echo phutil_console_format(
"<bg:green>** Select a Default Commit Range **</bg>\n\n"); "<bg:green>** Select a Default Commit Range **</bg>\n\n");
echo phutil_console_wrap( echo phutil_console_wrap(
"You're running a command which operates on a range of revisions ". pht(
"(usually, from some revision to HEAD) but have not specified the ". "You're running a command which operates on a range of revisions ".
"revision that should determine the start of the range.\n\n". "(usually, from some revision to HEAD) but have not specified the ".
"Previously, arc assumed you meant 'HEAD^' when you did not specify ". "revision that should determine the start of the range.\n\n".
"a start revision, but this behavior does not make much sense in ". "Previously, arc assumed you meant '%s' when you did not specify ".
"most workflows outside of Facebook's historic git-svn workflow.\n\n". "a start revision, but this behavior does not make much sense in ".
"arc no longer assumes 'HEAD^'. You must specify a relative commit ". "most workflows outside of Facebook's historic %s workflow.\n\n".
"explicitly when you invoke a command (e.g., `arc diff HEAD^`, not ". "arc no longer assumes '%s'. You must specify a relative commit ".
"just `arc diff`) or select a default for this working copy.\n\n". "explicitly when you invoke a command (e.g., `%s`, not just `%s`) ".
"In most cases, the best default is 'origin/master'. You can also ". "or select a default for this working copy.\n\nIn most cases, the ".
"select 'HEAD^' to preserve the old behavior, or some other remote ". "best default is '%s'. You can also select '%s' to preserve the ".
"or branch. But you almost certainly want to select ". "old behavior, or some other remote or branch. But you almost ".
"'origin/master'.\n\n". "certainly want to select 'origin/master'.\n\n".
"(Technically: the merge-base of the selected revision and HEAD is ". "(Technically: the merge-base of the selected revision and HEAD is ".
"used to determine the start of the commit range.)"); "used to determine the start of the commit range.)",
'HEAD^',
'git-svn',
'HEAD^',
'arc diff HEAD^',
'arc diff',
'origin/master',
'HEAD^'));
$prompt = 'What default do you want to use? [origin/master]'; $prompt = pht('What default do you want to use? [origin/master]');
$default = phutil_console_prompt($prompt); $default = phutil_console_prompt($prompt);
if (!strlen(trim($default))) { if (!strlen(trim($default))) {
@ -336,7 +356,9 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
if (trim($object_type) !== 'commit') { if (trim($object_type) !== 'commit') {
throw new Exception( throw new Exception(
"Relative commit '{$default_relative}' is not the name of a commit!"); pht(
"Relative commit '%s' is not the name of a commit!",
$default_relative));
} }
if ($do_write) { if ($do_write) {
@ -344,8 +366,9 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
// valid commit name. // valid commit name.
$this->writeScratchFile('default-relative-commit', $default_relative); $this->writeScratchFile('default-relative-commit', $default_relative);
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the merge-base of '{$default_relative}' and HEAD, as you ". pht(
"just specified."); "it is the merge-base of '%s' and HEAD, as you just specified.",
$default_relative));
} }
list($merge_base) = $this->execxLocal( list($merge_base) = $this->execxLocal(
@ -382,8 +405,9 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
if ($err) { if ($err) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Unable to find any git commit named '{$symbolic_commit}' in ". pht(
"this repository."); "Unable to find any git commit named '%s' in this repository.",
$symbolic_commit));
} }
return trim($commit_hash); return trim($commit_hash);
@ -547,7 +571,10 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$input); $input);
if (!$stdout) { if (!$stdout) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Cannot find the {$vcs} equivalent of {$input}."); pht(
'Cannot find the %s equivalent of %s.',
$vcs,
$input));
} }
// When git performs a partial-rebuild during svn // When git performs a partial-rebuild during svn
// look-up, we need to parse the final line // look-up, we need to parse the final line
@ -777,7 +804,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$line, $line,
$matches); $matches);
if (!$ok) { if (!$ok) {
throw new Exception("Bad blame? `{$line}'"); throw new Exception(pht("Bad blame? `%s'", $line));
} }
$revision = $matches[1]; $revision = $matches[1];
$author = $matches[2]; $author = $matches[2];
@ -812,7 +839,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$line, $line,
$matches); $matches);
if (!$ok) { if (!$ok) {
throw new Exception('Failed to parse git ls-tree output!'); throw new Exception(pht('Failed to parse %s output!', 'git ls-tree'));
} }
$result[$matches[4]] = array( $result[$matches[4]] = array(
'mode' => $matches[1], 'mode' => $matches[1],
@ -937,7 +964,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
public function performLocalBranchMerge($branch, $message) { public function performLocalBranchMerge($branch, $message) {
if (!$branch) { if (!$branch) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'Under git, you must specify the branch you want to merge.'); pht('Under git, you must specify the branch you want to merge.'));
} }
$err = phutil_passthru( $err = phutil_passthru(
'(cd %s && git merge --no-ff -m %s %s)', '(cd %s && git merge --no-ff -m %s %s)',
@ -951,8 +978,11 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
} }
public function getFinalizedRevisionMessage() { public function getFinalizedRevisionMessage() {
return "You may now push this commit upstream, as appropriate (e.g. with ". return pht(
"'git push', or 'git svn dcommit', or by printing and faxing it)."; "You may now push this commit upstream, as appropriate (e.g. with ".
"'%s', or '%s', or by printing and faxing it).",
'git push',
'git svn dcommit');
} }
public function getCommitMessage($commit) { public function getCommitMessage($commit) {
@ -996,8 +1026,9 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
foreach ($results as $key => $result) { foreach ($results as $key => $result) {
$hash = substr($reason_map[$result['id']], 0, 16); $hash = substr($reason_map[$result['id']], 0, 16);
$results[$key]['why'] = $results[$key]['why'] = pht(
"Commit message for '{$hash}' has explicit 'Differential Revision'."; "Commit message for '%s' has explicit 'Differential Revision'.",
$hash);
} }
return $results; return $results;
@ -1017,9 +1048,9 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
)); ));
foreach ($results as $key => $result) { foreach ($results as $key => $result) {
$results[$key]['why'] = $results[$key]['why'] = pht(
'A git commit or tree hash in the commit range is already attached '. 'A git commit or tree hash in the commit range is already attached '.
'to the Differential revision.'; 'to the Differential revision.');
} }
return $results; return $results;
@ -1032,7 +1063,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
public function getCommitSummary($commit) { public function getCommitSummary($commit) {
if ($commit == self::GIT_MAGIC_ROOT_COMMIT) { if ($commit == self::GIT_MAGIC_ROOT_COMMIT) {
return '(The Empty Tree)'; return pht('(The Empty Tree)');
} }
list($summary) = $this->execxLocal( list($summary) = $this->execxLocal(
@ -1044,17 +1075,16 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
} }
public function backoutCommit($commit_hash) { public function backoutCommit($commit_hash) {
$this->execxLocal( $this->execxLocal('revert %s -n --no-edit', $commit_hash);
'revert %s -n --no-edit', $commit_hash);
$this->reloadWorkingCopy(); $this->reloadWorkingCopy();
if (!$this->getUncommittedStatus()) { if (!$this->getUncommittedStatus()) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"{$commit_hash} has already been reverted."); pht('%s has already been reverted.', $commit_hash));
} }
} }
public function getBackoutMessage($commit_hash) { public function getBackoutMessage($commit_hash) {
return 'This reverts commit '.$commit_hash.'.'; return pht('This reverts commit %s.', $commit_hash);
} }
public function isGitSubversionRepo() { public function isGitSubversionRepo() {
@ -1073,9 +1103,12 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$matches[1]); $matches[1]);
if (!$err) { if (!$err) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the merge-base of '{$matches[1]}' and HEAD, as ". pht(
"specified by '{$rule}' in your {$source} 'base' ". "it is the merge-base of '%s' and HEAD, as specified by ".
"configuration."); "'%s' in your %s 'base' configuration.",
$matches[1],
$rule,
$source));
return trim($merge_base); return trim($merge_base);
} }
} else if (preg_match('/^branch-unique\((.+)\)$/', $name, $matches)) { } else if (preg_match('/^branch-unique\((.+)\)$/', $name, $matches)) {
@ -1118,9 +1151,13 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
} }
$branches = implode(', ', $branches); $branches = implode(', ', $branches);
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the first commit between '{$merge_base}' (the ". pht(
"merge-base of '{$matches[1]}' and HEAD) which is also ". "it is the first commit between '%s' (the merge-base of ".
"contained by another branch ({$branches})."); "'%s' and HEAD) which is also contained by another branch ".
"(%s).",
$merge_base,
$matches[1],
$branches));
return $commit; return $commit;
} }
} }
@ -1130,8 +1167,10 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$name); $name);
if (!$err) { if (!$err) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is specified by '{$rule}' in your {$source} 'base' ". pht(
"configuration."); "it is specified by '%s' in your %s 'base' configuration.",
$rule,
$source));
return $name; return $name;
} }
} }
@ -1140,8 +1179,10 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
switch ($name) { switch ($name) {
case 'empty': case 'empty':
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"you specified '{$rule}' in your {$source} 'base' ". pht(
"configuration."); "you specified '%s' in your %s 'base' configuration.",
$rule,
$source));
return self::GIT_MAGIC_ROOT_COMMIT; return self::GIT_MAGIC_ROOT_COMMIT;
case 'amended': case 'amended':
$text = $this->getCommitMessage('HEAD'); $text = $this->getCommitMessage('HEAD');
@ -1149,9 +1190,11 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$text); $text);
if ($message->getRevisionID()) { if ($message->getRevisionID()) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"HEAD has been amended with 'Differential Revision:', ". pht(
"as specified by '{$rule}' in your {$source} 'base' ". "HEAD has been amended with 'Differential Revision:', ".
"configuration."); "as specified by '%s' in your %s 'base' configuration.",
$rule,
$source));
return 'HEAD^'; return 'HEAD^';
} }
break; break;
@ -1166,16 +1209,21 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$upstream); $upstream);
$upstream_merge_base = rtrim($upstream_merge_base); $upstream_merge_base = rtrim($upstream_merge_base);
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the merge-base of the upstream of the current branch ". pht(
"and HEAD, and matched the rule '{$rule}' in your {$source} ". "it is the merge-base of the upstream of the current branch ".
"'base' configuration."); "and HEAD, and matched the rule '%s' in your %s ".
"'base' configuration.",
$rule,
$source));
return $upstream_merge_base; return $upstream_merge_base;
} }
break; break;
case 'this': case 'this':
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"you specified '{$rule}' in your {$source} 'base' ". pht(
"configuration."); "you specified '%s' in your %s 'base' configuration.",
$rule,
$source));
return 'HEAD^'; return 'HEAD^';
} }
default: default:

View file

@ -80,7 +80,7 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
$string); $string);
if (!$stdout) { if (!$stdout) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Cannot find the HG equivalent of {$revision_id} given."); pht('Cannot find the HG equivalent of %s given.', $revision_id));
} }
return $stdout; return $stdout;
} }
@ -92,7 +92,7 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
'log -r %s --template {svnrev}', $hash); 'log -r %s --template {svnrev}', $hash);
if (!$stdout) { if (!$stdout) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Cannot find the SVN equivalent of {$hash} given."); pht('Cannot find the SVN equivalent of %s given.', $hash));
} }
return $stdout; return $stdout;
} }
@ -125,14 +125,16 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
hgsprintf('ancestor(%R,.)', $symbolic_commit)); hgsprintf('ancestor(%R,.)', $symbolic_commit));
} catch (Exception $ex) { } catch (Exception $ex) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Commit '{$symbolic_commit}' is not a valid Mercurial commit ". pht(
"identifier."); "Commit '%s' is not a valid Mercurial commit identifier.",
$symbolic_commit));
} }
} }
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
'it is the greatest common ancestor of the working directory '. pht(
'and the commit you specified explicitly.'); 'it is the greatest common ancestor of the working directory '.
'and the commit you specified explicitly.'));
return $commit; return $commit;
} }
@ -141,9 +143,10 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
$base = $this->resolveBaseCommit(); $base = $this->resolveBaseCommit();
if (!$base) { if (!$base) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"None of the rules in your 'base' configuration matched a valid ". pht(
"commit. Adjust rules or specify which commit you want to use ". "None of the rules in your 'base' configuration matched a valid ".
"explicitly."); "commit. Adjust rules or specify which commit you want to use ".
"explicitly."));
} }
return $base; return $base;
} }
@ -172,8 +175,9 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
if (!$logs) { if (!$logs) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
'you have no outgoing commits, so arc assumes you intend to submit '. pht(
'uncommitted changes in the working copy.'); 'you have no outgoing commits, so arc assumes you intend to submit '.
'uncommitted changes in the working copy.'));
return $this->getWorkingCopyRevision(); return $this->getWorkingCopyRevision();
} }
@ -215,11 +219,12 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
if ($against == 'null') { if ($against == 'null') {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
'this is a new repository (all changes are outgoing).'); pht('this is a new repository (all changes are outgoing).'));
} else { } else {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
'it is the first commit reachable from the working copy state '. pht(
'which is not outgoing.'); 'it is the first commit reachable from the working copy state '.
'which is not outgoing.'));
} }
return $against; return $against;
@ -334,7 +339,10 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
$ok = preg_match('/^\s*([^:]+?) ([a-f0-9]{12}):/', $line, $matches); $ok = preg_match('/^\s*([^:]+?) ([a-f0-9]{12}):/', $line, $matches);
if (!$ok) { if (!$ok) {
throw new Exception("Unable to parse Mercurial blame line: {$line}"); throw new Exception(
pht(
'Unable to parse Mercurial blame line: %s',
$line));
} }
$revision = $matches[2]; $revision = $matches[2];
@ -619,13 +627,15 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
} }
if ($err) { if ($err) {
throw new ArcanistUsageException('Merge failed!'); throw new ArcanistUsageException(pht('Merge failed!'));
} }
} }
public function getFinalizedRevisionMessage() { public function getFinalizedRevisionMessage() {
return "You may now push this commit upstream, as appropriate (e.g. with ". return pht(
"'hg push' or by printing and faxing it)."; "You may now push this commit upstream, as appropriate (e.g. with ".
"'%s' or by printing and faxing it).",
'hg push');
} }
public function getCommitMessageLog() { public function getCommitMessageLog() {
@ -676,7 +686,9 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
foreach ($results as $key => $result) { foreach ($results as $key => $result) {
$hash = substr($reason_map[$result['id']], 0, 16); $hash = substr($reason_map[$result['id']], 0, 16);
$results[$key]['why'] = $results[$key]['why'] =
"Commit message for '{$hash}' has explicit 'Differential Revision'."; pht(
"Commit message for '%s' has explicit 'Differential Revision'.",
$hash);
} }
return $results; return $results;
@ -700,9 +712,9 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
)); ));
foreach ($results as $key => $hash) { foreach ($results as $key => $hash) {
$results[$key]['why'] = $results[$key]['why'] = pht(
'A mercurial commit hash in the commit range is already attached '. 'A mercurial commit hash in the commit range is already attached '.
'to the Differential revision.'; 'to the Differential revision.');
} }
return $results; return $results;
@ -795,7 +807,7 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
public function getCommitSummary($commit) { public function getCommitSummary($commit) {
if ($commit == 'null') { if ($commit == 'null') {
return '(The Empty Void)'; return pht('(The Empty Void)');
} }
list($summary) = $this->execxLocal( list($summary) = $this->execxLocal(
@ -808,17 +820,16 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
} }
public function backoutCommit($commit_hash) { public function backoutCommit($commit_hash) {
$this->execxLocal( $this->execxLocal('backout -r %s', $commit_hash);
'backout -r %s', $commit_hash);
$this->reloadWorkingCopy(); $this->reloadWorkingCopy();
if (!$this->getUncommittedStatus()) { if (!$this->getUncommittedStatus()) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"{$commit_hash} has already been reverted."); pht('%s has already been reverted.', $commit_hash));
} }
} }
public function getBackoutMessage($commit_hash) { public function getBackoutMessage($commit_hash) {
return 'Backed out changeset '.$commit_hash.'.'; return pht('Backed out changeset %s,', $commit_hash);
} }
public function resolveBaseCommitRule($rule, $source) { public function resolveBaseCommitRule($rule, $source) {
@ -838,9 +849,13 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
sprintf('ancestor(., %s)', $matches[1])); sprintf('ancestor(., %s)', $matches[1]));
if (!$err) { if (!$err) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the greatest common ancestor of '{$matches[1]}' and ., as". pht(
" specified by '{$rule}' in your {$source} 'base' ". "it is the greatest common ancestor of '%s' and %s, as ".
"configuration."); "specified by '%s' in your %s 'base' configuration.",
$matches[1],
'.',
$rule,
$source));
return trim($merge_base); return trim($merge_base);
} }
} else { } else {
@ -855,8 +870,10 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
} }
if (!$err) { if (!$err) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is specified by '{$rule}' in your {$source} 'base' ". pht(
"configuration."); "it is specified by '%s' in your %s 'base' configuration.",
$rule,
$source));
return trim($commit); return trim($commit);
} }
} }
@ -865,8 +882,10 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
switch ($name) { switch ($name) {
case 'empty': case 'empty':
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"you specified '{$rule}' in your {$source} 'base' ". pht(
"configuration."); "you specified '%s' in your %s 'base' configuration.",
$rule,
$source));
return 'null'; return 'null';
case 'outgoing': case 'outgoing':
list($err, $outgoing_base) = $this->execManualLocal( list($err, $outgoing_base) = $this->execManualLocal(
@ -874,9 +893,12 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
'limit(reverse(ancestors(.) - outgoing()), 1)'); 'limit(reverse(ancestors(.) - outgoing()), 1)');
if (!$err) { if (!$err) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the first ancestor of the working copy that is not ". pht(
"outgoing, and it matched the rule {$rule} in your {$source} ". "it is the first ancestor of the working copy that is not ".
"'base' configuration."); "outgoing, and it matched the rule %s in your %s ".
"'base' configuration.",
$rule,
$source));
return trim($outgoing_base); return trim($outgoing_base);
} }
case 'amended': case 'amended':
@ -885,9 +907,12 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
$text); $text);
if ($message->getRevisionID()) { if ($message->getRevisionID()) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"'.' has been amended with 'Differential Revision:', ". pht(
"as specified by '{$rule}' in your {$source} 'base' ". "'%s' has been amended with 'Differential Revision:', ".
"configuration."); "as specified by '%s' in your %s 'base' configuration.",
'.'.
$rule,
$source));
// NOTE: This should be safe because Mercurial doesn't support // NOTE: This should be safe because Mercurial doesn't support
// amend until 2.2. // amend until 2.2.
return $this->getCanonicalRevisionName('.^'); return $this->getCanonicalRevisionName('.^');
@ -906,16 +931,22 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
$revset); $revset);
if (!$err) { if (!$err) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the first ancestor of . that either has a bookmark, or ". pht(
"is already in the remote and it matched the rule {$rule} in ". "it is the first ancestor of %s that either has a bookmark, ".
"your {$source} 'base' configuration"); "or is already in the remote and it matched the rule %s in ".
"your %s 'base' configuration",
'.',
$rule,
$source));
return trim($bookmark_base); return trim($bookmark_base);
} }
break; break;
case 'this': case 'this':
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"you specified '{$rule}' in your {$source} 'base' ". pht(
"configuration."); "you specified '%s' in your %s 'base' configuration.",
$rule,
$source));
return $this->getCanonicalRevisionName('.^'); return $this->getCanonicalRevisionName('.^');
default: default:
if (preg_match('/^nodiff\((.+)\)$/', $name, $matches)) { if (preg_match('/^nodiff\((.+)\)$/', $name, $matches)) {
@ -936,10 +967,14 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
$desc); $desc);
if ($message->getRevisionID()) { if ($message->getRevisionID()) {
$this->setBaseCommitExplanation( $this->setBaseCommitExplanation(
"it is the first ancestor of . that has a diff ". pht(
"and is the gca or a descendant of the gca with ". "it is the first ancestor of %s that has a diff and is ".
"'{$matches[1]}', specified by '{$rule}' in your ". "the gca or a descendant of the gca with '%s', ".
"{$source} 'base' configuration."); "specified by '%s' in your %s 'base' configuration.",
'.',
$matches[1],
$rule,
$source));
return $node; return $node;
} }
} }

View file

@ -63,7 +63,8 @@ abstract class ArcanistRepositoryAPI {
if (!$working_copy) { if (!$working_copy) {
throw new Exception( throw new Exception(
pht( pht(
'Trying to create a RepositoryAPI without a working copy!')); 'Trying to create a %s without a working copy!',
__CLASS__));
} }
$root = $working_copy->getProjectRoot(); $root = $working_copy->getProjectRoot();

View file

@ -37,7 +37,6 @@ final class ArcanistSubversionAPI extends ArcanistRepositoryAPI {
} }
protected function buildLocalFuture(array $argv) { protected function buildLocalFuture(array $argv) {
$argv[0] = 'svn '.$argv[0]; $argv[0] = 'svn '.$argv[0];
$future = newv('ExecFuture', $argv); $future = newv('ExecFuture', $argv);
@ -106,7 +105,9 @@ final class ArcanistSubversionAPI extends ArcanistRepositoryAPI {
$mask |= self::FLAG_MODIFIED; $mask |= self::FLAG_MODIFIED;
break; break;
default: default:
throw new Exception("Unrecognized property status '{$props}'."); throw new Exception(pht(
"Unrecognized property status '%s'.",
$props));
} }
$mask |= $this->parseSVNStatus($item); $mask |= $this->parseSVNStatus($item);
@ -177,7 +178,7 @@ final class ArcanistSubversionAPI extends ArcanistRepositoryAPI {
case 'incomplete': case 'incomplete':
return self::FLAG_INCOMPLETE; return self::FLAG_INCOMPLETE;
default: default:
throw new Exception("Unrecognized item status '{$item}'."); throw new Exception(pht("Unrecognized item status '%s'.", $item));
} }
} }
@ -332,7 +333,7 @@ final class ArcanistSubversionAPI extends ArcanistRepositoryAPI {
list($err, $stdout) = $this->svnInfoRaw[$path]; list($err, $stdout) = $this->svnInfoRaw[$path];
if ($err) { if ($err) {
throw new Exception( throw new Exception(
"Error #{$err} executing svn info against '{$path}'."); pht("Error #%d executing svn info against '%s'.", $err, $path));
} }
// TODO: Hack for Windows. // TODO: Hack for Windows.
@ -364,7 +365,7 @@ final class ArcanistSubversionAPI extends ArcanistRepositoryAPI {
} }
if (empty($result)) { if (empty($result)) {
throw new Exception('Unable to parse SVN info.'); throw new Exception(pht('Unable to parse SVN info.'));
} }
$this->svnInfo[$path] = $result; $this->svnInfo[$path] = $result;
@ -431,9 +432,12 @@ EODIFF;
// happy about it. SVN will exit with code 1 and return the string below. // happy about it. SVN will exit with code 1 and return the string below.
if ($err != 0 && $stderr !== "svn: 'diff' returned 2\n") { if ($err != 0 && $stderr !== "svn: 'diff' returned 2\n") {
throw new Exception( throw new Exception(
"svn diff returned unexpected error code: $err\n". pht(
"stdout: $stdout\n". "%s returned unexpected error code: %d\nstdout: %s\nstderr: %s",
"stderr: $stderr"); 'svn diff',
$err,
$stdout,
$stderr));
} }
if ($err == 0 && empty($stdout)) { if ($err == 0 && empty($stdout)) {
@ -568,7 +572,7 @@ EODIFF;
foreach (explode("\n", $stdout) as $line) { foreach (explode("\n", $stdout) as $line) {
$m = array(); $m = array();
if (!preg_match('/^\s*(\d+)\s+(\S+)/', $line, $m)) { if (!preg_match('/^\s*(\d+)\s+(\S+)/', $line, $m)) {
throw new Exception("Bad blame? `{$line}'"); throw new Exception(pht("Bad blame? `%s'", $line));
} }
$revision = $m[1]; $revision = $m[1];
$author = $m[2]; $author = $m[2];
@ -665,8 +669,8 @@ EODIFF;
} }
foreach ($results as $key => $result) { foreach ($results as $key => $result) {
$results[$key]['why'] = $results[$key]['why'] = pht(
'Matching arcanist project name and working copy directory path.'; 'Matching arcanist project name and working copy directory path.');
} }
return $results; return $results;

View file

@ -6,7 +6,7 @@ final class ArcanistRepositoryAPIStateTestCase extends ArcanistTestCase {
if (Filesystem::binaryExists('git')) { if (Filesystem::binaryExists('git')) {
$this->parseState('git_basic.git.tgz'); $this->parseState('git_basic.git.tgz');
} else { } else {
$this->assertSkipped('Git is not installed'); $this->assertSkipped(pht('Git is not installed'));
} }
} }
@ -14,7 +14,7 @@ final class ArcanistRepositoryAPIStateTestCase extends ArcanistTestCase {
if (Filesystem::binaryExists('hg')) { if (Filesystem::binaryExists('hg')) {
$this->parseState('hg_basic.hg.tgz'); $this->parseState('hg_basic.hg.tgz');
} else { } else {
$this->assertSkipped('Mercurial is not installed'); $this->assertSkipped(pht('Mercurial is not installed'));
} }
} }
@ -22,7 +22,7 @@ final class ArcanistRepositoryAPIStateTestCase extends ArcanistTestCase {
if (Filesystem::binaryExists('svn')) { if (Filesystem::binaryExists('svn')) {
$this->parseState('svn_basic.svn.tgz'); $this->parseState('svn_basic.svn.tgz');
} else { } else {
$this->assertSkipped('Subversion is not installed'); $this->assertSkipped(pht('Subversion is not installed'));
} }
} }
@ -116,7 +116,7 @@ final class ArcanistRepositoryAPIStateTestCase extends ArcanistTestCase {
break; break;
default: default:
throw new Exception( throw new Exception(
"No test cases for working copy '{$test}'!"); pht("No test cases for working copy '%s'!", $test));
} }
} }

View file

@ -34,7 +34,10 @@ final class ArcanistMercurialParser {
foreach ($lines as $line) { foreach ($lines as $line) {
$flags = 0; $flags = 0;
if ($line[1] !== ' ') { if ($line[1] !== ' ') {
throw new Exception("Unparsable Mercurial status line '{$line}'."); throw new Exception(
pht(
"Unparsable Mercurial status line '%s'.",
$line));
} }
$code = $line[0]; $code = $line[0];
$path = substr($line, 2); $path = substr($line, 2);
@ -66,12 +69,15 @@ final class ArcanistMercurialParser {
// parsed to set its source. // parsed to set its source.
if ($last_path === null) { if ($last_path === null) {
throw new Exception( throw new Exception(
"Unexpected copy source in hg status, '{$line}'."); pht(
"Unexpected copy source in %s, '%s'.",
'hg status',
$line));
} }
$result[$last_path]['from'] = $path; $result[$last_path]['from'] = $path;
continue 2; continue 2;
default: default:
throw new Exception("Unknown Mercurial status '{$code}'."); throw new Exception(pht("Unknown Mercurial status '%s'.", $code));
} }
$result[$path] = array( $result[$path] = array(
@ -169,7 +175,8 @@ final class ArcanistMercurialParser {
$commit['bookmark'] = $value; $commit['bookmark'] = $value;
break; break;
default: default:
throw new Exception("Unknown Mercurial log field '{$name}'!"); throw new Exception(
pht("Unknown Mercurial log field '%s'!", $name));
} }
} }
$result[] = $commit; $result[] = $commit;
@ -211,7 +218,11 @@ final class ArcanistMercurialParser {
$regexp = '/^(\S+(?:\s+\S+)*)\s+(\d+):([a-f0-9]+)(\s+\\(inactive\\))?$/'; $regexp = '/^(\S+(?:\s+\S+)*)\s+(\d+):([a-f0-9]+)(\s+\\(inactive\\))?$/';
if (!preg_match($regexp, $line, $matches)) { if (!preg_match($regexp, $line, $matches)) {
throw new Exception("Failed to parse 'hg branches' output: {$line}"); throw new Exception(
pht(
"Failed to parse '%s' output: %s",
'hg branches',
$line));
} }
$branches[$matches[1]] = array( $branches[$matches[1]] = array(
'local' => $matches[2], 'local' => $matches[2],

View file

@ -82,7 +82,8 @@ final class ArcanistMercurialParserTestCase extends ArcanistTestCase {
idx($output, 'copy_source')); idx($output, 'copy_source'));
break; break;
default: default:
throw new Exception("No test information for test data '{$name}'!"); throw new Exception(
pht("No test information for test data '%s'!", $name));
} }
} }

View file

@ -17,9 +17,11 @@ abstract class ArcanistUnitTestEngine {
public function setRunAllTests($run_all_tests) { public function setRunAllTests($run_all_tests) {
if (!$this->supportsRunAllTests() && $run_all_tests) { if (!$this->supportsRunAllTests() && $run_all_tests) {
$class = get_class($this);
throw new Exception( throw new Exception(
"Engine '{$class}' does not support --everything."); pht(
"Engine '%s' does not support %s.",
get_class($this),
'--everything'));
} }
$this->runAllTests = $run_all_tests; $this->runAllTests = $run_all_tests;
@ -53,7 +55,7 @@ abstract class ArcanistUnitTestEngine {
if ($this instanceof ArcanistBaseUnitTestEngine) { if ($this instanceof ArcanistBaseUnitTestEngine) {
phutil_deprecated( phutil_deprecated(
'ArcanistBaseUnitTestEngine', 'ArcanistBaseUnitTestEngine',
'You should extend from `ArcanistUnitTestEngine` instead.'); pht('You should extend from `%s` instead.', __CLASS__));
} }
$this->workingCopy = $working_copy; $this->workingCopy = $working_copy;

View file

@ -37,15 +37,20 @@ final class CSharpToolsTestEngine extends XUnitTestEngine {
// Determine coverage path. // Determine coverage path.
if ($this->cscoverHintPath === null) { if ($this->cscoverHintPath === null) {
throw new Exception( throw new Exception(
"Unable to locate cscover. Configure it with ". pht(
"the `unit.csharp.coverage.binary' option in .arcconfig"); "Unable to locate %s. Configure it with the '%s' option in %s.",
'cscover',
'unit.csharp.coverage.binary',
'.arcconfig'));
} }
$cscover = $this->projectRoot.DIRECTORY_SEPARATOR.$this->cscoverHintPath; $cscover = $this->projectRoot.DIRECTORY_SEPARATOR.$this->cscoverHintPath;
if (file_exists($cscover)) { if (file_exists($cscover)) {
$this->coverEngine = Filesystem::resolvePath($cscover); $this->coverEngine = Filesystem::resolvePath($cscover);
} else { } else {
throw new Exception( throw new Exception(
'Unable to locate cscover coverage runner (have you built yet?)'); pht(
'Unable to locate %s coverage runner (have you built yet?)',
'cscover'));
} }
} }

View file

@ -75,17 +75,19 @@ final class NoseTestEngine extends ArcanistUnitTestEngine {
$cover_tmp = $tmpfiles[$test_path]['cover']; $cover_tmp = $tmpfiles[$test_path]['cover'];
$this->parser = new ArcanistXUnitTestResultParser(); $this->parser = new ArcanistXUnitTestResultParser();
$results[] = $this->parseTestResults($source_path, $results[] = $this->parseTestResults(
$xunit_tmp, $source_path,
$cover_tmp); $xunit_tmp,
$cover_tmp);
} }
return array_mergev($results); return array_mergev($results);
} }
public function buildTestFuture($path, $xunit_tmp, $cover_tmp) { public function buildTestFuture($path, $xunit_tmp, $cover_tmp) {
$cmd_line = csprintf('nosetests --with-xunit --xunit-file=%s', $cmd_line = csprintf(
$xunit_tmp); 'nosetests --with-xunit --xunit-file=%s',
$xunit_tmp);
if ($this->getEnableCoverage() !== false) { if ($this->getEnableCoverage() !== false) {
$cmd_line .= csprintf( $cmd_line .= csprintf(

View file

@ -42,7 +42,7 @@ final class PhpunitTestEngine extends ArcanistUnitTestEngine {
} }
if (empty($this->affectedTests)) { if (empty($this->affectedTests)) {
throw new ArcanistNoEffectException('No tests to run.'); throw new ArcanistNoEffectException(pht('No tests to run.'));
} }
$this->prepareConfigFile(); $this->prepareConfigFile();
@ -260,8 +260,10 @@ final class PhpunitTestEngine extends ArcanistUnitTestEngine {
if (Filesystem::pathExists($project_root.$config)) { if (Filesystem::pathExists($project_root.$config)) {
$this->configFile = $project_root.$config; $this->configFile = $project_root.$config;
} else { } else {
throw new Exception('PHPUnit configuration file was not '. throw new Exception(
'found in '.$project_root.$config); pht(
'PHPUnit configuration file was not found in %s',
$project_root.$config));
} }
} }
$bin = $this->getConfigurationManager()->getConfigFromAnySource( $bin = $this->getConfigurationManager()->getConfigFromAnySource(

View file

@ -25,8 +25,11 @@ final class PhutilUnitTestEngine extends ArcanistUnitTestEngine {
if (!function_exists('xdebug_start_code_coverage')) { if (!function_exists('xdebug_start_code_coverage')) {
if ($enable_coverage === true) { if ($enable_coverage === true) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'You specified --coverage but xdebug is not available, so '. pht(
'coverage can not be enabled for PhutilUnitTestEngine.'); 'You specified %s but xdebug is not available, so '.
'coverage can not be enabled for %s.',
'--coverage',
__CLASS__));
} }
} else { } else {
$enable_coverage = true; $enable_coverage = true;
@ -114,14 +117,20 @@ final class PhutilUnitTestEngine extends ArcanistUnitTestEngine {
if (!$library_name) { if (!$library_name) {
throw new Exception( throw new Exception(
"Attempting to run unit tests on a libphutil library which has not ". sprintf(
"been loaded, at:\n\n". "%s\n\n %s\n\n%s\n\n - %s\n - %s\n",
" {$library_root}\n\n". pht(
"This probably means one of two things:\n\n". 'Attempting to run unit tests on a libphutil library '.
" - You may need to add this library to .arcconfig.\n". 'which has not been loaded, at:'),
" - You may be running tests on a copy of libphutil or arcanist\n". $library_root,
" using a different copy of libphutil or arcanist. This\n". pht('This probably means one of two things:'),
" operation is not supported."); pht(
'You may need to add this library to %s.',
'.arcconfig.'),
pht(
'You may be running tests on a copy of libphutil or '.
'arcanist using a different copy of libphutil or arcanist. '.
'This operation is not supported.')));
} }
$path = Filesystem::resolvePath($path, $project_root); $path = Filesystem::resolvePath($path, $project_root);

View file

@ -17,7 +17,7 @@ final class PytestTestEngine extends ArcanistUnitTestEngine {
if (!Filesystem::pathExists($junit_tmp)) { if (!Filesystem::pathExists($junit_tmp)) {
throw new CommandException( throw new CommandException(
"Command failed with error #{$err}!", pht('Command failed with error #%s!', $err),
$future->getCommand(), $future->getCommand(),
$err, $err,
$stdout, $stdout,

View file

@ -42,7 +42,12 @@ class XUnitTestEngine extends ArcanistUnitTestEngine {
} else if (Filesystem::binaryExists('xbuild')) { } else if (Filesystem::binaryExists('xbuild')) {
$this->buildEngine = 'xbuild'; $this->buildEngine = 'xbuild';
} else { } else {
throw new Exception('Unable to find msbuild or xbuild in PATH!'); throw new Exception(
pht(
'Unable to find %s or %s in %s!',
'msbuild',
'xbuild',
'PATH'));
} }
// Determine runtime engine (.NET or Mono). // Determine runtime engine (.NET or Mono).
@ -51,7 +56,8 @@ class XUnitTestEngine extends ArcanistUnitTestEngine {
} else if (Filesystem::binaryExists('mono')) { } else if (Filesystem::binaryExists('mono')) {
$this->runtimeEngine = Filesystem::resolveBinary('mono'); $this->runtimeEngine = Filesystem::resolveBinary('mono');
} else { } else {
throw new Exception('Unable to find Mono and you are not on Windows!'); throw new Exception(
pht('Unable to find Mono and you are not on Windows!'));
} }
// Read the discovery rules. // Read the discovery rules.
@ -60,8 +66,11 @@ class XUnitTestEngine extends ArcanistUnitTestEngine {
'unit.csharp.discovery'); 'unit.csharp.discovery');
if ($this->discoveryRules === null) { if ($this->discoveryRules === null) {
throw new Exception( throw new Exception(
'You must configure discovery rules to map C# files '. pht(
'back to test projects (`unit.csharp.discovery` in .arcconfig).'); 'You must configure discovery rules to map C# files '.
'back to test projects (`%s` in %s).',
'unit.csharp.discovery',
'.arcconfig'));
} }
// Determine xUnit test runner path. // Determine xUnit test runner path.
@ -77,8 +86,11 @@ class XUnitTestEngine extends ArcanistUnitTestEngine {
$this->testEngine = 'xunit.console.clr4.exe'; $this->testEngine = 'xunit.console.clr4.exe';
} else { } else {
throw new Exception( throw new Exception(
"Unable to locate xUnit console runner. Configure ". pht(
"it with the `unit.csharp.xunit.binary' option in .arcconfig"); "Unable to locate xUnit console runner. Configure ".
"it with the `%s' option in %s.",
'unit.csharp.xunit.binary',
'.arcconfig'));
} }
} }
@ -234,7 +246,7 @@ class XUnitTestEngine extends ArcanistUnitTestEngine {
$this->projectRoot)); $this->projectRoot));
$results = array(); $results = array();
$result = new ArcanistUnitTestResult(); $result = new ArcanistUnitTestResult();
$result->setName("(regenerate projects for $platform)"); $result->setName(pht('(regenerate projects for %s)', $platform));
try { try {
$regenerate_future->resolvex(); $regenerate_future->resolvex();

View file

@ -18,7 +18,9 @@ final class PhutilUnitTestEngineTestCase extends ArcanistTestCase {
$this->assertEqual( $this->assertEqual(
1, 1,
self::$allTestsCounter, self::$allTestsCounter,
'Expect willRunTests() has been called once.'); pht(
'Expect %s has been called once.',
'willRunTests()'));
self::$allTestsCounter--; self::$allTestsCounter--;
@ -27,21 +29,27 @@ final class PhutilUnitTestEngineTestCase extends ArcanistTestCase {
$this->assertEqual( $this->assertEqual(
$actual_test_count, $actual_test_count,
count(self::$distinctWillRunTests), count(self::$distinctWillRunTests),
'Expect willRunOneTest() was called once for each test.'); pht(
'Expect %s was called once for each test.',
'willRunOneTest()'));
$this->assertEqual( $this->assertEqual(
$actual_test_count, $actual_test_count,
count(self::$distinctDidRunTests), count(self::$distinctDidRunTests),
'Expect didRunOneTest() was called once for each test.'); pht(
'Expect %s was called once for each test.',
'didRunOneTest()'));
$this->assertEqual( $this->assertEqual(
self::$distinctWillRunTests, self::$distinctWillRunTests,
self::$distinctDidRunTests, self::$distinctDidRunTests,
'Expect same tests had pre- and post-run callbacks invoked.'); pht('Expect same tests had pre-run and post-run callbacks invoked.'));
} }
public function __destruct() { public function __destruct() {
if (self::$allTestsCounter !== 0) { if (self::$allTestsCounter !== 0) {
throw new Exception( throw new Exception(
'didRunTests() was not called correctly after tests completed!'); pht(
'%s was not called correctly after tests completed!',
'didRunTests()'));
} }
} }
@ -54,14 +62,14 @@ final class PhutilUnitTestEngineTestCase extends ArcanistTestCase {
$this->assertEqual( $this->assertEqual(
1, 1,
self::$oneTestCounter, self::$oneTestCounter,
'Expect willRunOneTest depth to be one.'); pht('Expect %s depth to be one.', 'willRunOneTest()'));
self::$distinctDidRunTests[$test] = true; self::$distinctDidRunTests[$test] = true;
self::$oneTestCounter--; self::$oneTestCounter--;
} }
public function testPass() { public function testPass() {
$this->assertEqual(1, 1, 'This test is expected to pass.'); $this->assertEqual(1, 1, pht('This test is expected to pass.'));
} }
public function testFailSkip() { public function testFailSkip() {
@ -74,11 +82,11 @@ final class PhutilUnitTestEngineTestCase extends ArcanistTestCase {
} else if ($result->getResult() == ArcanistUnitTestResult::RESULT_SKIP) { } else if ($result->getResult() == ArcanistUnitTestResult::RESULT_SKIP) {
$skipped++; $skipped++;
} else { } else {
$this->assertFailure('These tests should either fail or skip.'); $this->assertFailure(pht('These tests should either fail or skip.'));
} }
} }
$this->assertEqual(1, $failed, 'One test was expected to fail.'); $this->assertEqual(1, $failed, pht('One test was expected to fail.'));
$this->assertEqual(1, $skipped, 'One test was expected to skip.'); $this->assertEqual(1, $skipped, pht('One test was expected to skip.'));
} }
public function testTryTestCases() { public function testTryTestCases() {
@ -105,7 +113,7 @@ final class PhutilUnitTestEngineTestCase extends ArcanistTestCase {
protected function throwIfFalsey($input) { protected function throwIfFalsey($input) {
if (!$input) { if (!$input) {
throw new Exception('This is a negative test case!'); throw new Exception(pht('This is a negative test case!'));
} }
} }

View file

@ -111,14 +111,14 @@ abstract class ArcanistPhutilTestCase {
$output .= "\n"; $output .= "\n";
if (strpos($expect, "\n") === false && strpos($result, "\n") === false) { if (strpos($expect, "\n") === false && strpos($result, "\n") === false) {
$output .= "Expected: {$expect}\n"; $output .= pht("Expected: %s\n Actual: %s", $expect, $result);
$output .= " Actual: {$result}";
} else { } else {
$output .= "Expected vs Actual Output Diff\n"; $output .= pht(
$output .= ArcanistDiffUtils::renderDifferences( "Expected vs Actual Output Diff\n%s",
$expect, ArcanistDiffUtils::renderDifferences(
$result, $expect,
$lines = 0xFFFF); $result,
$lines = 0xFFFF));
} }
$this->failTest($output); $this->failTest($output);
@ -216,7 +216,7 @@ abstract class ArcanistPhutilTestCase {
if (count($inputs) !== count($expect)) { if (count($inputs) !== count($expect)) {
$this->assertFailure( $this->assertFailure(
'Input and expectations must have the same number of values.'); pht('Input and expectations must have the same number of values.'));
} }
$labels = array_keys($inputs); $labels = array_keys($inputs);
@ -243,18 +243,23 @@ abstract class ArcanistPhutilTestCase {
if ($expect === $actual) { if ($expect === $actual) {
if ($expect) { if ($expect) {
$message = "Test case '{$label}' did not throw, as expected."; $message = pht("Test case '%s' did not throw, as expected.", $label);
} else { } else {
$message = "Test case '{$label}' threw, as expected."; $message = pht("Test case '%s' threw, as expected.", $label);
} }
} else { } else {
if ($expect) { if ($expect) {
$message = "Test case '{$label}' was expected to succeed, but it ". $message = pht(
"raised an exception of class ".get_class($ex)." with ". "Test case '%s' was expected to succeed, but it ".
"message: ".$ex->getMessage(); "raised an exception of class %s with message: %s",
$label,
get_class($ex),
$ex->getMessage());
} else { } else {
$message = "Test case '{$label}' was expected to raise an ". $message = pht(
"exception, but it did not throw anything."; "Test case '%s' was expected to raise an ".
"exception, but it did not throw anything.",
$label);
} }
} }
@ -498,7 +503,7 @@ abstract class ArcanistPhutilTestCase {
throw head($exceptions); throw head($exceptions);
} else { } else {
throw new PhutilAggregateException( throw new PhutilAggregateException(
'Multiple exceptions were raised during test execution.', pht('Multiple exceptions were raised during test execution.'),
$exceptions); $exceptions);
} }
} }
@ -518,7 +523,12 @@ abstract class ArcanistPhutilTestCase {
$ex_class = get_class($ex); $ex_class = get_class($ex);
$ex_message = $ex->getMessage(); $ex_message = $ex->getMessage();
$ex_trace = $ex->getTraceAsString(); $ex_trace = $ex->getTraceAsString();
$message = "EXCEPTION ({$ex_class}): {$ex_message}\n{$ex_trace}"; $message = sprintf(
"%s (%s): %s\n%s",
pht('EXCEPTION'),
$ex_class,
$ex_message,
$ex_trace);
$this->failTest($message); $this->failTest($message);
} }
} }
@ -599,7 +609,7 @@ abstract class ArcanistPhutilTestCase {
final private function assertCoverageAvailable() { final private function assertCoverageAvailable() {
if (!function_exists('xdebug_start_code_coverage')) { if (!function_exists('xdebug_start_code_coverage')) {
throw new Exception( throw new Exception(
"You've enabled code coverage but XDebug is not installed."); pht("You've enabled code coverage but XDebug is not installed."));
} }
} }

View file

@ -122,7 +122,6 @@ final class ArcanistGoTestResultParser extends ArcanistTestResultParser {
} }
private function fixNames($test_case_results, $test_case_name) { private function fixNames($test_case_results, $test_case_name) {
foreach ($test_case_results as &$result) { foreach ($test_case_results as &$result) {
$test_name = $result->getName(); $test_name = $result->getName();
$result->setName('Go::Test::'.$test_case_name.'::'.$test_name); $result->setName('Go::Test::'.$test_case_name.'::'.$test_name);

View file

@ -170,12 +170,13 @@ final class ArcanistPhpunitTestResultParser extends ArcanistTestResultParser {
private function getJsonReport($json) { private function getJsonReport($json) {
if (empty($json)) { if (empty($json)) {
throw new Exception('JSON report file is empty, '. throw new Exception(
'it probably means that phpunit failed to run tests. '. pht(
'Try running arc unit with --trace option and then run '. 'JSON report file is empty, it probably means that phpunit '.
'generated phpunit command yourself, you might get the '. 'failed to run tests. Try running %s with %s option and then run '.
'answer.' 'generated phpunit command yourself, you might get the answer.',
); 'arc unit',
'--trace'));
} }
$json = preg_replace('/}{\s*"/', '},{"', $json); $json = preg_replace('/}{\s*"/', '},{"', $json);

View file

@ -16,7 +16,10 @@ final class ArcanistXUnitTestResultParser {
public function parseTestResults($test_results) { public function parseTestResults($test_results) {
if (!strlen($test_results)) { if (!strlen($test_results)) {
throw new Exception( throw new Exception(
'test_results argument to parseTestResults must not be empty'); pht(
'%s argument to %s must not be empty',
'test_results',
'parseTestResults()'));
} }
// xunit xsd: https://gist.github.com/959290 // xunit xsd: https://gist.github.com/959290
@ -28,7 +31,10 @@ final class ArcanistXUnitTestResultParser {
->setMaximumGlyphs(150) ->setMaximumGlyphs(150)
->truncateString($test_results); ->truncateString($test_results);
throw new Exception( throw new Exception(
"Failed to load XUnit report; Input starts with:\n\n {$input_start}"); sprintf(
"%s\n\n%s",
pht('Failed to load XUnit report; Input starts with:'),
$input_start));
} }
$results = array(); $results = array();

View file

@ -28,7 +28,7 @@ final class XUnitTestResultParserTestCase extends ArcanistTestCase {
$parsed_results = id(new ArcanistXUnitTestResultParser()) $parsed_results = id(new ArcanistXUnitTestResultParser())
->parseTestResults(''); ->parseTestResults('');
$this->failTest('Should throw on empty input'); $this->failTest(pht('Should throw on empty input'));
} catch (Exception $e) { } catch (Exception $e) {
// OK // OK
} }
@ -43,7 +43,7 @@ final class XUnitTestResultParserTestCase extends ArcanistTestCase {
$parsed_results = id(new ArcanistXUnitTestResultParser()) $parsed_results = id(new ArcanistXUnitTestResultParser())
->parseTestResults($stubbed_results); ->parseTestResults($stubbed_results);
$this->failTest('Should throw on non-xml input'); $this->failTest(pht('Should throw on non-xml input'));
} catch (Exception $e) { } catch (Exception $e) {
// OK // OK
} }

View file

@ -36,16 +36,32 @@ final class ArcanistUnitConsoleRenderer extends ArcanistUnitRenderer {
} }
private function getFormattedResult($result) { private function getFormattedResult($result) {
static $status_codes = array( switch ($result) {
ArcanistUnitTestResult::RESULT_PASS => '<bg:green>** PASS **</bg>', case ArcanistUnitTestResult::RESULT_PASS:
ArcanistUnitTestResult::RESULT_FAIL => '<bg:red>** FAIL **</bg>', return phutil_console_format('<bg:green>** %s **</bg>', pht('PASS'));
ArcanistUnitTestResult::RESULT_SKIP => '<bg:yellow>** SKIP **</bg>',
ArcanistUnitTestResult::RESULT_BROKEN => '<bg:red>** BROKEN **</bg>', case ArcanistUnitTestResult::RESULT_FAIL:
ArcanistUnitTestResult::RESULT_UNSOUND => '<bg:yellow>** UNSOUND **</bg>', return phutil_console_format('<bg:red>** %s **</bg>', pht('FAIL'));
ArcanistUnitTestResult::RESULT_POSTPONED =>
'<bg:yellow>** POSTPONED **</bg>', case ArcanistUnitTestResult::RESULT_SKIP:
); return phutil_console_format('<bg:yellow>** %s **</bg>', pht('SKIP'));
return phutil_console_format($status_codes[$result]);
case ArcanistUnitTestResult::RESULT_BROKEN:
return phutil_console_format('<bg:red>** %s **</bg>', pht('BROKEN'));
case ArcanistUnitTestResult::RESULT_UNSOUND:
return phutil_console_format(
'<bg:yellow>** %s **</bg>',
pht('UNSOUND'));
case ArcanistUnitTestResult::RESULT_POSTPONED:
return phutil_console_format(
'<bg:yellow>** %s **</bg>',
pht('POSTPONED'));
default:
return null;
}
} }
private function formatTestDuration($seconds) { private function formatTestDuration($seconds) {

View file

@ -91,22 +91,24 @@ EOTEXT
implode(' ' , $binding)); implode(' ' , $binding));
} }
} else { } else {
echo "You haven't defined any aliases yet.\n"; echo pht("You haven't defined any aliases yet.")."\n";
} }
} else if (count($argv) == 1) { } else if (count($argv) == 1) {
if (empty($aliases[$argv[0]])) { if (empty($aliases[$argv[0]])) {
echo "No alias '{$argv[0]}' to remove.\n"; echo pht("No alias '%s' to remove.", $argv[0])."\n";
} else { } else {
echo phutil_console_format( echo pht(
"'**arc %s**' is currently aliased to '**arc %s**'.", "'%s' is currently aliased to '%s'.",
$argv[0], phutil_console_format('**arc %s**', $argv[0]),
implode(' ', $aliases[$argv[0]])); phutil_console_format(
$ok = phutil_console_confirm('Delete this alias?'); '**arc %s**',
implode(' ', $aliases[$argv[0]])));
$ok = phutil_console_confirm(pht('Delete this alias?'));
if ($ok) { if ($ok) {
$was = implode(' ', $aliases[$argv[0]]); $was = implode(' ', $aliases[$argv[0]]);
unset($aliases[$argv[0]]); unset($aliases[$argv[0]]);
$this->writeAliases($aliases); $this->writeAliases($aliases);
echo "Unaliased '{$argv[0]}' (was '{$was}').\n"; echo pht("Unaliased '%s' (was '%s').", $argv[0], $was)."\n";
} else { } else {
throw new ArcanistUserAbortException(); throw new ArcanistUserAbortException();
} }
@ -116,15 +118,18 @@ EOTEXT
if ($arc_config->buildWorkflow($argv[0])) { if ($arc_config->buildWorkflow($argv[0])) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"You can not create an alias for '{$argv[0]}' because it is a ". pht(
"builtin command. 'arc alias' can only create new commands."); "You can not create an alias for '%s' because it is a ".
"builtin command. '%s' can only create new commands.",
$argv[0],
'arc alias'));
} }
$aliases[$argv[0]] = array_slice($argv, 1); $aliases[$argv[0]] = array_slice($argv, 1);
echo phutil_console_format( echo pht(
"Aliased '**arc %s**' to '**arc %s**'.\n", "Aliased '%s' to '%s'.\n",
$argv[0], phutil_console_format('**arc %s**', $argv[0]),
implode(' ', $aliases[$argv[0]])); phutil_console_format('**arc %s**', implode(' ', $aliases[$argv[0]])));
$this->writeAliases($aliases); $this->writeAliases($aliases);
} }

View file

@ -67,21 +67,25 @@ EOTEXT
if (!$is_show) { if (!$is_show) {
if (!$repository_api->supportsAmend()) { if (!$repository_api->supportsAmend()) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"You may only run 'arc amend' in a git or hg (version ". pht(
"2.2 or newer) working copy."); "You may only run '%s' in a git or hg ".
"(version 2.2 or newer) working copy.",
'arc amend'));
} }
if ($this->isHistoryImmutable()) { if ($this->isHistoryImmutable()) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'This project is marked as adhering to a conservative history '. pht(
'mutability doctrine (having an immutable local history), which '. 'This project is marked as adhering to a conservative history '.
'precludes amending commit messages.'); 'mutability doctrine (having an immutable local history), which '.
'precludes amending commit messages.'));
} }
if ($repository_api->getUncommittedChanges()) { if ($repository_api->getUncommittedChanges()) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'You have uncommitted changes in this branch. Stage and commit (or '. pht(
'revert) them before proceeding.'); 'You have uncommitted changes in this branch. Stage and commit '.
'(or revert) them before proceeding.'));
} }
} }
@ -101,14 +105,18 @@ EOTEXT
if (!$revision_id) { if (!$revision_id) {
if (count($in_working_copy) == 0) { if (count($in_working_copy) == 0) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"No revision specified with '--revision', and no revisions found ". pht(
"in the working copy. Use '--revision <id>' to specify which ". "No revision specified with '%s', and no revisions found ".
"revision you want to amend."); "in the working copy. Use '%s' to specify which revision ".
"you want to amend.",
'--revision',
'--revision <id>'));
} else if (count($in_working_copy) > 1) { } else if (count($in_working_copy) > 1) {
$message = "More than one revision was found in the working copy:\n". $message = pht(
$this->renderRevisionList($in_working_copy)."\n". "More than one revision was found in the working copy:\n%s\n".
"Use '--revision <id>' to specify which revision you want to ". "Use '%s' to specify which revision you want to amend.",
"amend."; $this->renderRevisionList($in_working_copy),
'--revision <id>');
throw new ArcanistUsageException($message); throw new ArcanistUsageException($message);
} else { } else {
$revision_id = key($in_working_copy); $revision_id = key($in_working_copy);
@ -123,9 +131,11 @@ EOTEXT
$other_author = $other_author[$revision['authorPHID']]; $other_author = $other_author[$revision['authorPHID']];
$rev_title = $revision['title']; $rev_title = $revision['title'];
$ok = phutil_console_confirm( $ok = phutil_console_confirm(
"You are amending the revision 'D{$revision_id}: {$rev_title}' ". pht(
"but you are not the author. Amend this revision by ". "You are amending the revision '%s' but you are not ".
"{$other_author}?"); "the author. Amend this revision by %s?",
"D{$revision_id}: {$rev_title}",
$other_author));
if (!$ok) { if (!$ok) {
throw new ArcanistUserAbortException(); throw new ArcanistUserAbortException();
} }
@ -146,7 +156,7 @@ EOTEXT
throw $ex; throw $ex;
} else { } else {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Revision D{$revision_id} does not exist." pht("Revision '%s' does not exist.", "D{$revision_id}")
); );
} }
} }
@ -158,7 +168,7 @@ EOTEXT
)); ));
if (empty($revision)) { if (empty($revision)) {
throw new Exception( throw new Exception(
"Failed to lookup information for 'D{$revision_id}'!"); pht("Failed to lookup information for '%s'!", "D{$revision_id}"));
} }
$revision = head($revision); $revision = head($revision);
$revision_title = $revision['title']; $revision_title = $revision['title'];
@ -166,9 +176,11 @@ EOTEXT
if (!$is_show) { if (!$is_show) {
if ($revision_id && empty($in_working_copy[$revision_id])) { if ($revision_id && empty($in_working_copy[$revision_id])) {
$ok = phutil_console_confirm( $ok = phutil_console_confirm(
"The revision 'D{$revision_id}' does not appear to be in the ". pht(
"working copy. Are you sure you want to amend HEAD with the ". "The revision '%s' does not appear to be in the working copy. Are ".
"commit message for 'D{$revision_id}: {$revision_title}'?"); "you sure you want to amend HEAD with the commit message for '%s'?",
"D{$revision_id}",
"D{$revision_id}: {$revision_title}"));
if (!$ok) { if (!$ok) {
throw new ArcanistUserAbortException(); throw new ArcanistUserAbortException();
} }
@ -178,9 +190,12 @@ EOTEXT
if ($is_show) { if ($is_show) {
echo $message."\n"; echo $message."\n";
} else { } else {
echo phutil_console_format( echo pht(
"Amending commit message to reflect revision **%s**.\n", "Amending commit message to reflect revision %s.\n",
"D{$revision_id}: {$revision_title}"); phutil_console_format(
'**D%d: %s**',
$revision_id,
$revision_title));
$repository_api->amendCommit($message); $repository_api->amendCommit($message);
} }

View file

@ -61,16 +61,16 @@ EOTEXT
)); ));
if (!$revisions) { if (!$revisions) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'The revision you provided does not exist!'); pht('The revision you provided does not exist!'));
} }
$revision = $revisions[0]; $revision = $revisions[0];
$commits = $revision['commits']; $commits = $revision['commits'];
if (!$commits) { if (!$commits) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'This revision has not been committed yet!'); pht('This revision has not been committed yet!'));
} else if (count($commits) > 1) { } else if (count($commits) > 1) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'The revision you provided has multiple commits!'); pht('The revision you provided has multiple commits!'));
} }
$commit_phid = $commits[0]; $commit_phid = $commits[0];
$commit = $conduit->callMethodSynchronous( $commit = $conduit->callMethodSynchronous(
@ -144,11 +144,11 @@ EOTEXT
$repository_api->isHgSubversionRepo(); $repository_api->isHgSubversionRepo();
$revision_id = null; $revision_id = null;
$console->writeOut("Starting backout\n"); $console->writeOut(pht('Starting backout.')."\n");
$input = $this->getArgument('input'); $input = $this->getArgument('input');
if (!$input || count($input) != 1) { if (!$input || count($input) != 1) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'You must specify one commit to backout!'); pht('You must specify one commit to backout!'));
} }
// Input looks like a Differential revision, so // Input looks like a Differential revision, so
@ -175,14 +175,15 @@ EOTEXT
// Run 'backout'. // Run 'backout'.
$subject = $repository_api->getCommitSummary($commit_hash); $subject = $repository_api->getCommitSummary($commit_hash);
$console->writeOut("Backing out commit {$commit_hash} {$subject} \n"); $console->writeOut(
pht('Backing out commit %s %s', $commit_hash, $subject)."\n");
$repository_api->backoutCommit($commit_hash); $repository_api->backoutCommit($commit_hash);
// Create commit message and execute the commit // Create commit message and execute the commit
$message = $this->buildCommitMessage($commit_hash); $message = $this->buildCommitMessage($commit_hash);
$repository_api->doCommit($message); $repository_api->doCommit($message);
$console->writeOut("Double-check the commit and push when ready\n"); $console->writeOut(pht('Double-check the commit and push when ready.')."\n");
} }
} }

View file

@ -37,7 +37,8 @@ EOTEXT
'branch' => array( 'branch' => array(
'param' => 'branch_name', 'param' => 'branch_name',
'help' => pht( 'help' => pht(
'Default branch name to view on server. Defaults to "master".'), 'Default branch name to view on server. Defaults to "%s".',
'master'),
), ),
'force' => array( 'force' => array(
'help' => pht( 'help' => pht(
@ -74,7 +75,8 @@ EOTEXT
throw new ArcanistUsageException( throw new ArcanistUsageException(
pht( pht(
'Specify one or more paths or objects to browse. Use the command '. 'Specify one or more paths or objects to browse. Use the command '.
'"arc browse ." if you want to browse this directory.')); '"%s" if you want to browse this directory.',
'arc browse .'));
} }
$things = array_fuse($things); $things = array_fuse($things);
@ -182,21 +184,25 @@ EOTEXT
} else { } else {
if ($things) { if ($things) {
$console->writeOut( $console->writeOut(
"%s\n",
pht( pht(
"The current working directory is not a repository working ". "The current working directory is not a repository working ".
"copy, so remaining arguments can not be resolved as paths or ". "copy, so remaining arguments can not be resolved as paths or ".
"commits. To browse paths or symbolic commits in Diffusion, run ". "commits. To browse paths or symbolic commits in Diffusion, run ".
"'arc browse' from inside a working copy.")."\n"); "'%s' from inside a working copy.",
'arc browse'));
} }
} }
foreach ($things as $thing) { foreach ($things as $thing) {
$console->writeOut( $console->writeOut(
"%s\n",
pht( pht(
'Unable to find an object named **%s**, no such commit exists in '. 'Unable to find an object named **%s**, no such commit exists in '.
'the remote, and no such path exists in the working copy. Use '. 'the remote, and no such path exists in the working copy. Use '.
'__--force__ to treat this as a path anyway.', '__%s__ to treat this as a path anyway.',
$thing)."\n"); $thing,
'--force'));
} }
if ($uris) { if ($uris) {
@ -212,8 +218,10 @@ EOTEXT
throw new ArcanistUsageException( throw new ArcanistUsageException(
pht( pht(
'arc is unable to determine which repository in Diffusion '. 'arc is unable to determine which repository in Diffusion '.
'this working copy belongs to. Use "arc which" to understand how '. 'this working copy belongs to. Use "%s" to understand how '.
'arc looks for a repository.')); '%s looks for a repository.',
'arc which',
'arc'));
} }
$branch = $this->getArgument('branch', 'master'); $branch = $this->getArgument('branch', 'master');

View file

@ -32,13 +32,14 @@ EOTEXT
public function getArguments() { public function getArguments() {
return array( return array(
'finalize' => array( 'finalize' => array(
'help' => 'help' => pht(
"Close only if the repository is untracked and the revision is ". "Close only if the repository is untracked and the revision is ".
"accepted. Continue even if the close can't happen. This is a soft ". "accepted. Continue even if the close can't happen. This is a soft ".
"version of 'close-revision' used by other workflows.", "version of '' used by other workflows.",
'close-revision'),
), ),
'quiet' => array( 'quiet' => array(
'help' => 'Do not print a success message.', 'help' => pht('Do not print a success message.'),
), ),
'*' => 'revision', '*' => 'revision',
); );
@ -68,11 +69,15 @@ EOTEXT
$revision_list = $this->getArgument('revision', array()); $revision_list = $this->getArgument('revision', array());
if (!$revision_list) { if (!$revision_list) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'close-revision requires a revision number.'); pht(
'%s requires a revision number.',
'close-revision'));
} }
if (count($revision_list) != 1) { if (count($revision_list) != 1) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'close-revision requires exactly one revision.'); pht(
'%s requires exactly one revision.',
'close-revision'));
} }
$revision_id = reset($revision_list); $revision_id = reset($revision_list);
$revision_id = $this->normalizeRevisionID($revision_id); $revision_id = $this->normalizeRevisionID($revision_id);
@ -86,8 +91,9 @@ EOTEXT
if (!$revision && !$is_finalize) { if (!$revision && !$is_finalize) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Revision D{$revision_id} does not exist." pht(
); 'Revision %s does not exist.',
"D{$revision_id}"));
} }
$status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED; $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
@ -95,14 +101,18 @@ EOTEXT
if (!$is_finalize && $revision['status'] != $status_accepted) { if (!$is_finalize && $revision['status'] != $status_accepted) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Revision D{$revision_id} can not be closed. You can only close ". pht(
"revisions which have been 'accepted'."); "Revision %s can not be closed. You can only close ".
"revisions which have been 'accepted'.",
"D{$revision_id}"));
} }
if ($revision) { if ($revision) {
if (!$is_finalize && $revision['authorPHID'] != $this->getUserPHID()) { if (!$is_finalize && $revision['authorPHID'] != $this->getUserPHID()) {
$prompt = "You are not the author of revision D{$revision_id}, ". $prompt = pht(
'are you sure you want to close it?'; 'You are not the author of revision %s, '.
'are you sure you want to close it?',
"D{$revision_id}");
if (!phutil_console_confirm($prompt)) { if (!phutil_console_confirm($prompt)) {
throw new ArcanistUserAbortException(); throw new ArcanistUserAbortException();
} }
@ -118,7 +128,10 @@ EOTEXT
if ($actually_close) { if ($actually_close) {
$revision_name = $revision['title']; $revision_name = $revision['title'];
echo "Closing revision D{$revision_id} '{$revision_name}'...\n"; echo pht(
"Closing revision %s '%s'...\n",
"D{$revision_id}",
$revision_name);
$conduit->callMethodSynchronous( $conduit->callMethodSynchronous(
'differential.close', 'differential.close',
@ -143,7 +156,7 @@ EOTEXT
$message = $this->getRepositoryAPI()->getFinalizedRevisionMessage(); $message = $this->getRepositoryAPI()->getFinalizedRevisionMessage();
echo phutil_console_wrap($message)."\n"; echo phutil_console_wrap($message)."\n";
} else { } else {
echo "Done.\n"; echo pht('Done.')."\n";
} }
} }

View file

@ -18,13 +18,13 @@ final class ArcanistCloseWorkflow extends ArcanistWorkflow {
private function getStatusOptions() { private function getStatusOptions() {
if ($this->statusData === null) { if ($this->statusData === null) {
throw new Exception('loadStatusData first!'); throw new Exception(pht('Call %s first!', 'loadStatusData()'));
} }
return idx($this->statusData, 'statusMap'); return idx($this->statusData, 'statusMap');
} }
private function getDefaultClosedStatus() { private function getDefaultClosedStatus() {
if ($this->statusData === null) { if ($this->statusData === null) {
throw new Exception('loadStatusData first!'); throw new Exception(pht('Call %s first!', 'loadStatusData()'));
} }
return idx($this->statusData, 'defaultClosedStatus'); return idx($this->statusData, 'defaultClosedStatus');
} }
@ -73,10 +73,11 @@ EOTEXT
'short' => 's', 'short' => 's',
'help' => pht( 'help' => pht(
'Specify a new status. Valid status options can be '. 'Specify a new status. Valid status options can be '.
'seen with the `list-statuses` argument.'), 'seen with the `%s` argument.',
'list-statuses'),
), ),
'list-statuses' => array( 'list-statuses' => array(
'help' => 'Show available status options and exit.', 'help' => pht('Show available status options and exit.'),
), ),
); );
} }
@ -85,9 +86,11 @@ EOTEXT
$this->loadStatusData(); $this->loadStatusData();
$list_statuses = $this->getArgument('list-statuses'); $list_statuses = $this->getArgument('list-statuses');
if ($list_statuses) { if ($list_statuses) {
echo phutil_console_format(pht( echo phutil_console_format(
"Valid status options are:\n". "%s\n",
"\t%s\n", implode($this->getStatusOptions(), ', '))); pht(
"Valid status options are:\n\t%s",
implode($this->getStatusOptions(), ', ')));
return 0; return 0;
} }
$ids = $this->getArgument('task_id'); $ids = $this->getArgument('task_id');
@ -102,23 +105,33 @@ EOTEXT
if (!isset($status_options[$status])) { if (!isset($status_options[$status])) {
$options = array_keys($status_options); $options = array_keys($status_options);
$last = array_pop($options); $last = array_pop($options);
echo "Invalid status {$status}, valid options are ". echo pht(
implode(', ', $options).", or {$last}.\n"; "Invalid status %s, valid options are %s, or %s.\n",
$status,
implode(', ', $options),
$last);
return; return;
} }
foreach ($ids as $id) { foreach ($ids as $id) {
if (!preg_match('/^T?\d+$/', $id)) { if (!preg_match('/^T?\d+$/', $id)) {
echo "Invalid Task ID: {$id}.\n"; echo pht('Invalid Task ID: %s.', $id)."\n";
return 1; return 1;
} }
$id = ltrim($id, 'T'); $id = ltrim($id, 'T');
$result = $this->closeTask($id, $status, $message); $result = $this->closeTask($id, $status, $message);
$current_status = $status_options[$status]; $current_status = $status_options[$status];
if ($result) { if ($result) {
echo "T{$id}'s status is now set to {$current_status}.\n"; echo pht(
"%s's status is now set to %s.\n",
"T{$id}",
$current_status);
} else { } else {
echo "T{$id} is already set to {$current_status}.\n"; echo pht(
"%s is already set to %s.\n",
"T{$id}",
$current_status);
} }
} }
return 0; return 0;

View file

@ -49,15 +49,15 @@ EOTEXT
public function getArguments() { public function getArguments() {
return array( return array(
'show' => array( 'show' => array(
'help' => 'help' => pht(
'Show the command which would be issued, but do not actually '. 'Show the command which would be issued, but do not actually '.
'commit anything.', 'commit anything.'),
), ),
'revision' => array( 'revision' => array(
'param' => 'revision_id', 'param' => 'revision_id',
'help' => 'help' => pht(
'Commit a specific revision. If you do not specify a revision, '. 'Commit a specific revision. If you do not specify a revision, '.
'arc will look for committable revisions.', 'arc will look for committable revisions.'),
), ),
); );
} }
@ -76,13 +76,17 @@ EOTEXT
if (count($revisions) == 0) { if (count($revisions) == 0) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Unable to identify the revision in the working copy. Use ". pht(
"'--revision <revision_id>' to select a revision."); "Unable to identify the revision in the working copy. Use ".
"'%s' to select a revision.",
'--revision <revision_id>'));
} else if (count($revisions) > 1) { } else if (count($revisions) > 1) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"More than one revision exists in the working copy:\n\n". pht(
$this->renderRevisionList($revisions)."\n". "More than one revision exists in the working copy:\n\n%s\n".
"Use '--revision <revision_id>' to select a revision."); "Use '%s' to select a revision.",
$this->renderRevisionList($revisions),
'--revision <revision_id>'));
} }
} else { } else {
@ -94,7 +98,9 @@ EOTEXT
if (count($revisions) == 0) { if (count($revisions) == 0) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Revision 'D{$revision_id}' does not exist."); pht(
"Revision '%s' does not exist.",
"D{$revision_id}"));
} }
} }
@ -129,7 +135,10 @@ EOTEXT
} }
$revision_title = $revision['title']; $revision_title = $revision['title'];
echo "Committing 'D{$revision_id}: {$revision_title}'...\n"; echo pht(
"Committing '%s: %s'...\n",
"D{$revision_id}",
$revision_title);
$files = $this->getCommitFileList($revision); $files = $this->getCommitFileList($revision);
@ -151,7 +160,7 @@ EOTEXT
$err = phutil_passthru('%C', $command); $err = phutil_passthru('%C', $command);
if ($err) { if ($err) {
throw new Exception("Executing 'svn commit' failed!"); throw new Exception(pht("Executing '%s' failed!", 'svn commit'));
} }
$this->askForRepositoryUpdate(); $this->askForRepositoryUpdate();
@ -199,12 +208,15 @@ EOTEXT
foreach ($commit_paths as $will_commit => $ignored) { foreach ($commit_paths as $will_commit => $ignored) {
if (Filesystem::isDescendant($path, $will_commit)) { if (Filesystem::isDescendant($path, $will_commit)) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"This commit includes the directory '{$will_commit}', but ". pht(
"it contains a modified path ('{$path}') which is NOT included ". "This commit includes the directory '%s', but it contains a ".
"in the commit. Subversion can not handle this operation and ". "modified path ('%s') which is NOT included in the commit. ".
"will commit the path anyway. You need to sort out the working ". "Subversion can not handle this operation and will commit the ".
"copy changes to '{$path}' before you may proceed with the ". "path anyway. You need to sort out the working copy changes to ".
"commit."); "'%s' before you may proceed with the commit.",
$will_commit,
$path,
$path));
} }
} }
$modified_but_not_included[] = $path; $modified_but_not_included[] = $path;
@ -249,7 +261,9 @@ EOTEXT
if (empty($files)) { if (empty($files)) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'There is nothing left to commit. None of the modified paths exist.'); pht(
'There is nothing left to commit. '.
'None of the modified paths exist.'));
} }
return $files; return $files;
@ -303,24 +317,29 @@ EOTEXT
$confirm = array(); $confirm = array();
if ($revision['status'] != ArcanistDifferentialRevisionStatus::ACCEPTED) { if ($revision['status'] != ArcanistDifferentialRevisionStatus::ACCEPTED) {
$confirm[] = $confirm[] = pht(
"Revision 'D{$revision_id}: {$revision_title}' has not been accepted. ". "Revision '%s: %s' has not been accepted. Commit this revision anyway?",
"Commit this revision anyway?"; "D{$revision_id}",
$revision_title);
} }
if ($revision['authorPHID'] != $this->getUserPHID()) { if ($revision['authorPHID'] != $this->getUserPHID()) {
$confirm[] = $confirm[] = pht(
"You are not the author of 'D{$revision_id}: {$revision_title}'. ". "You are not the author of '%s: %s'. Commit this revision anyway?",
"Commit this revision anyway?"; "D{$revision_id}",
$revision_title);
} }
$revision_source = idx($revision, 'branch'); $revision_source = idx($revision, 'branch');
$current_source = $repository_api->getBranchName(); $current_source = $repository_api->getBranchName();
if ($revision_source != $current_source) { if ($revision_source != $current_source) {
$confirm[] = $confirm[] = pht(
"Revision 'D{$revision_id}: {$revision_title}' was generated from ". "Revision '%s: %s' was generated from '%s', but current working ".
"'{$revision_source}', but current working copy root is ". "copy root is '%s'. Commit this revision anyway?",
"'{$current_source}'. Commit this revision anyway?"; "D{$revision_id}",
$revision_title,
$revision_source,
$current_source);
} }
foreach ($confirm as $thing) { foreach ($confirm as $thing) {

View file

@ -31,13 +31,13 @@ EOTEXT
return array( return array(
'rev' => array( 'rev' => array(
'param' => 'revision', 'param' => 'revision',
'help' => 'Cover changes since a specific revision.', 'help' => pht('Cover changes since a specific revision.'),
'supports' => array( 'supports' => array(
'git', 'git',
'hg', 'hg',
), ),
'nosupport' => array( 'nosupport' => array(
'svn' => 'cover does not currently support --rev in svn.', 'svn' => pht('cover does not currently support %s in svn.', '--rev'),
), ),
), ),
'*' => 'paths', '*' => 'paths',
@ -78,7 +78,7 @@ EOTEXT
if (!$paths) { if (!$paths) {
throw new ArcanistNoEffectException( throw new ArcanistNoEffectException(
"You're covered, you didn't change anything."); pht("You're covered, you didn't change anything."));
} }
$covers = array(); $covers = array();
@ -126,7 +126,8 @@ EOTEXT
} }
} }
} else { } else {
echo "You're covered, your changes didn't touch anyone else's code.\n"; echo pht(
"You're covered, your changes didn't touch anyone else's code.\n");
} }
return 0; return 0;

View file

@ -2395,9 +2395,12 @@ EOTEXT
$title = $revision['title']; $title = $revision['title'];
throw new ArcanistUsageException( throw new ArcanistUsageException(
"You don't own revision D{$id} '{$title}'. You can only update ". pht(
"revisions you own. You can 'Commandeer' this revision from the web ". "You don't own revision %s '%s'. You can only update revisions ".
"interface if you want to become the owner."); "you own. You can 'Commandeer' this revision from the web ".
"interface if you want to become the owner.",
"D{$id}",
$title));
} }
@ -2524,12 +2527,14 @@ EOTEXT
$change->setMetadata("{$type}:binary-phid", $phid); $change->setMetadata("{$type}:binary-phid", $phid);
echo pht("Uploaded '%s' (%s).", $name, $type)."\n"; echo pht("Uploaded '%s' (%s).", $name, $type)."\n";
} catch (Exception $e) { } catch (Exception $e) {
echo "Failed to upload {$type} binary '{$name}'.\n\n"; echo pht("Failed to upload %s binary '%s'.", $type, $name)."\n\n";
echo $e->getMessage()."\n"; echo $e->getMessage()."\n";
if (!phutil_console_confirm('Continue?', $default_no = false)) { if (!phutil_console_confirm(pht('Continue?'), $default_no = false)) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'Aborted due to file upload failure. You can use --skip-binaries '. pht(
'to skip binary uploads.'); 'Aborted due to file upload failure. You can use %s '.
'to skip binary uploads.',
'--skip-binaries'));
} }
} }
} }

View file

@ -34,15 +34,18 @@ EOTEXT
return array( return array(
'show' => array( 'show' => array(
'conflicts' => array( 'conflicts' => array(
'as' => 'as' => pht(
'Use --show to direct the file to stdout, or --as to direct '. 'Use %s to direct the file to stdout, or %s to direct '.
'it to a named location.', 'it to a named location.',
'--show',
'--as'),
), ),
'help' => 'Write file to stdout instead of to disk.', 'help' => pht('Write file to stdout instead of to disk.'),
), ),
'as' => array( 'as' => array(
'param' => 'name', 'param' => 'name',
'help' => 'Save the file with a specific name rather than the default.', 'help' => pht(
'Save the file with a specific name rather than the default.'),
), ),
'*' => 'argv', '*' => 'argv',
); );
@ -51,15 +54,17 @@ EOTEXT
protected function didParseArguments() { protected function didParseArguments() {
$argv = $this->getArgument('argv'); $argv = $this->getArgument('argv');
if (!$argv) { if (!$argv) {
throw new ArcanistUsageException('Specify a file to download.'); throw new ArcanistUsageException(pht('Specify a file to download.'));
} }
if (count($argv) > 1) { if (count($argv) > 1) {
throw new ArcanistUsageException('Specify exactly one file to download.'); throw new ArcanistUsageException(
pht('Specify exactly one file to download.'));
} }
$file = reset($argv); $file = reset($argv);
if (!preg_match('/^F?\d+$/', $file)) { if (!preg_match('/^F?\d+$/', $file)) {
throw new ArcanistUsageException('Specify file by ID, e.g. F123.'); throw new ArcanistUsageException(
pht('Specify file by ID, e.g. %s.', 'F123'));
} }
$this->id = (int)ltrim($file, 'F'); $this->id = (int)ltrim($file, 'F');
@ -72,10 +77,9 @@ EOTEXT
} }
public function run() { public function run() {
$conduit = $this->getConduit(); $conduit = $this->getConduit();
$this->writeStatusMessage("Getting file information...\n"); $this->writeStatusMessage(pht('Getting file information...')."\n");
$info = $conduit->callMethodSynchronous( $info = $conduit->callMethodSynchronous(
'file.info', 'file.info',
array( array(
@ -88,7 +92,7 @@ EOTEXT
$desc = "'".$info['name']."' ".$desc; $desc = "'".$info['name']."' ".$desc;
} }
$this->writeStatusMessage("Downloading file {$desc}...\n"); $this->writeStatusMessage(pht('Downloading file %s...', $desc)."\n");
$data = $conduit->callMethodSynchronous( $data = $conduit->callMethodSynchronous(
'file.download', 'file.download',
array( array(
@ -103,7 +107,7 @@ EOTEXT
$path = Filesystem::writeUniqueFile( $path = Filesystem::writeUniqueFile(
nonempty($this->saveAs, $info['name'], 'file'), nonempty($this->saveAs, $info['name'], 'file'),
$data); $data);
$this->writeStatusMessage("Saved file as '{$path}'.\n"); $this->writeStatusMessage(pht("Saved file as '%s'.", $path)."\n");
} }
return 0; return 0;

View file

@ -44,39 +44,44 @@ EOTEXT
public function getArguments() { public function getArguments() {
return array( return array(
'git' => array( 'git' => array(
'help' => 'help' => pht(
"Export change as a git patch. This format is more complete than ". "Export change as a git patch. This format is more complete than ".
"unified, but less complete than arc bundles. These patches can be ". "unified, but less complete than arc bundles. These patches can be ".
"applied with 'git apply' or 'arc patch'.", "applied with '%s' or '%s'.",
'git apply',
'arc patch'),
), ),
'unified' => array( 'unified' => array(
'help' => 'help' => pht(
"Export change as a unified patch. This format is less complete ". "Export change as a unified patch. This format is less complete ".
"than git patches or arc bundles. These patches can be applied with ". "than git patches or arc bundles. These patches can be applied with ".
"'patch' or 'arc patch'.", "'%s' or '%s'.",
'patch',
'arc patch'),
), ),
'arcbundle' => array( 'arcbundle' => array(
'param' => 'file', 'param' => 'file',
'help' => 'help' => pht(
"Export change as an arc bundle. This format can represent all ". "Export change as an arc bundle. This format can represent all ".
"changes. These bundles can be applied with 'arc patch'.", "changes. These bundles can be applied with '%s'.",
'arc patch'),
), ),
'encoding' => array( 'encoding' => array(
'param' => 'encoding', 'param' => 'encoding',
'help' => 'help' => pht(
'Attempt to convert non UTF-8 patch into specified encoding.', 'Attempt to convert non UTF-8 patch into specified encoding.'),
), ),
'revision' => array( 'revision' => array(
'param' => 'revision_id', 'param' => 'revision_id',
'help' => 'help' => pht(
'Instead of exporting changes from the working copy, export them '. 'Instead of exporting changes from the working copy, export them '.
'from a Differential revision.', 'from a Differential revision.'),
), ),
'diff' => array( 'diff' => array(
'param' => 'diff_id', 'param' => 'diff_id',
'help' => 'help' => pht(
'Instead of exporting changes from the working copy, export them '. 'Instead of exporting changes from the working copy, export them '.
'from a Differential diff.', 'from a Differential diff.'),
), ),
'*' => 'paths', '*' => 'paths',
); );
@ -102,8 +107,11 @@ EOTEXT
if ($requested > 1) { if ($requested > 1) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Options '--revision' and '--diff' are not compatible. Choose exactly ". pht(
"one change source."); "Options '%s' and '%s' are not compatible. Choose exactly ".
"one change source.",
'--revision',
'--diff'));
} }
$format = null; $format = null;
@ -123,12 +131,19 @@ EOTEXT
if ($requested === 0) { if ($requested === 0) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Specify one of '--git', '--unified' or '--arcbundle <path>' to ". pht(
"choose an export format."); "Specify one of '%s', '%s' or '%s' to choose an export format.",
'--git',
'--unified',
'--arcbundle <path>'));
} else if ($requested > 1) { } else if ($requested > 1) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Options '--git', '--unified' and '--arcbundle' are not compatible. ". pht(
"Choose exactly one export format."); "Options '%s', '%s' and '%s' are not compatible. ".
"Choose exactly one export format.",
'--git',
'--unified',
'--arcbundle'));
} }
$this->format = $format; $this->format = $format;
@ -260,9 +275,9 @@ EOTEXT
break; break;
case self::FORMAT_BUNDLE: case self::FORMAT_BUNDLE:
$path = $this->getArgument('arcbundle'); $path = $this->getArgument('arcbundle');
echo "Writing bundle to '{$path}'...\n"; echo pht("Writing bundle to '%s'...", $path)."\n";
$bundle->writeToDisk($path); $bundle->writeToDisk($path);
echo "done.\n"; echo pht('Done.')."\n";
break; break;
} }

View file

@ -53,17 +53,19 @@ EOTEXT
public function getArguments() { public function getArguments() {
return array( return array(
'view-all' => array( 'view-all' => array(
'help' => 'Include closed and abandoned revisions.', 'help' => pht('Include closed and abandoned revisions.'),
), ),
'by-status' => array( 'by-status' => array(
'help' => 'Sort branches by status instead of time.', 'help' => pht('Sort branches by status instead of time.'),
), ),
'output' => array( 'output' => array(
'param' => 'format', 'param' => 'format',
'support' => array( 'support' => array(
'json', 'json',
), ),
'help' => "With 'json', show features in machine-readable JSON format.", 'help' => pht(
"With '%s', show features in machine-readable JSON format.",
'json'),
), ),
'*' => 'branch', '*' => 'branch',
); );
@ -79,14 +81,15 @@ EOTEXT
$names = $this->getArgument('branch'); $names = $this->getArgument('branch');
if ($names) { if ($names) {
if (count($names) > 2) { if (count($names) > 2) {
throw new ArcanistUsageException('Specify only one branch.'); throw new ArcanistUsageException(pht('Specify only one branch.'));
} }
return $this->checkoutBranch($names); return $this->checkoutBranch($names);
} }
$branches = $repository_api->getAllBranches(); $branches = $repository_api->getAllBranches();
if (!$branches) { if (!$branches) {
throw new ArcanistUsageException('No branches in this working copy.'); throw new ArcanistUsageException(
pht('No branches in this working copy.'));
} }
$branches = $this->loadCommitInfo($branches); $branches = $this->loadCommitInfo($branches);
@ -302,7 +305,7 @@ EOTEXT
$status = $revision['statusName']; $status = $revision['statusName'];
} else { } else {
$desc = $branch['desc']; $desc = $branch['desc'];
$status = 'No Revision'; $status = pht('No Revision');
} }
if (!$this->getArgument('view-all') && !$branch['current']) { if (!$this->getArgument('view-all') && !$branch['current']) {

View file

@ -57,18 +57,18 @@ EOTEXT
return array( return array(
'*' => 'objects', '*' => 'objects',
'clear' => array( 'clear' => array(
'help' => 'Delete the flag on an object.', 'help' => pht('Delete the flag on an object.'),
), ),
'edit' => array( 'edit' => array(
'help' => 'Edit the flag on an object.', 'help' => pht('Edit the flag on an object.'),
), ),
'color' => array( 'color' => array(
'param' => 'color', 'param' => 'color',
'help' => 'Set the color of a flag.', 'help' => pht('Set the color of a flag.'),
), ),
'note' => array( 'note' => array(
'param' => 'note', 'param' => 'note',
'help' => 'Set the note on a flag.', 'help' => pht('Set the note on a flag.'),
), ),
); );
} }
@ -114,10 +114,11 @@ EOTEXT
$editing = $edit || ($color != -1) || $note; $editing = $edit || ($color != -1) || $note;
if ($editing && $clear) { if ($editing && $clear) {
throw new ArcanistUsageException("You can't both edit and clear a flag."); throw new ArcanistUsageException(
pht("You can't both edit and clear a flag."));
} }
if (($editing || $clear) && count($objects) != 1) { if (($editing || $clear) && count($objects) != 1) {
throw new ArcanistUsageException('Specify exactly one object.'); throw new ArcanistUsageException(pht('Specify exactly one object.'));
} }
if (!empty($objects)) { if (!empty($objects)) {
@ -131,7 +132,9 @@ EOTEXT
if (isset($handles[$object])) { if (isset($handles[$object])) {
$phids[$object] = $handles[$object]['phid']; $phids[$object] = $handles[$object]['phid'];
} else { } else {
echo phutil_console_format("**%s** doesn't exist.\n", $object); echo pht(
"%s doesn't exist.\n",
phutil_console_format('**%s**', $object));
} }
} }
if (empty($phids)) { if (empty($phids)) {
@ -153,7 +156,9 @@ EOTEXT
'objectPHID' => head($phids), 'objectPHID' => head($phids),
)); ));
if (!$flag) { if (!$flag) {
echo phutil_console_format("**%s** has no flag to clear.\n", $object); echo pht(
"%s has no flag to clear.\n",
phutil_console_format('**%s**', $object));
} else { } else {
self::flagWasEdited($flag, 'deleted'); self::flagWasEdited($flag, 'deleted');
} }
@ -186,7 +191,9 @@ EOTEXT
'objectPHID'); 'objectPHID');
foreach ($phids as $object => $phid) { foreach ($phids as $object => $phid) {
if (!isset($flags[$phid])) { if (!isset($flags[$phid])) {
echo phutil_console_format("**%s** has no flag.\n", $object); echo pht(
"%s has no flag.\n",
phutil_console_format('**%s**', $object));
} }
} }
@ -196,7 +203,7 @@ EOTEXT
// If the user passed object names, we already told them all their // If the user passed object names, we already told them all their
// objects are nonexistent or unflagged. // objects are nonexistent or unflagged.
if (empty($objects)) { if (empty($objects)) {
echo "You have no flagged objects.\n"; echo pht('You have no flagged objects.')."\n";
} }
} else { } else {
// Print ALL the flags. With fancy formatting. Because fancy formatting // Print ALL the flags. With fancy formatting. Because fancy formatting

View file

@ -163,8 +163,8 @@ EOTEXT
if (!$verbose) { if (!$verbose) {
$console->writeOut( $console->writeOut(
"%s\n", "(%s)\n",
pht('(Run with --verbose for more details.)')); pht('Run with %s for more details.', '--verbose'));
} }
return 0; return 0;

View file

@ -46,7 +46,10 @@ EOTEXT
$target = head($this->getArgument('command')); $target = head($this->getArgument('command'));
if (empty($workflows[$target])) { if (empty($workflows[$target])) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Unrecognized command '{$target}'. Try 'arc help'."); pht(
"Unrecognized command '%s'. Try '%s'.",
$target,
'arc help'));
} }
} }
@ -109,19 +112,19 @@ EOTEXT
} }
if (isset($config_arguments[$argument])) { if (isset($config_arguments[$argument])) {
$optref[] = ' (This is a custom option for this '. $optref[] = ' '.
'project.)'; pht('(This is a custom option for this project.)');
} }
if (isset($spec['supports'])) { if (isset($spec['supports'])) {
$optref[] = ' Supports: '. $optref[] = ' '.
implode(', ', $spec['supports']); pht('Supports: %s', implode(', ', $spec['supports']));
} }
if (isset($spec['help'])) { if (isset($spec['help'])) {
$docs = $spec['help']; $docs = $spec['help'];
} else { } else {
$docs = 'This option is not documented.'; $docs = pht('This option is not documented.');
} }
$docs = phutil_console_wrap($docs, 14); $docs = phutil_console_wrap($docs, 14);
$optref[] = "{$docs}\n"; $optref[] = "{$docs}\n";
@ -163,7 +166,9 @@ EOTEXT
); );
if (!$this->getArgument('full')) { if (!$this->getArgument('full')) {
echo "Run 'arc help --full' to get commands and options descriptions.\n"; echo pht(
"Run '%s' to get commands and options descriptions.\n",
'arc help --full');
return; return;
} }

View file

@ -89,17 +89,17 @@ EOTEXT
// Ignore. // Ignore.
} }
echo phutil_console_format("**LOGIN TO PHABRICATOR**\n"); echo phutil_console_format("**%s**\n", pht('LOGIN TO PHABRICATOR'));
echo "Open this page in your browser and login to Phabricator if ". echo phutil_console_format(
"necessary:\n"; "%s\n\n%s\n\n%s",
echo "\n"; pht(
echo " {$token_uri}\n"; 'Open this page in your browser and login to '.
echo "\n"; 'Phabricator if necessary:'),
echo 'Then paste the API Token on that page below.'; $token_uri,
pht('Then paste the API Token on that page below.'));
do { do {
$token = phutil_console_prompt('Paste API Token from that page:'); $token = phutil_console_prompt(pht('Paste API Token from that page:'));
$token = trim($token); $token = trim($token);
if (strlen($token)) { if (strlen($token)) {
break; break;
@ -142,7 +142,7 @@ EOTEXT
); );
} else { } else {
echo "\n"; echo "\n";
echo "Downloading authentication certificate...\n"; echo pht('Downloading authentication certificate...')."\n";
$info = $conduit->callMethodSynchronous( $info = $conduit->callMethodSynchronous(
'conduit.getcertificate', 'conduit.getcertificate',
array( array(
@ -151,22 +151,26 @@ EOTEXT
)); ));
$user = $info['username']; $user = $info['username'];
echo "Installing certificate for '{$user}'...\n"; echo pht("Installing certificate for '%s'...", $user)."\n";
$config['hosts'][$uri] = array( $config['hosts'][$uri] = array(
'user' => $user, 'user' => $user,
'cert' => $info['certificate'], 'cert' => $info['certificate'],
); );
} }
echo "Writing ~/.arcrc...\n"; echo pht('Writing %s...', '~/.arcrc')."\n";
$configuration_manager->writeUserConfigurationFile($config); $configuration_manager->writeUserConfigurationFile($config);
if ($is_token_auth) { if ($is_token_auth) {
echo phutil_console_format( echo phutil_console_format(
"<bg:green>** SUCCESS! **</bg> API Token installed.\n"); "<bg:green>** %s **</bg> %s\n",
pht('SUCCESS!'),
pht('API Token installed.'));
} else { } else {
echo phutil_console_format( echo phutil_console_format(
"<bg:green>** SUCCESS! **</bg> Certificate installed.\n"); "<bg:green>** %s **</bg> %s\n",
pht('SUCCESS!'),
pht('Certificate installed.'));
} }
return 0; return 0;
@ -175,15 +179,17 @@ EOTEXT
private function determineConduitURI() { private function determineConduitURI() {
$uri = $this->getArgument('uri'); $uri = $this->getArgument('uri');
if (count($uri) > 1) { if (count($uri) > 1) {
throw new ArcanistUsageException('Specify at most one URI.'); throw new ArcanistUsageException(pht('Specify at most one URI.'));
} else if (count($uri) == 1) { } else if (count($uri) == 1) {
$uri = reset($uri); $uri = reset($uri);
} else { } else {
$conduit_uri = $this->getConduitURI(); $conduit_uri = $this->getConduitURI();
if (!$conduit_uri) { if (!$conduit_uri) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'Specify an explicit URI or run this command from within a project '. pht(
'which is configured with a .arcconfig.'); 'Specify an explicit URI or run this command from within a '.
'project which is configured with a %s.',
'.arcconfig'));
} }
$uri = $conduit_uri; $uri = $conduit_uri;
} }

View file

@ -83,8 +83,10 @@ EOTEXT
'help' => pht( 'help' => pht(
"Land feature branch onto a branch other than the default ". "Land feature branch onto a branch other than the default ".
"('master' in git, 'default' in hg). You can change the default ". "('master' in git, 'default' in hg). You can change the default ".
"by setting 'arc.land.onto.default' with `arc set-config` or ". "by setting '%s' with `%s` or for the entire project in %s.",
"for the entire project in .arcconfig."), 'arc.land.onto.default',
'arc set-config',
'.arcconfig'),
), ),
'hold' => array( 'hold' => array(
'help' => pht( 'help' => pht(
@ -102,22 +104,31 @@ EOTEXT
), ),
'merge' => array( 'merge' => array(
'help' => pht( 'help' => pht(
'Perform a --no-ff merge, not a --squash merge. If the project '. 'Perform a %s merge, not a %s merge. If the project '.
'is marked as having an immutable history, this is the default '. 'is marked as having an immutable history, this is the default '.
'behavior.'), 'behavior.',
'--no-ff',
'--squash'),
'supports' => array( 'supports' => array(
'git', 'git',
), ),
'nosupport' => array( 'nosupport' => array(
'hg' => pht('Use the --squash strategy when landing in mercurial.'), 'hg' => pht(
'Use the %s strategy when landing in mercurial.',
'--squash'),
), ),
), ),
'squash' => array( 'squash' => array(
'help' => pht( 'help' => pht(
'Perform a --squash merge, not a --no-ff merge. If the project is '. 'Perform a %s merge, not a %s merge. If the project is '.
'marked as having a mutable history, this is the default behavior.'), 'marked as having a mutable history, this is the default behavior.',
'--squash',
'--no-ff'),
'conflicts' => array( 'conflicts' => array(
'merge' => '--merge and --squash are conflicting merge strategies.', 'merge' => pht(
'%s and %s are conflicting merge strategies.',
'--merge',
'--squash'),
), ),
), ),
'delete-remote' => array( 'delete-remote' => array(
@ -131,12 +142,16 @@ EOTEXT
'help' => pht( 'help' => pht(
"When updating the feature branch, use rebase instead of merge. ". "When updating the feature branch, use rebase instead of merge. ".
"This might make things work better in some cases. Set ". "This might make things work better in some cases. Set ".
"arc.land.update.default to 'rebase' to make this the default."), "%s to '%s' to make this the default.",
'arc.land.update.default',
'rebase'),
'conflicts' => array( 'conflicts' => array(
'merge' => pht( 'merge' => pht(
'The --merge strategy does not update the feature branch.'), 'The %s strategy does not update the feature branch.',
'--merge'),
'update-with-merge' => pht( 'update-with-merge' => pht(
'Cannot be used with --update-with-merge.'), 'Cannot be used with %s.',
'--update-with-merge'),
), ),
'supports' => array( 'supports' => array(
'git', 'git',
@ -145,13 +160,17 @@ EOTEXT
'update-with-merge' => array( 'update-with-merge' => array(
'help' => pht( 'help' => pht(
"When updating the feature branch, use merge instead of rebase. ". "When updating the feature branch, use merge instead of rebase. ".
"This is the default behavior. Setting arc.land.update.default to ". "This is the default behavior. Setting %s to '%s' can also be ".
"'merge' can also be used to make this the default."), "used to make this the default.",
'arc.land.update.default',
'merge'),
'conflicts' => array( 'conflicts' => array(
'merge' => pht( 'merge' => pht(
'The --merge strategy does not update the feature branch.'), 'The %s strategy does not update the feature branch.',
'--merge'),
'update-with-rebase' => pht( 'update-with-rebase' => pht(
'Cannot be used with --update-with-rebase.'), 'Cannot be used with %s.',
'--update-with-rebase'),
), ),
'supports' => array( 'supports' => array(
'git', 'git',
@ -329,7 +348,7 @@ EOTEXT
$this->branch, $this->branch,
$this->onto); $this->onto);
if (!$this->isHistoryImmutable()) { if (!$this->isHistoryImmutable()) {
$message .= ' '.pht("You may be able to 'arc amend' instead."); $message .= ' '.pht("You may be able to '%s' instead.", 'arc amend');
} }
throw new ArcanistUsageException($message); throw new ArcanistUsageException($message);
} }
@ -339,23 +358,26 @@ EOTEXT
if (!$repository_api->supportsRebase()) { if (!$repository_api->supportsRebase()) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
pht( pht(
'You must enable the rebase extension to use the --squash '. 'You must enable the rebase extension to use the %s strategy.',
'strategy.')); '--squash'));
} }
} }
if ($this->branchType != $this->ontoType) { if ($this->branchType != $this->ontoType) {
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(pht(
'Source %s is a %s but destination %s is a %s. When landing a '. 'Source %s is a %s but destination %s is a %s. When landing a '.
'%s, the destination must also be a %s. Use --onto to specify a %s, '. '%s, the destination must also be a %s. Use %s to specify a %s, '.
'or set arc.land.onto.default in .arcconfig.', 'or set %s in %s.',
$this->branch, $this->branch,
$this->branchType, $this->branchType,
$this->onto, $this->onto,
$this->ontoType, $this->ontoType,
$this->branchType, $this->branchType,
$this->branchType, $this->branchType,
$this->branchType)); '--onto',
$this->branchType,
'arc.land.onto.default',
'.arcconfig'));
} }
} }
@ -376,16 +398,15 @@ EOTEXT
private function checkoutBranch() { private function checkoutBranch() {
$repository_api = $this->getRepositoryAPI(); $repository_api = $this->getRepositoryAPI();
if ($this->getBranchOrBookmark() != $this->branch) { if ($this->getBranchOrBookmark() != $this->branch) {
$repository_api->execxLocal( $repository_api->execxLocal('checkout %s', $this->branch);
'checkout %s',
$this->branch);
} }
echo phutil_console_format( echo phutil_console_format(
pht('Switched to %s **%s**. Identifying and merging...', "%s\n",
$this->branchType, pht(
$this->branch). 'Switched to %s **%s**. Identifying and merging...',
"\n"); $this->branchType,
$this->branch));
} }
private function printPendingCommits() { private function printPendingCommits() {
@ -417,7 +438,7 @@ EOTEXT
if (!trim($out)) { if (!trim($out)) {
$this->restoreBranch(); $this->restoreBranch();
throw new ArcanistUsageException( throw new ArcanistUsageException(
pht('No commits to land from %s.', $this->branch)); pht('No commits to land from %s.', $this->branch));
} }
echo pht("The following commit(s) will be landed:\n\n%s", $out), "\n"; echo pht("The following commit(s) will be landed:\n\n%s", $out), "\n";
@ -451,11 +472,13 @@ EOTEXT
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(pht(
"arc can not identify which revision exists on %s '%s'. Update the ". "arc can not identify which revision exists on %s '%s'. Update the ".
"revision with recent changes to synchronize the %s name and hashes, ". "revision with recent changes to synchronize the %s name and hashes, ".
"or use 'arc amend' to amend the commit message at HEAD, or use ". "or use '%s' to amend the commit message at HEAD, or use ".
"'--revision <id>' to select a revision explicitly.", "'%s' to select a revision explicitly.",
$this->branchType, $this->branchType,
$this->branch, $this->branch,
$this->branchType)); $this->branchType,
'arc amend',
'--revision <id>'));
} else if (count($revisions) > 1) { } else if (count($revisions) > 1) {
$message = pht( $message = pht(
"There are multiple revisions on feature %s '%s' which are not ". "There are multiple revisions on feature %s '%s' which are not ".
@ -531,9 +554,10 @@ EOTEXT
} }
$open_revs = implode("\n", $open_revs); $open_revs = implode("\n", $open_revs);
echo pht("Revision '%s' depends on open revisions:\n\n%s", echo pht(
"D{$rev_id}: {$rev_title}", "Revision '%s' depends on open revisions:\n\n%s",
$open_revs); "D{$rev_id}: {$rev_title}",
$open_revs);
$ok = phutil_console_confirm(pht('Continue anyway?')); $ok = phutil_console_confirm(pht('Continue anyway?'));
if (!$ok) { if (!$ok) {
@ -552,8 +576,9 @@ EOTEXT
$this->messageFile = new TempFile(); $this->messageFile = new TempFile();
Filesystem::writeFile($this->messageFile, $message); Filesystem::writeFile($this->messageFile, $message);
echo pht("Landing revision '%s'...", echo pht(
"D{$rev_id}: {$rev_title}"), "\n"; "Landing revision '%s'...",
"D{$rev_id}: {$rev_title}")."\n";
$diff_phid = idx($this->revision, 'activeDiffPHID'); $diff_phid = idx($this->revision, 'activeDiffPHID');
if ($diff_phid) { if ($diff_phid) {
@ -590,9 +615,7 @@ EOTEXT
} }
} else if ($this->isHg) { } else if ($this->isHg) {
echo phutil_console_format(pht( echo phutil_console_format(pht('Updating **%s**...', $this->onto)."\n");
'Updating **%s**...',
$this->onto)."\n");
try { try {
list($out, $err) = $repository_api->execxLocal('pull'); list($out, $err) = $repository_api->execxLocal('pull');
@ -602,10 +625,11 @@ EOTEXT
throw new ArcanistUsageException(phutil_console_format(pht( throw new ArcanistUsageException(phutil_console_format(pht(
"Local bookmark **%s** has diverged from the server's **%s** ". "Local bookmark **%s** has diverged from the server's **%s** ".
"(now labeled **%s**). Please resolve this divergence and run ". "(now labeled **%s**). Please resolve this divergence and run ".
"'arc land' again.", "'%s' again.",
$this->onto, $this->onto,
$this->onto, $this->onto,
$divergedbookmark))); $divergedbookmark,
'arc land')));
} }
} catch (CommandException $ex) { } catch (CommandException $ex) {
$err = $ex->getError(); $err = $ex->getError();
@ -659,13 +683,14 @@ EOTEXT
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(pht(
"Local %s '%s' is ahead of remote %s '%s', so landing a feature ". "Local %s '%s' is ahead of remote %s '%s', so landing a feature ".
"%s would push additional changes. Push or reset the changes in '%s' ". "%s would push additional changes. Push or reset the changes in '%s' ".
"before running 'arc land'.", "before running '%s'.",
$this->ontoType, $this->ontoType,
$this->onto, $this->onto,
$this->ontoType, $this->ontoType,
$this->ontoRemoteBranch, $this->ontoRemoteBranch,
$this->ontoType, $this->ontoType,
$this->onto)); $this->onto,
'arc land'));
} }
} }
@ -682,11 +707,13 @@ EOTEXT
$err = phutil_passthru('git rebase %s', $this->onto); $err = phutil_passthru('git rebase %s', $this->onto);
if ($err) { if ($err) {
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(pht(
"'git rebase %s' failed. You can abort with 'git rebase ". "'%s' failed. You can abort with '%s', or resolve conflicts ".
"--abort', or resolve conflicts and use 'git rebase --continue' ". "and use '%s' to continue forward. After resolving the rebase, ".
"to continue forward. After resolving the rebase, run 'arc land' ". "run '%s' again.",
"again.", sprintf('git rebase %s', $this->onto),
$this->onto)); 'git rebase --abort',
'git rebase --continue',
'arc land'));
} }
} else { } else {
echo phutil_console_format(pht( echo phutil_console_format(pht(
@ -696,21 +723,20 @@ EOTEXT
$err = phutil_passthru( $err = phutil_passthru(
'git merge --no-stat %s -m %s', 'git merge --no-stat %s -m %s',
$this->onto, $this->onto,
pht("Automatic merge by 'arc land'")); pht("Automatic merge by '%s'", 'arc land'));
if ($err) { if ($err) {
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(pht(
"'git merge %s' failed. ". "'%s' failed. To continue: resolve the conflicts, commit ".
"To continue: resolve the conflicts, commit the changes, then run ". "the changes, then run '%s' again. To abort: run '%s'.",
"'arc land' again. To abort: run 'git merge --abort'.", sprintf('git merge %s', $this->onto),
$this->onto)); 'arc land',
'git merge --abort'));
} }
} }
} else if ($this->isHg) { } else if ($this->isHg) {
$onto_tip = $repository_api->getCanonicalRevisionName($this->onto); $onto_tip = $repository_api->getCanonicalRevisionName($this->onto);
$common_ancestor = $repository_api->getCanonicalRevisionName( $common_ancestor = $repository_api->getCanonicalRevisionName(
hgsprintf('ancestor(%s, %s)', hgsprintf('ancestor(%s, %s)', $this->onto, $this->branch));
$this->onto,
$this->branch));
// Only rebase if the local branch is not at the tip of the onto branch. // Only rebase if the local branch is not at the tip of the onto branch.
if ($onto_tip != $common_ancestor) { if ($onto_tip != $common_ancestor) {
@ -719,17 +745,17 @@ EOTEXT
'rebase -d %s --keepbranches', 'rebase -d %s --keepbranches',
$this->onto); $this->onto);
if ($err) { if ($err) {
echo phutil_console_format("Aborting rebase\n"); echo phutil_console_format("%s\n", pht('Aborting rebase'));
$repository_api->execManualLocal( $repository_api->execManualLocal('rebase --abort');
'rebase --abort');
$this->restoreBranch(); $this->restoreBranch();
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(pht(
"'hg rebase %s' failed and the rebase was aborted. ". "'%s' failed and the rebase was aborted. This is most ".
"This is most likely due to conflicts. Manually rebase %s onto ". "likely due to conflicts. Manually rebase %s onto %s, resolve ".
"%s, resolve the conflicts, then run 'arc land' again.", "the conflicts, then run '%s' again.",
$this->onto, sprintf('hg rebase %s', $this->onto),
$this->branch, $this->branch,
$this->onto)); $this->onto,
'arc land'));
} }
} }
} }
@ -789,12 +815,14 @@ EOTEXT
$this->onto); $this->onto);
if ($err) { if ($err) {
$repository_api->execManualLocal( $repository_api->execManualLocal('rebase --abort');
'rebase --abort');
$this->restoreBranch(); $this->restoreBranch();
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Squashing the commits under {$this->branch} failed. ". pht(
"Manually squash your commits and run 'arc land' again."); "Squashing the commits under %s failed. ".
"Manually squash your commits and run '%s' again.",
$this->branch,
'arc land'));
} }
if ($repository_api->isBookmark($this->branch)) { if ($repository_api->isBookmark($this->branch)) {
@ -903,10 +931,11 @@ EOTEXT
$branch_string = implode("\n", $alt_branches); $branch_string = implode("\n", $alt_branches);
echo echo
"\n", "\n",
pht("Remove the %s starting at these revisions and ". pht(
"run arc land again:\n%s", "Remove the %s starting at these revisions and run %s again:\n%s",
$this->branchType.'s', $this->branchType.'s',
$branch_string), $branch_string,
'arc land'),
"\n\n"; "\n\n";
throw new ArcanistUserAbortException(); throw new ArcanistUserAbortException();
} else { } else {
@ -931,9 +960,11 @@ EOTEXT
if ($err) { if ($err) {
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(pht(
"'git merge' failed. Your working copy has been left in a partially ". "'%s' failed. Your working copy has been left in a partially ".
"merged state. You can: abort with 'git merge --abort'; or follow ". "merged state. You can: abort with '%s'; or follow the ".
"the instructions to complete the merge.")); "instructions to complete the merge.",
'git merge',
'git merge --abort'));
} }
} else if ($this->isHg) { } else if ($this->isHg) {
// HG arc land currently doesn't support --merge. // HG arc land currently doesn't support --merge.
@ -943,20 +974,18 @@ EOTEXT
// until there is a demand for it. // until there is a demand for it.
// The user should never reach this line, since --merge is // The user should never reach this line, since --merge is
// forbidden at the command line argument level. // forbidden at the command line argument level.
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(
'--merge is not currently supported for hg repos.')); pht('%s is not currently supported for hg repos.', '--merge'));
} }
} }
private function push() { private function push() {
$repository_api = $this->getRepositoryAPI(); $repository_api = $this->getRepositoryAPI();
// these commands can fail legitimately (e.g. commit hooks) // These commands can fail legitimately (e.g. commit hooks)
try { try {
if ($this->isGit) { if ($this->isGit) {
$repository_api->execxLocal( $repository_api->execxLocal('commit -F %s', $this->messageFile);
'commit -F %s',
$this->messageFile);
if (phutil_is_windows()) { if (phutil_is_windows()) {
// Occasionally on large repositories on Windows, Git can exit with // Occasionally on large repositories on Windows, Git can exit with
// an unclean working copy here. This prevents reverts from being // an unclean working copy here. This prevents reverts from being
@ -995,18 +1024,13 @@ EOTEXT
$err = phutil_passthru('git svn dcommit'); $err = phutil_passthru('git svn dcommit');
$cmd = 'git svn dcommit'; $cmd = 'git svn dcommit';
} else if ($this->isGit) { } else if ($this->isGit) {
$err = phutil_passthru( $err = phutil_passthru('git push %s %s', $this->remote, $this->onto);
'git push %s %s',
$this->remote,
$this->onto);
$cmd = 'git push'; $cmd = 'git push';
} else if ($this->isHgSvn) { } else if ($this->isHgSvn) {
// hg-svn doesn't support 'push -r', so we do a normal push // hg-svn doesn't support 'push -r', so we do a normal push
// which hg-svn modifies to only push the current branch and // which hg-svn modifies to only push the current branch and
// ancestors. // ancestors.
$err = $repository_api->execPassthru( $err = $repository_api->execPassthru('push %s', $this->remote);
'push %s',
$this->remote);
$cmd = 'hg push'; $cmd = 'hg push';
} else if ($this->isHg) { } else if ($this->isHg) {
$err = $repository_api->execPassthru( $err = $repository_api->execPassthru(
@ -1017,13 +1041,15 @@ EOTEXT
} }
if ($err) { if ($err) {
$failed_str = pht('PUSH FAILED!'); echo phutil_console_format(
echo phutil_console_format("<bg:red>** %s **</bg>\n", $failed_str); "<bg:red>** %s **</bg>\n",
pht('PUSH FAILED!'));
$this->executeCleanupAfterFailedPush(); $this->executeCleanupAfterFailedPush();
if ($this->isGit) { if ($this->isGit) {
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(pht(
"'%s' failed! Fix the error and run 'arc land' again.", "'%s' failed! Fix the error and run '%s' again.",
$cmd)); $cmd,
'arc land'));
} }
throw new ArcanistUsageException(pht( throw new ArcanistUsageException(pht(
"'%s' failed! Fix the error and push this change manually.", "'%s' failed! Fix the error and push this change manually.",
@ -1072,14 +1098,10 @@ EOTEXT
$this->branch, $this->branch,
$ref); $ref);
echo pht('(Use `%s` if you want it back.)', $recovery_command), "\n"; echo pht('(Use `%s` if you want it back.)', $recovery_command), "\n";
$repository_api->execxLocal( $repository_api->execxLocal('branch -D %s', $this->branch);
'branch -D %s',
$this->branch);
} else if ($this->isHg) { } else if ($this->isHg) {
$common_ancestor = $repository_api->getCanonicalRevisionName( $common_ancestor = $repository_api->getCanonicalRevisionName(
hgsprintf('ancestor(%s,%s)', hgsprintf('ancestor(%s,%s)', $this->onto, $this->branch));
$this->onto,
$this->branch));
$branch_root = $repository_api->getCanonicalRevisionName( $branch_root = $repository_api->getCanonicalRevisionName(
hgsprintf('first((%s::%s)-%s)', hgsprintf('first((%s::%s)-%s)',
@ -1092,9 +1114,7 @@ EOTEXT
$branch_root); $branch_root);
if ($repository_api->isBookmark($this->branch)) { if ($repository_api->isBookmark($this->branch)) {
$repository_api->execxLocal( $repository_api->execxLocal('bookmark -d %s', $this->branch);
'bookmark -d %s',
$this->branch);
} }
} }
@ -1106,8 +1126,10 @@ EOTEXT
$this->branch); $this->branch);
if ($err) { if ($err) {
echo pht('No remote feature %s to clean up.', echo pht(
$this->branchType), "\n"; 'No remote feature %s to clean up.',
$this->branchType);
echo "\n";
} else { } else {
// NOTE: In Git, you delete a remote branch by pushing it with a // NOTE: In Git, you delete a remote branch by pushing it with a
@ -1166,16 +1188,14 @@ EOTEXT
*/ */
private function restoreBranch() { private function restoreBranch() {
$repository_api = $this->getRepositoryAPI(); $repository_api = $this->getRepositoryAPI();
$repository_api->execxLocal( $repository_api->execxLocal('checkout %s', $this->oldBranch);
'checkout %s',
$this->oldBranch);
if ($this->isGit) { if ($this->isGit) {
$repository_api->execxLocal( $repository_api->execxLocal('submodule update --init --recursive');
'submodule update --init --recursive');
} }
echo phutil_console_format( echo pht(
"Switched back to {$this->branchType} **%s**.\n", "Switched back to %s %s.\n",
$this->oldBranch); $this->branchType,
phutil_console_format('**%s**', $this->oldBranch));
} }
@ -1212,8 +1232,7 @@ EOTEXT
$console->writeOut( $console->writeOut(
"**<bg:green> %s </bg>** %s\n", "**<bg:green> %s </bg>** %s\n",
pht('BUILDS PASSED'), pht('BUILDS PASSED'),
pht( pht('Harbormaster builds for the active diff completed successfully.'));
'Harbormaster builds for the active diff completed successfully.'));
return; return;
} }

View file

@ -34,35 +34,35 @@ EOTEXT
public function getArguments() { public function getArguments() {
return array( return array(
'all' => array( 'all' => array(
'help' => 'help' => pht(
'Drop the module cache before liberating. This will completely '. 'Drop the module cache before liberating. This will completely '.
'reanalyze the entire library. Thorough, but slow!', 'reanalyze the entire library. Thorough, but slow!'),
), ),
'force-update' => array( 'force-update' => array(
'help' => 'help' => pht(
'Force the library map to be updated, even in the presence of '. 'Force the library map to be updated, even in the presence of '.
'lint errors.', 'lint errors.'),
), ),
'library-name' => array( 'library-name' => array(
'param' => 'name', 'param' => 'name',
'help' => 'help' =>
'Use a flag for library name rather than awaiting user input.', pht('Use a flag for library name rather than awaiting user input.'),
), ),
'remap' => array( 'remap' => array(
'hide' => true, 'hide' => true,
'help' => 'help' => pht(
'Internal. Run the remap step of liberation. You do not need to '. 'Internal. Run the remap step of liberation. You do not need to '.
'run this unless you are debugging the workflow.', 'run this unless you are debugging the workflow.'),
), ),
'verify' => array( 'verify' => array(
'hide' => true, 'hide' => true,
'help' => 'help' => pht(
'Internal. Run the verify step of liberation. You do not need to '. 'Internal. Run the verify step of liberation. You do not need to '.
'run this unless you are debugging the workflow.', 'run this unless you are debugging the workflow.'),
), ),
'upgrade' => array( 'upgrade' => array(
'hide' => true, 'hide' => true,
'help' => 'Experimental. Upgrade library to v2.', 'help' => pht('Experimental. Upgrade library to v2.'),
), ),
'*' => 'argv', '*' => 'argv',
); );
@ -72,8 +72,10 @@ EOTEXT
$argv = $this->getArgument('argv'); $argv = $this->getArgument('argv');
if (count($argv) > 1) { if (count($argv) > 1) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Provide only one path to 'arc liberate'. The path should be a ". pht(
"directory where you want to create or update a libphutil library."); "Provide only one path to '%s'. The path should be a directory ".
"where you want to create or update a libphutil library.",
'arc liberate'));
} else if (count($argv) == 0) { } else if (count($argv) == 0) {
$path = getcwd(); $path = getcwd();
} else { } else {
@ -96,8 +98,9 @@ EOTEXT
if ($init) { if ($init) {
if (count($init) > 1) { if (count($init) > 1) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'Specified directory contains more than one libphutil library. Use '. pht(
'a more specific path.'); 'Specified directory contains more than one libphutil library. '.
'Use a more specific path.'));
} }
$path = Filesystem::resolvePath(dirname(reset($init)), $path); $path = Filesystem::resolvePath(dirname(reset($init)), $path);
} else { } else {
@ -110,7 +113,7 @@ EOTEXT
} }
} }
if (!$found) { if (!$found) {
echo "No library currently exists at that path...\n"; echo pht("No library currently exists at that path...\n");
$this->liberateCreateDirectory($path); $this->liberateCreateDirectory($path);
$this->liberateCreateLibrary($path); $this->liberateCreateLibrary($path);
return; return;
@ -124,17 +127,19 @@ EOTEXT
return $this->upgradeLibrary($path); return $this->upgradeLibrary($path);
} }
throw new ArcanistUsageException( throw new ArcanistUsageException(
"This library is using libphutil v1, which is no longer supported. ". pht(
"Run 'arc liberate --upgrade' to upgrade to v2."); "This library is using libphutil v1, which is no ".
"longer supported. Run '%s' to upgrade to v2.",
'arc liberate --upgrade'));
case 2: case 2:
if ($this->getArgument('upgrade')) { if ($this->getArgument('upgrade')) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Can't upgrade a v2 library!"); pht("Can't upgrade a v2 library!"));
} }
return $this->liberateVersion2($path); return $this->liberateVersion2($path);
default: default:
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Unknown library version '{$version}'!"); pht("Unknown library version '%s'!", $version));
} }
} }
@ -171,12 +176,12 @@ EOTEXT
->withType('f') ->withType('f')
->find(); ->find();
echo "Removing __init__.php files...\n"; echo pht('Removing %s files...', '__init__.php')."\n";
foreach ($inits as $init) { foreach ($inits as $init) {
Filesystem::remove($path.'/'.$init); Filesystem::remove($path.'/'.$init);
} }
echo "Upgrading library to v2...\n"; echo pht('Upgrading library to v2...')."\n";
$this->liberateVersion2($path); $this->liberateVersion2($path);
} }
@ -184,14 +189,15 @@ EOTEXT
if (Filesystem::pathExists($path)) { if (Filesystem::pathExists($path)) {
if (!is_dir($path)) { if (!is_dir($path)) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'Provide a directory to create or update a libphutil library in.'); pht(
'Provide a directory to create or update a libphutil library in.'));
} }
return; return;
} }
echo "The directory '{$path}' does not exist."; echo pht("The directory '%s' does not exist.", $path);
if (!phutil_console_confirm('Do you want to create it?')) { if (!phutil_console_confirm(pht('Do you want to create it?'))) {
throw new ArcanistUsageException('Cancelled.'); throw new ArcanistUsageException(pht('Canceled.'));
} }
execx('mkdir -p %s', $path); execx('mkdir -p %s', $path);
@ -203,21 +209,22 @@ EOTEXT
return; return;
} }
echo "Creating new libphutil library in '{$path}'.\n"; echo pht("Creating new libphutil library in '%s'.", $path)."\n";
do { do {
$name = $this->getArgument('library-name'); $name = $this->getArgument('library-name');
if ($name === null) { if ($name === null) {
echo "Choose a name for the new library.\n"; echo pht('Choose a name for the new library.')."\n";
$name = phutil_console_prompt('What do you want to name this library?'); $name = phutil_console_prompt(
pht('What do you want to name this library?'));
} else { } else {
echo "Using library name {$name}.\n"; echo pht('Using library name %s.', $name)."\n";
} }
if (preg_match('/^[a-z-]+$/', $name)) { if (preg_match('/^[a-z-]+$/', $name)) {
break; break;
} else { } else {
echo "Library name should contain only lowercase letters and ". echo pht(
"hyphens.\n"; 'Library name should contain only lowercase letters and hyphens.')."\n";
} }
} while (true); } while (true);
@ -225,7 +232,10 @@ EOTEXT
"<?php\n\n". "<?php\n\n".
"phutil_register_library('{$name}', __FILE__);\n"; "phutil_register_library('{$name}', __FILE__);\n";
echo "Writing '__phutil_library_init__.php' to '{$path}'...\n"; echo pht(
"Writing '%s' to '%s'...\n",
'__phutil_library_init__.php',
$path);
Filesystem::writeFile($init_path, $template); Filesystem::writeFile($init_path, $template);
$this->liberateVersion2($path); $this->liberateVersion2($path);
} }

View file

@ -60,99 +60,104 @@ EOTEXT
public function getArguments() { public function getArguments() {
return array( return array(
'lintall' => array( 'lintall' => array(
'help' => 'help' => pht(
'Show all lint warnings, not just those on changed lines. When '. 'Show all lint warnings, not just those on changed lines. When '.
'paths are specified, this is the default behavior.', 'paths are specified, this is the default behavior.'),
'conflicts' => array( 'conflicts' => array(
'only-changed' => true, 'only-changed' => true,
), ),
), ),
'only-changed' => array( 'only-changed' => array(
'help' => 'help' => pht(
'Show lint warnings just on changed lines. When no paths are '. 'Show lint warnings just on changed lines. When no paths are '.
'specified, this is the default. This differs from only-new '. 'specified, this is the default. This differs from only-new '.
'in cases where line modifications introduce lint on other '. 'in cases where line modifications introduce lint on other '.
'unmodified lines.', 'unmodified lines.'),
'conflicts' => array( 'conflicts' => array(
'lintall' => true, 'lintall' => true,
), ),
), ),
'rev' => array( 'rev' => array(
'param' => 'revision', 'param' => 'revision',
'help' => 'Lint changes since a specific revision.', 'help' => pht('Lint changes since a specific revision.'),
'supports' => array( 'supports' => array(
'git', 'git',
'hg', 'hg',
), ),
'nosupport' => array( 'nosupport' => array(
'svn' => 'Lint does not currently support --rev in SVN.', 'svn' => pht('Lint does not currently support %s in SVN.', '--rev'),
), ),
), ),
'output' => array( 'output' => array(
'param' => 'format', 'param' => 'format',
'help' => 'help' => pht(
"With 'summary', show lint warnings in a more compact format. ". "With 'summary', show lint warnings in a more compact format. ".
"With 'json', show lint warnings in machine-readable JSON format. ". "With 'json', show lint warnings in machine-readable JSON format. ".
"With 'none', show no lint warnings. ". "With 'none', show no lint warnings. ".
"With 'compiler', show lint warnings in suitable for your editor. ". "With 'compiler', show lint warnings in suitable for your editor. ".
"With 'xml', show lint warnings in the Checkstyle XML format.", "With 'xml', show lint warnings in the Checkstyle XML format."),
), ),
'only-new' => array( 'only-new' => array(
'param' => 'bool', 'param' => 'bool',
'supports' => array('git', 'hg'), // TODO: svn 'supports' => array('git', 'hg'), // TODO: svn
'help' => 'Display only messages not present in the original code.', 'help' => pht(
'Display only messages not present in the original code.'),
), ),
'engine' => array( 'engine' => array(
'param' => 'classname', 'param' => 'classname',
'help' => 'help' => pht('Override configured lint engine for this project.'),
'Override configured lint engine for this project.',
), ),
'apply-patches' => array( 'apply-patches' => array(
'help' => 'help' => pht(
'Apply patches suggested by lint to the working copy without '. 'Apply patches suggested by lint to the working copy without '.
'prompting.', 'prompting.'),
'conflicts' => array( 'conflicts' => array(
'never-apply-patches' => true, 'never-apply-patches' => true,
), ),
), ),
'never-apply-patches' => array( 'never-apply-patches' => array(
'help' => 'Never apply patches suggested by lint.', 'help' => pht('Never apply patches suggested by lint.'),
'conflicts' => array( 'conflicts' => array(
'apply-patches' => true, 'apply-patches' => true,
), ),
), ),
'amend-all' => array( 'amend-all' => array(
'help' => 'help' => pht(
'When linting git repositories, amend HEAD with all patches '. 'When linting git repositories, amend HEAD with all patches '.
'suggested by lint without prompting.', 'suggested by lint without prompting.'),
), ),
'amend-autofixes' => array( 'amend-autofixes' => array(
'help' => 'help' => pht(
'When linting git repositories, amend HEAD with autofix '. 'When linting git repositories, amend HEAD with autofix '.
'patches suggested by lint without prompting.', 'patches suggested by lint without prompting.'),
), ),
'everything' => array( 'everything' => array(
'help' => 'Lint all files in the project.', 'help' => pht('Lint all files in the project.'),
'conflicts' => array( 'conflicts' => array(
'cache' => '--everything lints all files', 'cache' => pht('%s lints all files', '--everything'),
'rev' => '--everything lints all files', 'rev' => pht('%s lints all files', '--everything'),
), ),
), ),
'severity' => array( 'severity' => array(
'param' => 'string', 'param' => 'string',
'help' => 'help' => pht(
"Set minimum message severity. One of: '". "Set minimum message severity. One of: %s. Defaults to '%s'.",
implode( sprintf(
"', '", "'%s'",
array_keys(ArcanistLintSeverity::getLintSeverities())). implode(
"'. Defaults to '".self::DEFAULT_SEVERITY."'.", "', '",
array_keys(ArcanistLintSeverity::getLintSeverities()))),
self::DEFAULT_SEVERITY),
), ),
'cache' => array( 'cache' => array(
'param' => 'bool', 'param' => 'bool',
'help' => 'help' => pht(
"0 to disable cache, 1 to enable. The default value is ". "%d to disable cache, %d to enable. The default value is determined ".
"determined by 'arc.lint.cache' in configuration, which defaults ". "by '%s' in configuration, which defaults to off. See notes in '%s'.",
"to off. See notes in 'arc.lint.cache'.", 0,
1,
'arc.lint.cache',
'arc.lint.cache'),
), ),
'*' => 'paths', '*' => 'paths',
); );
@ -191,8 +196,10 @@ EOTEXT
$everything = $this->getArgument('everything'); $everything = $this->getArgument('everything');
if ($everything && $paths) { if ($everything && $paths) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'You can not specify paths with --everything. The --everything '. pht(
'flag lints every file.'); 'You can not specify paths with %s. The %s flag lints every file.',
'--everything',
'--everything'));
} }
if ($use_cache === null) { if ($use_cache === null) {
$use_cache = (bool)$configuration_manager->getConfigFromAnySource( $use_cache = (bool)$configuration_manager->getConfigFromAnySource(
@ -201,7 +208,8 @@ EOTEXT
} }
if ($rev && $paths) { if ($rev && $paths) {
throw new ArcanistUsageException('Specify either --rev or paths.'); throw new ArcanistUsageException(
pht('Specify either %s or paths.', '--rev'));
} }
@ -252,7 +260,10 @@ EOTEXT
if ($cached) { if ($cached) {
$console->writeErr( $console->writeErr(
pht("Using lint cache, use '--cache 0' to disable it.")."\n"); "%s\n",
pht(
"Using lint cache, use '%s' to disable it.",
'--cache 0'));
} }
$engine->setCachedResults($cached); $engine->setCachedResults($cached);
@ -491,9 +502,9 @@ EOTEXT
$console->writeOut('%s', $stdout); $console->writeOut('%s', $stdout);
$console->writeErr('%s', $stderr); $console->writeErr('%s', $stderr);
$prompt = phutil_console_format( $prompt = pht(
'Apply this patch to __%s__?', 'Apply this patch to %s?',
$result->getPath()); phutil_console_format('__%s__', $result->getPath()));
if (!$console->confirm($prompt, $default_no = false)) { if (!$console->confirm($prompt, $default_no = false)) {
continue; continue;
} }
@ -511,11 +522,12 @@ EOTEXT
if ($this->shouldAmendWithoutPrompt || if ($this->shouldAmendWithoutPrompt ||
($this->shouldAmendAutofixesWithoutPrompt && $all_autofix)) { ($this->shouldAmendAutofixesWithoutPrompt && $all_autofix)) {
$console->writeOut( $console->writeOut(
"<bg:yellow>** LINT NOTICE **</bg> Automatically amending HEAD ". "<bg:yellow>** %s **</bg> %s\n",
"with lint patches.\n"); pht('LINT NOTICE'),
pht('Automatically amending HEAD with lint patches.'));
$amend = true; $amend = true;
} else { } else {
$amend = $console->confirm('Amend HEAD with lint patches?'); $amend = $console->confirm(pht('Amend HEAD with lint patches?'));
} }
if ($amend) { if ($amend) {
@ -527,8 +539,9 @@ EOTEXT
$repository_api->amendCommit(); $repository_api->amendCommit();
} else { } else {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'Sort out the lint changes that were applied to the working '. pht(
'copy and relint.'); 'Sort out the lint changes that were applied to the working '.
'copy and relint.'));
} }
} }

View file

@ -178,7 +178,7 @@ EOTEXT
if (!$this->getArgument('verbose')) { if (!$this->getArgument('verbose')) {
$console->writeOut( $console->writeOut(
"%s\n", "%s\n",
pht('(Run `arc linters --verbose` for more details.)')); pht('(Run `%s` for more details.)', 'arc linters --verbose'));
} }
} }
@ -191,8 +191,8 @@ EOTEXT
private function getStatusMap() { private function getStatusMap() {
$text_map = array( $text_map = array(
'configured' => pht('CONFIGURED'), 'configured' => pht('CONFIGURED'),
'available' => pht('AVAILABLE'), 'available' => pht('AVAILABLE'),
'error' => pht('ERROR'), 'error' => pht('ERROR'),
); );
$sizes = array(); $sizes = array();

View file

@ -55,7 +55,7 @@ EOTEXT
)); ));
if (!$revisions) { if (!$revisions) {
echo "You have no open Differential revisions.\n"; echo pht('You have no open Differential revisions.')."\n";
return 0; return 0;
} }
@ -93,9 +93,12 @@ EOTEXT
$table->addRow(array( $table->addRow(array(
'exists' => $spec['exists'] ? phutil_console_format('**%s**', '*') : '', 'exists' => $spec['exists'] ? phutil_console_format('**%s**', '*') : '',
'status' => phutil_console_format( 'status' => phutil_console_format(
"<fg:{$spec['color']}>%s</fg>", $spec['statusName']), "<fg:{$spec['color']}>%s</fg>",
$spec['statusName']),
'title' => phutil_console_format( 'title' => phutil_console_format(
'**D%d:** %s', $revision['id'], $revision['title']), '**D%d:** %s',
$revision['id'],
$revision['title']),
)); ));
} }

View file

@ -123,7 +123,7 @@ EOTEXT
$conduit = $this->getConduit(); $conduit = $this->getConduit();
if (!function_exists('posix_isatty') || posix_isatty(STDIN)) { if (!function_exists('posix_isatty') || posix_isatty(STDIN)) {
$this->writeStatusMessage("Reading paste from stdin...\n"); $this->writeStatusMessage(pht('Reading paste from stdin...')."\n");
} }
$info = $conduit->callMethodSynchronous( $info = $conduit->callMethodSynchronous(

View file

@ -42,37 +42,42 @@ EOTEXT
'revision' => array( 'revision' => array(
'param' => 'revision_id', 'param' => 'revision_id',
'paramtype' => 'complete', 'paramtype' => 'complete',
'help' => 'help' => pht(
"Apply changes from a Differential revision, using the most recent ". "Apply changes from a Differential revision, using the most recent ".
"diff that has been attached to it. You can run 'arc patch D12345' ". "diff that has been attached to it. You can run '%s' as a shorthand.",
"as a shorthand.", 'arc patch D12345'),
), ),
'diff' => array( 'diff' => array(
'param' => 'diff_id', 'param' => 'diff_id',
'help' => 'help' => pht(
'Apply changes from a Differential diff. Normally you want to use '. 'Apply changes from a Differential diff. Normally you want to use '.
'--revision to get the most recent changes, but you can '. '%s to get the most recent changes, but you can specifically apply '.
'specifically apply an out-of-date diff or a diff which was never '. 'an out-of-date diff or a diff which was never attached to a '.
'attached to a revision by using this flag.', 'revision by using this flag.',
'--revision'),
), ),
'arcbundle' => array( 'arcbundle' => array(
'param' => 'bundlefile', 'param' => 'bundlefile',
'paramtype' => 'file', 'paramtype' => 'file',
'help' => 'help' => pht(
"Apply changes from an arc bundle generated with 'arc export'.", "Apply changes from an arc bundle generated with '%s'.",
'arc export'),
), ),
'patch' => array( 'patch' => array(
'param' => 'patchfile', 'param' => 'patchfile',
'paramtype' => 'file', 'paramtype' => 'file',
'help' => 'Apply changes from a git patchfile or unified patchfile.', 'help' => pht(
'Apply changes from a git patchfile or unified patchfile.'),
), ),
'encoding' => array( 'encoding' => array(
'param' => 'encoding', 'param' => 'encoding',
'help' => 'Attempt to convert non UTF-8 patch into specified encoding.', 'help' => pht(
'Attempt to convert non UTF-8 patch into specified encoding.'),
), ),
'update' => array( 'update' => array(
'supports' => array('git', 'svn', 'hg'), 'supports' => array('git', 'svn', 'hg'),
'help' => 'Update the local working copy before applying the patch.', 'help' => pht(
'Update the local working copy before applying the patch.'),
'conflicts' => array( 'conflicts' => array(
'nobranch' => true, 'nobranch' => true,
'bookmark' => true, 'bookmark' => true,
@ -80,30 +85,30 @@ EOTEXT
), ),
'nocommit' => array( 'nocommit' => array(
'supports' => array('git', 'hg'), 'supports' => array('git', 'hg'),
'help' => 'help' => pht(
'Normally under git/hg, if the patch is successful, the changes '. 'Normally under git/hg, if the patch is successful, the changes '.
'are committed to the working copy. This flag prevents the commit.', 'are committed to the working copy. This flag prevents the commit.'),
), ),
'skip-dependencies' => array( 'skip-dependencies' => array(
'supports' => array('git', 'hg'), 'supports' => array('git', 'hg'),
'help' => 'help' => pht(
'Normally, if a patch has dependencies that are not present in the '. 'Normally, if a patch has dependencies that are not present in the '.
'working copy, arc tries to apply them as well. This flag prevents '. 'working copy, arc tries to apply them as well. This flag prevents '.
'such work.', 'such work.'),
), ),
'nobranch' => array( 'nobranch' => array(
'supports' => array('git', 'hg'), 'supports' => array('git', 'hg'),
'help' => 'help' => pht(
'Normally, a new branch (git) or bookmark (hg) is created and then '. 'Normally, a new branch (git) or bookmark (hg) is created and then '.
'the patch is applied and committed in the new branch/bookmark. '. 'the patch is applied and committed in the new branch/bookmark. '.
'This flag cherry-picks the resultant commit onto the original '. 'This flag cherry-picks the resultant commit onto the original '.
'branch and deletes the temporary branch.', 'branch and deletes the temporary branch.'),
'conflicts' => array( 'conflicts' => array(
'update' => true, 'update' => true,
), ),
), ),
'force' => array( 'force' => array(
'help' => 'Do not run any sanity checks.', 'help' => pht('Do not run any sanity checks.'),
), ),
'*' => 'name', '*' => 'name',
); );
@ -133,7 +138,8 @@ EOTEXT
if ($this->getArgument('name')) { if ($this->getArgument('name')) {
$namev = $this->getArgument('name'); $namev = $this->getArgument('name');
if (count($namev) > 1) { if (count($namev) > 1) {
throw new ArcanistUsageException('Specify at most one revision name.'); throw new ArcanistUsageException(
pht('Specify at most one revision name.'));
} }
$source = self::SOURCE_REVISION; $source = self::SOURCE_REVISION;
$requested++; $requested++;
@ -143,15 +149,26 @@ EOTEXT
if ($requested === 0) { if ($requested === 0) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Specify one of 'D12345', '--revision <revision_id>' (to select the ". pht(
"current changes attached to a Differential revision), ". "Specify one of '%s', '%s' (to select the current changes attached ".
"'--diff <diff_id>' (to select a specific, out-of-date diff or a ". "to a Differential revision), '%s' (to select a specific, ".
"diff which is not attached to a revision), '--arcbundle <file>' ". "out-of-date diff or a diff which is not attached to a revision), ".
"or '--patch <file>' to choose a patch source."); "'%s' or '%s' to choose a patch source.",
'D12345',
'--revision <revision_id>',
'--diff <diff_id>',
'--arcbundle <file>',
'--patch <file>'));
} else if ($requested > 1) { } else if ($requested > 1) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Options 'D12345', '--revision', '--diff', '--arcbundle' and ". pht(
"'--patch' are not compatible. Choose exactly one patch source."); "Options '%s', '%s', '%s', '%s' and '%s' are not compatible. ".
"Choose exactly one patch source.",
'D12345',
'--revision',
'--diff',
'--arcbundle',
'--patch'));
} }
$this->source = $source; $this->source = $source;
@ -218,7 +235,10 @@ EOTEXT
// no error means git rev-parse found a branch // no error means git rev-parse found a branch
if (!$err) { if (!$err) {
echo phutil_console_format( echo phutil_console_format(
"Branch name {$proposed_name} already exists; trying a new name.\n"); "%s\n",
pht(
'Branch name %s already exists; trying a new name.',
$proposed_name));
continue; continue;
} else { } else {
$branch_name = $proposed_name; $branch_name = $proposed_name;
@ -228,9 +248,9 @@ EOTEXT
if (!$branch_name) { if (!$branch_name) {
throw new Exception( throw new Exception(
'Arc was unable to automagically make a name for this patch. '. pht(
'Please clean up your working copy and try again.' 'Arc was unable to automagically make a name for this patch. '.
); 'Please clean up your working copy and try again.'));
} }
return $branch_name; return $branch_name;
@ -256,8 +276,10 @@ EOTEXT
// no error means hg log found a bookmark // no error means hg log found a bookmark
if (!$err) { if (!$err) {
echo phutil_console_format( echo phutil_console_format(
"Bookmark name %s already exists; trying a new name.\n", "%s\n",
$proposed_name); pht(
'Bookmark name %s already exists; trying a new name.',
$proposed_name));
continue; continue;
} else { } else {
$bookmark_name = $proposed_name; $bookmark_name = $proposed_name;
@ -267,9 +289,9 @@ EOTEXT
if (!$bookmark_name) { if (!$bookmark_name) {
throw new Exception( throw new Exception(
'Arc was unable to automagically make a name for this patch. '. pht(
'Please clean up your working copy and try again.' 'Arc was unable to automagically make a name for this patch. '.
); 'Please clean up your working copy and try again.'));
} }
return $bookmark_name; return $bookmark_name;
@ -289,14 +311,14 @@ EOTEXT
$branch_name, $branch_name,
$base_revision); $base_revision);
} else { } else {
$repository_api->execxLocal( $repository_api->execxLocal('checkout -b %s', $branch_name);
'checkout -b %s',
$branch_name);
} }
echo phutil_console_format( echo phutil_console_format(
"Created and checked out branch %s.\n", "%s\n",
$branch_name); pht(
'Created and checked out branch %s.',
$branch_name));
} else if ($repository_api instanceof ArcanistMercurialAPI) { } else if ($repository_api instanceof ArcanistMercurialAPI) {
$branch_name = $this->getBookmarkName($bundle); $branch_name = $this->getBookmarkName($bundle);
$base_revision = $bundle->getBaseRevision(); $base_revision = $bundle->getBaseRevision();
@ -305,17 +327,17 @@ EOTEXT
$base_revision = $repository_api->getCanonicalRevisionName( $base_revision = $repository_api->getCanonicalRevisionName(
$base_revision); $base_revision);
echo "Updating to the revision's base commit\n"; echo pht("Updating to the revision's base commit")."\n";
$repository_api->execPassthru( $repository_api->execPassthru('update %s', $base_revision);
'update %s',
$base_revision);
} }
$repository_api->execxLocal('bookmark %s', $branch_name); $repository_api->execxLocal('bookmark %s', $branch_name);
echo phutil_console_format( echo phutil_console_format(
"Created and checked out bookmark %s.\n", "%s\n",
$branch_name); pht(
'Created and checked out bookmark %s.',
$branch_name));
} }
return $branch_name; return $branch_name;
@ -330,9 +352,9 @@ EOTEXT
} }
private function updateWorkingCopy() { private function updateWorkingCopy() {
echo "Updating working copy...\n"; echo pht('Updating working copy...')."\n";
$this->getRepositoryAPI()->updateWorkingCopy(); $this->getRepositoryAPI()->updateWorkingCopy();
echo "Done.\n"; echo pht('Done.')."\n";
} }
public function run() { public function run() {
@ -345,7 +367,7 @@ EOTEXT
$patch = @file_get_contents('php://stdin'); $patch = @file_get_contents('php://stdin');
if (!strlen($patch)) { if (!strlen($patch)) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'Failed to read patch from stdin!'); pht('Failed to read patch from stdin!'));
} }
} else { } else {
$patch = Filesystem::readFile($param); $patch = Filesystem::readFile($param);
@ -469,8 +491,10 @@ EOTEXT
$fpath = $repository_api->getPath($path); $fpath = $repository_api->getPath($path);
if (!@file_exists($fpath)) { if (!@file_exists($fpath)) {
$ok = phutil_console_confirm( $ok = phutil_console_confirm(
"Patch deletes file '{$path}', but the file does not exist in ". pht(
"the working copy. Continue anyway?"); "Patch deletes file '%s', but the file does not exist in ".
"the working copy. Continue anyway?",
$path));
if (!$ok) { if (!$ok) {
throw new ArcanistUserAbortException(); throw new ArcanistUserAbortException();
} }
@ -486,13 +510,17 @@ EOTEXT
if (!@file_exists($fpath)) { if (!@file_exists($fpath)) {
$cpath = $change->getCurrentPath(); $cpath = $change->getCurrentPath();
if ($type == ArcanistDiffChangeType::TYPE_COPY_HERE) { if ($type == ArcanistDiffChangeType::TYPE_COPY_HERE) {
$verbs = 'copies'; $verbs = pht('copies');
} else { } else {
$verbs = 'moves'; $verbs = pht('moves');
} }
$ok = phutil_console_confirm( $ok = phutil_console_confirm(
"Patch {$verbs} '{$path}' to '{$cpath}', but source path ". pht(
"does not exist in the working copy. Continue anyway?"); "Patch %s '%s' to '%s', but source path does not exist ".
"in the working copy. Continue anyway?",
$verbs,
$path,
$cpath));
if (!$ok) { if (!$ok) {
throw new ArcanistUserAbortException(); throw new ArcanistUserAbortException();
} }
@ -634,18 +662,26 @@ EOTEXT
if ($patch_err == 0) { if ($patch_err == 0) {
echo phutil_console_format( echo phutil_console_format(
"<bg:green>** OKAY **</bg> Successfully applied patch ". "<bg:green>** %s **</bg> %s\n",
"to the working copy.\n"); pht('OKAY'),
pht('Successfully applied patch to the working copy.'));
} else { } else {
echo phutil_console_format( echo phutil_console_format(
"\n\n<bg:yellow>** WARNING **</bg> Some hunks could not be applied ". "\n\n<bg:yellow>** %s **</bg> %s\n",
"cleanly by the unix 'patch' utility. Your working copy may be ". pht('WARNING'),
"different from the revision's base, or you may be in the wrong ". pht(
"subdirectory. You can export the raw patch file using ". "Some hunks could not be applied cleanly by the unix '%s' ".
"'arc export --unified', and then try to apply it by fiddling with ". "utility. Your working copy may be different from the revision's ".
"options to 'patch' (particularly, -p), or manually. The output ". "base, or you may be in the wrong subdirectory. You can export ".
"above, from 'patch', may be helpful in figuring out what went ". "the raw patch file using '%s', and then try to apply it by ".
"wrong.\n"); "fiddling with options to '%s' (particularly, %s), or manually. ".
"The output above, from '%s', may be helpful in ".
"figuring out what went wrong.",
'patch',
'arc export --unified',
'patch',
'-p',
'patch'));
} }
return $patch_err; return $patch_err;
@ -662,19 +698,19 @@ EOTEXT
if ($err) { if ($err) {
echo phutil_console_format( echo phutil_console_format(
"\n<bg:red>** Patch Failed! **</bg>\n"); "\n<bg:red>** %s **</bg>\n",
pht('Patch Failed!'));
// NOTE: Git patches may fail if they change the case of a filename // NOTE: Git patches may fail if they change the case of a filename
// (for instance, from 'example.c' to 'Example.c'). As of now, Git // (for instance, from 'example.c' to 'Example.c'). As of now, Git
// can not apply these patches on case-insensitive filesystems and // can not apply these patches on case-insensitive filesystems and
// there is no way to build a patch which works. // there is no way to build a patch which works.
throw new ArcanistUsageException('Unable to apply patch!'); throw new ArcanistUsageException(pht('Unable to apply patch!'));
} }
// in case there were any submodule changes involved // in case there were any submodule changes involved
$repository_api->execpassthru( $repository_api->execpassthru('submodule update --init --recursive');
'submodule update --init --recursive');
if ($this->shouldCommit()) { if ($this->shouldCommit()) {
if ($bundle->getFullAuthor()) { if ($bundle->getFullAuthor()) {
@ -689,9 +725,9 @@ EOTEXT
$author_cmd); $author_cmd);
$future->write($commit_message); $future->write($commit_message);
$future->resolvex(); $future->resolvex();
$verb = 'committed'; $verb = pht('committed');
} else { } else {
$verb = 'applied'; $verb = pht('applied');
} }
if ($this->canBranch() && if ($this->canBranch() &&
@ -707,33 +743,39 @@ EOTEXT
$repository_api->execxLocal('branch -D %s', $new_branch); $repository_api->execxLocal('branch -D %s', $new_branch);
if ($ex) { if ($ex) {
echo phutil_console_format( echo phutil_console_format(
"\n<bg:red>** Cherry Pick Failed!**</bg>\n"); "\n<bg:red>** %s**</bg>\n",
pht('Cherry Pick Failed!'));
throw $ex; throw $ex;
} }
} }
echo phutil_console_format( echo phutil_console_format(
"<bg:green>** OKAY **</bg> Successfully {$verb} patch.\n"); "<bg:green>** %s **</bg> %s\n",
pht('OKAY'),
pht('Successfully %s patch.', $verb));
} else if ($repository_api instanceof ArcanistMercurialAPI) { } else if ($repository_api instanceof ArcanistMercurialAPI) {
$future = $repository_api->execFutureLocal('import --no-commit -');
$future = $repository_api->execFutureLocal(
'import --no-commit -');
$future->write($bundle->toGitPatch()); $future->write($bundle->toGitPatch());
try { try {
$future->resolvex(); $future->resolvex();
} catch (CommandException $ex) { } catch (CommandException $ex) {
echo phutil_console_format( echo phutil_console_format(
"\n<bg:red>** Patch Failed! **</bg>\n"); "\n<bg:red>** %s **</bg>\n",
pht('Patch Failed!'));
$stderr = $ex->getStdErr(); $stderr = $ex->getStdErr();
if (preg_match('/case-folding collision/', $stderr)) { if (preg_match('/case-folding collision/', $stderr)) {
echo phutil_console_wrap( echo phutil_console_wrap(
phutil_console_format( phutil_console_format(
"\n<bg:yellow>** WARNING **</bg> This patch may have failed ". "\n<bg:yellow>** %s **</bg> %s\n",
"because it attempts to change the case of a filename (for ". pht('WARNING'),
"instance, from 'example.c' to 'Example.c'). Mercurial cannot ". pht(
"apply patches like this on case-insensitive filesystems. You ". "This patch may have failed because it attempts to change ".
"must apply this patch manually.\n")); "the case of a filename (for instance, from '%s' to '%s'). ".
"Mercurial cannot apply patches like this on case-insensitive ".
"filesystems. You must apply this patch manually.",
'example.c',
'Example.c')));
} }
throw $ex; throw $ex;
} }
@ -770,21 +812,24 @@ EOTEXT
$repository_api->execxLocal('bookmark --delete %s', $new_branch); $repository_api->execxLocal('bookmark --delete %s', $new_branch);
if ($err) { if ($err) {
$repository_api->execManualLocal('rebase --abort'); $repository_api->execManualLocal('rebase --abort');
throw new ArcanistUsageException(phutil_console_format( throw new ArcanistUsageException(
"\n<bg:red>** Rebase onto $original_branch failed!**</bg>\n")); phutil_console_format(
"\n<bg:red>** %s**</bg>\n",
pht('Rebase onto %s failed!', $original_branch)));
} }
} }
$verb = 'committed'; $verb = pht('committed');
} else { } else {
$verb = 'applied'; $verb = pht('applied');
} }
echo phutil_console_format( echo phutil_console_format(
"<bg:green>** OKAY **</bg> Successfully {$verb} patch.\n"); "<bg:green>** %s **</bg> %s\n",
pht('OKAY'),
pht('Successfully %s patch.', $verb));
} else { } else {
throw new Exception('Unknown version control system.'); throw new Exception(pht('Unknown version control system.'));
} }
return 0; return 0;
@ -806,20 +851,23 @@ EOTEXT
array( array(
'revision_id' => $revision_id, 'revision_id' => $revision_id,
)); ));
$prompt_message = " Note arcanist failed to load the commit message ". $prompt_message = pht(
"from differential for revision D{$revision_id}."; ' Note arcanist failed to load the commit message '.
'from differential for revision %s.',
"D{$revision_id}");
} }
// no revision id or failed to fetch commit message so get it from the // no revision id or failed to fetch commit message so get it from the
// user on the command line // user on the command line
if (!$commit_message) { if (!$commit_message) {
$template = $template = sprintf(
"\n\n". "\n\n# %s%s\n",
"# Enter a commit message for this patch. If you just want to apply ". pht(
"the patch to the working copy without committing, re-run arc patch ". 'Enter a commit message for this patch. If you just want to apply '.
"with the --nocommit flag.". 'the patch to the working copy without committing, re-run arc patch '.
$prompt_message. 'with the %s flag.',
"\n"; '--nocommit'),
$prompt_message);
$commit_message = $this->newInteractiveEditor($template) $commit_message = $this->newInteractiveEditor($template)
->setName('arcanist-patch-commit-message') ->setName('arcanist-patch-commit-message')
@ -848,8 +896,9 @@ EOTEXT
$cycle_phids = $graph->detectCycles($start_phid); $cycle_phids = $graph->detectCycles($start_phid);
if ($cycle_phids) { if ($cycle_phids) {
$phids = array_keys($graph->getNodes()); $phids = array_keys($graph->getNodes());
$issue = 'The dependencies for this patch have a cycle. Applying them '. $issue = pht(
'is not guaranteed to work. Continue anyway?'; 'The dependencies for this patch have a cycle. Applying them '.
'is not guaranteed to work. Continue anyway?');
$okay = phutil_console_confirm($issue, true); $okay = phutil_console_confirm($issue, true);
} else { } else {
$phids = $graph->getTopographicallySortedNodes(); $phids = $graph->getTopographicallySortedNodes();
@ -915,17 +964,20 @@ EOTEXT
// they don't come with a project id so just do nothing // they don't come with a project id so just do nothing
} else if ($bundle_project_id != $working_copy_project_id) { } else if ($bundle_project_id != $working_copy_project_id) {
if ($working_copy_project_id) { if ($working_copy_project_id) {
$issue = $issue = pht(
"This patch is for the '{$bundle_project_id}' project, but the ". "This patch is for the '%s' project, but the working copy ".
"working copy belongs to the '{$working_copy_project_id}' project."; "belongs to the '%s' project.",
$bundle_project_id,
$working_copy_project_id);
} else { } else {
$issue = $issue = pht(
"This patch is for the '{$bundle_project_id}' project, but the ". "This patch is for the '%s' project, but the working copy does ".
"working copy does not have an '.arcconfig' file to identify which ". "not have an '%s' file to identify which project it belongs to.",
"project it belongs to."; $bundle_project_id,
'.arcconfig');
} }
$ok = phutil_console_confirm( $ok = phutil_console_confirm(
"{$issue} Still try to apply the patch?", pht('%s Still try to apply the patch?', $issue),
$default_no = false); $default_no = false);
if (!$ok) { if (!$ok) {
throw new ArcanistUserAbortException(); throw new ArcanistUserAbortException();
@ -985,9 +1037,12 @@ EOTEXT
$source_base_rev); $source_base_rev);
$ok = phutil_console_confirm( $ok = phutil_console_confirm(
"This diff is against commit {$bundle_base_rev_str}, but the ". pht(
"commit is nowhere in the working copy. Try to apply it against ". 'This diff is against commit %s, but the commit is nowhere '.
"the current working copy state? ({$source_base_rev_str})", 'in the working copy. Try to apply it against the current '.
'working copy state? (%s)',
$bundle_base_rev_str,
$source_base_rev_str),
$default_no = false); $default_no = false);
if (!$ok) { if (!$ok) {
throw new ArcanistUserAbortException(); throw new ArcanistUserAbortException();

View file

@ -34,7 +34,9 @@ EOTEXT
} }
public function run() { public function run() {
echo pht('Please use `%s` instead.', 'arc backout')."\n"; echo pht(
'Please use `%s` instead.',
'arc backout')."\n";
return 1; return 1;
} }

View file

@ -36,7 +36,7 @@ EOTEXT
public function getArguments() { public function getArguments() {
return array( return array(
'local' => array( 'local' => array(
'help' => 'Set a local config value instead of a user one', 'help' => pht('Set a local config value instead of a user one.'),
), ),
'*' => 'argv', '*' => 'argv',
); );
@ -85,9 +85,16 @@ EOTEXT
$old = $settings->formatConfigValueForDisplay($key, $old); $old = $settings->formatConfigValueForDisplay($key, $old);
if ($old === null) { if ($old === null) {
echo "Deleted key '{$key}' from {$which} config.\n"; echo pht(
"Deleted key '%s' from %s config.\n",
$key,
$which);
} else { } else {
echo "Deleted key '{$key}' from {$which} config (was {$old}).\n"; echo pht(
"Deleted key '%s' from %s config (was %s).\n",
$key,
$which,
$old);
} }
} else { } else {
$val = $settings->willWriteValue($key, $val); $val = $settings->willWriteValue($key, $val);
@ -103,9 +110,18 @@ EOTEXT
$old = $settings->formatConfigValueForDisplay($key, $old); $old = $settings->formatConfigValueForDisplay($key, $old);
if ($old === null) { if ($old === null) {
echo "Set key '{$key}' = {$val} in {$which} config.\n"; echo pht(
"Set key '%s' = %s in %s config.\n",
$key,
$val,
$which);
} else { } else {
echo "Set key '{$key}' = {$val} in {$which} config (was {$old}).\n"; echo pht(
"Set key '%s' = %s in %s config (was %s).\n",
$key,
$val,
$which,
$old);
} }
} }

View file

@ -50,7 +50,9 @@ EOTEXT
if ($pos > $argc) { if ($pos > $argc) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
'Specified position is greater than the number of arguments provided.'); pht(
'Specified position is greater than the number of '.
'arguments provided.'));
} }
// Determine which revision control system the working copy uses, so we // Determine which revision control system the working copy uses, so we

Some files were not shown because too many files have changed in this diff Show more