Enrich arc configuration and add stronger typing
Summary:
See <https://github.com/facebook/arcanist/issues/45>
Currently, when the user types `arc set-config x false`, we set it as the string "false", which is usually not desirable. We have some steps toward typed config already, but expand on what we have and move as much stuff as possible into it, including all the config settings that aren't currently documented (there are still some lint-specific and project-specific settings not present here, but this is most of it).
Also make the `phutil_libraries` key a legacy name for `load`, and `immutable_history` a legacy name for `history.immutable`. Generally the goal here is to make config simpler and bring it more in-line with Git/Mercurial, which use dotted hierarchies.
I'll add some documentation here but I think most of the changes should be fairly straightforward.
Test Plan:
- `arc set-config history.immutable on` (And similar -- sets to boolean true.)
- `arc set-config history.immutable off` (And similar -- sets to boolean false.)
- `arc set-config history.immutable derp` (And similar -- raises exception.)
- `arc set-config history.immutable ''` (And similar -- removes setting value.)
- `arc set-config --show`
- `arc get-config`
- `arc get-config base`
Reviewers: dschleimer, bos, btrahan, vrana
Reviewed By: dschleimer
CC: aran
Maniphest Tasks: T1546
Differential Revision: https://secure.phabricator.com/D3045
2012-07-25 18:37:09 -07:00
|
|
|
<?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"',
|
|
|
|
),
|
2012-12-09 14:09:35 -08:00
|
|
|
'browser' => array(
|
|
|
|
'type' => 'string',
|
|
|
|
'help' =>
|
|
|
|
"Command to use to invoke a web browser.",
|
|
|
|
'example' => '"gnome-www-browser"',
|
|
|
|
),
|
2012-09-05 11:45:54 -07:00
|
|
|
'events.listeners' => array(
|
|
|
|
'type' => 'list',
|
|
|
|
'help' => 'List of event listener classes to install at startup.',
|
|
|
|
'example' => '["ExampleEventListener"]',
|
|
|
|
),
|
2012-12-17 17:58:53 -08:00
|
|
|
'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"',
|
|
|
|
),
|
2013-03-21 15:51:39 -07:00
|
|
|
'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',
|
|
|
|
),
|
Enrich arc configuration and add stronger typing
Summary:
See <https://github.com/facebook/arcanist/issues/45>
Currently, when the user types `arc set-config x false`, we set it as the string "false", which is usually not desirable. We have some steps toward typed config already, but expand on what we have and move as much stuff as possible into it, including all the config settings that aren't currently documented (there are still some lint-specific and project-specific settings not present here, but this is most of it).
Also make the `phutil_libraries` key a legacy name for `load`, and `immutable_history` a legacy name for `history.immutable`. Generally the goal here is to make config simpler and bring it more in-line with Git/Mercurial, which use dotted hierarchies.
I'll add some documentation here but I think most of the changes should be fairly straightforward.
Test Plan:
- `arc set-config history.immutable on` (And similar -- sets to boolean true.)
- `arc set-config history.immutable off` (And similar -- sets to boolean false.)
- `arc set-config history.immutable derp` (And similar -- raises exception.)
- `arc set-config history.immutable ''` (And similar -- removes setting value.)
- `arc set-config --show`
- `arc get-config`
- `arc get-config base`
Reviewers: dschleimer, bos, btrahan, vrana
Reviewed By: dschleimer
CC: aran
Maniphest Tasks: T1546
Differential Revision: https://secure.phabricator.com/D3045
2012-07-25 18:37:09 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|