1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-02-21 11:09:02 +01:00
phorge-arcanist/src/configuration/ArcanistSettings.php
James Rhodes 2900ab6abd Added automatic stash / unstash support for Git in arc diff.
Summary:
- Added arc.autostash option to have this behaviour off by
default (but configurable on a per-project basis).
- Automatic stashing of changes now informs the user of how
to restore their working directory if Arcanist unexpectedly
terminates.
- Fixed an issue with finalizeWorkingCopy when the workflow
didn't require a clean working copy.

Test Plan:
Test `arc diff` when there are changes in the working
directory; by default it should tell you to stash or commit.
Turn on the arc.autostash option and try again; it should
automatically stash with a message on how to recover, and
it should restore the working directory automatically under
almost any circumstances (other than an unrecoverable error).

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Differential Revision: https://secure.phabricator.com/D5385
2013-03-21 16:00:05 -07:00

253 lines
7.4 KiB
PHP

<?php
/**
* @group config
*/
final class ArcanistSettings {
private function getOptions() {
return array(
'default' => array(
'type' => 'string',
'help' =>
'The URI of a Phabricator install to connect to by default, if '.
'arc is run in a project without a Phabricator URI or run outside '.
'of a project.',
'example' => '"http://phabricator.example.com/"',
),
'base' => array(
'type' => 'string',
'help' =>
'Base commit ruleset to invoke when determining the start of a '.
'commit range. See "Arcanist User Guide: Commit Ranges" for '.
'details.',
'example' => '"arc:amended, arc:prompt"',
),
'load' => array(
'type' => 'list',
'legacy' => 'phutil_libraries',
'help' =>
'A list of paths to phutil libraries that should be loaded at '.
'startup. This can be used to make classes available, like lint or '.
'unit test engines.',
'example' => '["/var/arc/customlib/src"]',
),
'lint.engine' => array(
'type' => 'string',
'legacy' => 'lint_engine',
'help' =>
'The name of a default lint engine to use, if no lint engine is '.
'specified by the current project.',
'example' => '"ExampleLintEngine"',
),
'unit.engine' => array(
'type' => 'string',
'legacy' => 'unit_engine',
'help' =>
'The name of a default unit test engine to use, if no unit test '.
'engine is specified by the current project.',
'example' => '"ExampleUnitTestEngine"',
),
'arc.land.onto.default' => array(
'type' => 'string',
'help' =>
'The name of the default branch to land changes onto when '.
'`arc land` is run.',
'example' => '"develop"',
),
'history.immutable' => array(
'type' => 'bool',
'legacy' => 'immutable_history',
'help' =>
'If true, arc will never change repository history (e.g., through '.
'amending or rebasing). Defaults to true in Mercurial and false in '.
'Git. This setting has no effect in Subversion.',
'example' => 'false',
),
'editor' => array(
'type' => 'string',
'help' =>
"Command to use to invoke an interactive editor, like 'nano' or ".
"'vim'. This setting overrides the EDITOR environmental variable.",
'example' => '"nano"',
),
'browser' => array(
'type' => 'string',
'help' =>
"Command to use to invoke a web browser.",
'example' => '"gnome-www-browser"',
),
'events.listeners' => array(
'type' => 'list',
'help' => 'List of event listener classes to install at startup.',
'example' => '["ExampleEventListener"]',
),
'http.basicauth.user' => array(
'type' => 'string',
'help' =>
"Username to use for basic auth over http transports",
'example' => '"bob"',
),
'http.basicauth.pass' => array(
'type' => 'string',
'help' =>
"Password to use for basic auth over http transports",
'example' => '"bobhasasecret"',
),
'arc.autostash' => array(
'type' => 'bool',
'help' =>
'Whether arc should permit the automatic stashing of changes in '.
'the working directory when requiring a clean working copy. '.
'This option should only be used when users understand how '.
'to restore their working directory from the local stash if '.
'an Arcanist operation causes an unrecoverable error.',
'example' => 'false',
),
);
}
private function getOption($key) {
return idx($this->getOptions(), $key, array());
}
public function getAllKeys() {
return array_keys($this->getOptions());
}
public function getHelp($key) {
return idx($this->getOption($key), 'help');
}
public function getExample($key) {
return idx($this->getOption($key), 'example');
}
public function getType($key) {
return idx($this->getOption($key), 'type', 'wild');
}
public function getLegacyName($key) {
return idx($this->getOption($key), 'legacy');
}
public function willWriteValue($key, $value) {
$type = $this->getType($key);
switch ($type) {
case 'bool':
if (strtolower($value) === 'false' ||
strtolower($value) === 'no' ||
strtolower($value) === 'off' ||
$value === '' ||
$value === '0' ||
$value === 0 ||
$value === false) {
$value = false;
} else if (strtolower($value) === 'true' ||
strtolower($value) === 'yes' ||
strtolower($value) === 'on' ||
$value === '1' ||
$value === 1 ||
$value === true) {
$value = true;
} else {
throw new ArcanistUsageException(
"Type of setting '{$key}' must be boolean, like 'true' or ".
"'false'.");
}
break;
case 'list':
if (is_array($value)) {
break;
}
if (is_string($value)) {
$list = json_decode($value, true);
if (is_array($list)) {
$value = $list;
break;
}
}
$list_example = '["apple", "banana", "cherry"]';
throw new ArcanistUsageException(
"Type of setting '{$key}' must be list. You can specify a list ".
"in JSON, like: {$list_example}");
case 'string':
if (!is_scalar($value)) {
throw new ArcanistUsageException(
"Type of setting '{$key}' must be string.");
}
$value = (string)$value;
break;
case 'wild':
break;
}
return $value;
}
public function willReadValue($key, $value) {
$type = $this->getType($key);
switch ($type) {
case 'string':
if (!is_string($value)) {
throw new ArcanistUsageException(
"Type of setting '{$key}' must be string.");
}
break;
case 'bool':
if ($value !== true && $value !== false) {
throw new ArcanistUsageException(
"Type of setting '{$key}' must be boolean.");
}
break;
case 'list':
if (!is_array($value)) {
throw new ArcanistUsageException(
"Type of setting '{$key}' must be list.");
}
break;
case 'wild':
break;
}
return $value;
}
public function formatConfigValueForDisplay($key, $value) {
if ($value === false) {
return 'false';
}
if ($value === true) {
return 'true';
}
if ($value === null) {
return 'null';
}
if (is_string($value)) {
return '"'.$value.'"';
}
if (is_array($value)) {
// TODO: Both json_encode() and PhutilJSON do a bad job with one-liners.
// PhutilJSON splits them across a bunch of lines, while json_encode()
// escapes all kinds of stuff like "/". It would be nice if PhutilJSON
// had a mode for pretty one-liners.
$value = json_encode($value);
// json_encode() unnecessarily escapes "/" to prevent "</script>" stuff,
// optimistically unescape it for display to improve readability.
$value = preg_replace('@(?<!\\\\)\\\\/@', '/', $value);
return $value;
}
return $value;
}
}