1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-02-19 18:28:38 +01:00
phorge-arcanist/src/configuration/ArcanistSettings.php

286 lines
8.8 KiB
PHP
Raw Normal View History

<?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.feature.start.default' => array(
'type' => 'string',
'help' =>
'The name of the default branch to create the new feature branch '.
'off of.',
'example' => '"develop"',
),
'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"',
),
'arc.land.update.default' => array(
'type' => 'string',
'help' =>
'The default strategy to use when arc land updates the feature '.
'branch. Supports \'rebase\' and \'merge\' strategies.',
'example' => '"rebase"',
),
Disable lint cache by default Summary: Fixes T2266. Motivation: - The lint cache does not always invalidate correctly. Because of the nature of the cache, this is a hard problem (right after "naming things"). - We already have a fair amount of complexity in trying to invalidate it, and are still discovering new places where it doesn't work (e.g., Windows with "/" vs "\" paths). - One invalidation failure is when linter code changes, which seems unresolvable in the general case (e.g., changes to external linters). - It's not obvious what's happening when the lint cache causes some kind of issue. - Particularly while developing or debugging linters, your changes often won't be reflected in the lint output. Some of this is theoretically tractable but the external linter case probably isn't. - When someone reports a problem with the lint cache in IRC or elsewhere, there is essentially never a way for me to fix it. The lint cache can't be debugged effectively without access to a working copy where the problem reproduces. - The cache provides limited benefit outside of Facebook's install. To remedy these issues: - Introduce configuration which controls cache usage. - Default it off. - Print a message when the cache is in use. (I'd tentatively support removing the cache entirely, but I don't know how @vrana and Facebook feel about that.) Test Plan: Ran `arc set-config --show`, `arc lint --cache 0`, `arc lint --cache 1`. Reviewers: vrana, btrahan Reviewed By: vrana CC: aran, mbishopim3, nh, edward, wez Maniphest Tasks: T2266 Differential Revision: https://secure.phabricator.com/D5766
2013-04-23 11:26:28 -07:00
'arc.lint.cache' => array(
'type' => 'bool',
'help' =>
"Enable the lint cache by default. When enabled, 'arc lint' ".
"attempts to use cached results if possible. Currently, the cache ".
"is not always invalidated correctly and may cause 'arc lint' to ".
"report incorrect results, particularly while developing linters. ".
"This is probably worth enabling only if your linters are very slow.",
'example' => 'false',
),
'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"',
),
'https.cabundle' => array(
'type' => 'string',
'help' =>
"Path to a custom CA bundle file to be used for arcanist's cURL ".
"calls. This is used primarily when your conduit endpoint is ".
"behind https signed by your organization's internal CA.",
'example' => 'support/yourca.pem'
),
'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;
}
}