mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-21 22:32:41 +01:00
Extract configuration read/write methods out of BaseWorlkflow
Summary: Create a new class for them, pass instance around as need. This looks like it's mostly working, but I'd like to replace the various `new ArcanistConfigurationManager()` calls with something more suitable. And maybe get a better name for ArcanistConfigurationManager ("Configuration" is already taken). Test Plan: arc unit --everything, and then some. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley CC: Korvin, epriestley, aran, chad Differential Revision: https://secure.phabricator.com/D7271
This commit is contained in:
parent
b2021586d4
commit
a2285b2b5a
25 changed files with 517 additions and 323 deletions
|
@ -74,14 +74,17 @@ try {
|
|||
array_unshift($args, 'help');
|
||||
}
|
||||
|
||||
$global_config = ArcanistBaseWorkflow::readGlobalArcConfig();
|
||||
$system_config = ArcanistBaseWorkflow::readSystemArcConfig();
|
||||
$configuration_manager = new ArcanistConfigurationManager();
|
||||
|
||||
$global_config = $configuration_manager->readUserArcConfig();
|
||||
$system_config = $configuration_manager->readSystemArcConfig();
|
||||
if ($skip_arcconfig) {
|
||||
$working_copy = ArcanistWorkingCopyIdentity::newDummyWorkingCopy();
|
||||
} else {
|
||||
$working_copy =
|
||||
ArcanistWorkingCopyIdentity::newFromPath($working_directory);
|
||||
}
|
||||
$configuration_manager->setWorkingCopyIdentity($working_copy);
|
||||
|
||||
reenter_if_this_is_arcanist_or_libphutil(
|
||||
$console,
|
||||
|
@ -133,7 +136,7 @@ try {
|
|||
$working_copy);
|
||||
}
|
||||
|
||||
$user_config = ArcanistBaseWorkflow::readUserConfigurationFile();
|
||||
$user_config = $configuration_manager->readUserConfigurationFile();
|
||||
|
||||
$config_class = $working_copy->getConfig('arcanist_configuration');
|
||||
if ($config_class) {
|
||||
|
@ -144,7 +147,12 @@ try {
|
|||
|
||||
$command = strtolower($args[0]);
|
||||
$args = array_slice($args, 1);
|
||||
$workflow = $config->selectWorkflow($command, $args, $working_copy, $console);
|
||||
$workflow = $config->selectWorkflow(
|
||||
$command,
|
||||
$args,
|
||||
$configuration_manager,
|
||||
$console);
|
||||
$workflow->setConfigurationManager($configuration_manager);
|
||||
$workflow->setArcanistConfiguration($config);
|
||||
$workflow->setCommand($command);
|
||||
$workflow->setWorkingDirectory($working_directory);
|
||||
|
@ -182,14 +190,16 @@ try {
|
|||
"This command must be run in a Git, Mercurial or Subversion working ".
|
||||
"copy.");
|
||||
}
|
||||
$workflow->setWorkingCopy($working_copy);
|
||||
$configuration_manager->setWorkingCopyIdentity($working_copy);
|
||||
}
|
||||
|
||||
if ($force_conduit) {
|
||||
$conduit_uri = $force_conduit;
|
||||
} else {
|
||||
if ($working_copy->getConduitURI()) {
|
||||
$conduit_uri = $working_copy->getConduitURI();
|
||||
$project_conduit_uri =
|
||||
$configuration_manager->getProjectConfig('conduit_uri');
|
||||
if ($project_conduit_uri) {
|
||||
$conduit_uri = $project_conduit_uri;
|
||||
} else {
|
||||
$conduit_uri = idx($global_config, 'default');
|
||||
}
|
||||
|
@ -207,14 +217,15 @@ try {
|
|||
$workflow->setConduitURI($conduit_uri);
|
||||
|
||||
// Apply global CA bundle from configs.
|
||||
if ($ca_bundle = $working_copy->getConfigFromAnySource('https.cabundle')) {
|
||||
$ca_bundle = $configuration_manager->getConfigFromAnySource('https.cabundle');
|
||||
if ($ca_bundle) {
|
||||
$ca_bundle = Filesystem::resolvePath(
|
||||
$ca_bundle, $working_copy->getProjectRoot());
|
||||
HTTPSFuture::setGlobalCABundleFromPath($ca_bundle);
|
||||
}
|
||||
|
||||
$blind_key = 'https.blindly-trust-domains';
|
||||
$blind_trust = $working_copy->getConfigFromAnySource($blind_key);
|
||||
$blind_trust = $configuration_manager->getConfigFromAnySource($blind_key);
|
||||
if ($blind_trust) {
|
||||
HTTPSFuture::setBlindlyTrustDomains($blind_trust);
|
||||
}
|
||||
|
@ -268,12 +279,13 @@ try {
|
|||
}
|
||||
|
||||
if ($need_repository_api || ($want_repository_api && $working_copy)) {
|
||||
$repository_api = ArcanistRepositoryAPI::newAPIFromWorkingCopyIdentity(
|
||||
$working_copy);
|
||||
$repository_api = ArcanistRepositoryAPI::newAPIFromConfigurationManager(
|
||||
$configuration_manager);
|
||||
$workflow->setRepositoryAPI($repository_api);
|
||||
}
|
||||
|
||||
$listeners = $working_copy->getConfigFromAnySource('events.listeners');
|
||||
$listeners = $configuration_manager->getConfigFromAnySource(
|
||||
'events.listeners');
|
||||
if ($listeners) {
|
||||
foreach ($listeners as $listener) {
|
||||
$console->writeLog(
|
||||
|
|
|
@ -43,6 +43,7 @@ phutil_register_library_map(array(
|
|||
'ArcanistConduitLinter' => 'lint/linter/ArcanistConduitLinter.php',
|
||||
'ArcanistConfiguration' => 'configuration/ArcanistConfiguration.php',
|
||||
'ArcanistConfigurationDrivenLintEngine' => 'lint/engine/ArcanistConfigurationDrivenLintEngine.php',
|
||||
'ArcanistConfigurationManager' => 'configuration/ArcanistConfigurationManager.php',
|
||||
'ArcanistCoverWorkflow' => 'workflow/ArcanistCoverWorkflow.php',
|
||||
'ArcanistCppcheckLinter' => 'lint/linter/ArcanistCppcheckLinter.php',
|
||||
'ArcanistCpplintLinter' => 'lint/linter/ArcanistCpplintLinter.php',
|
||||
|
|
|
@ -78,7 +78,7 @@ class ArcanistConfiguration {
|
|||
final public function selectWorkflow(
|
||||
&$command,
|
||||
array &$args,
|
||||
ArcanistWorkingCopyIdentity $working_copy,
|
||||
ArcanistConfigurationManager $configuration_manager,
|
||||
PhutilConsole $console) {
|
||||
|
||||
// First, try to build a workflow with the exact name provided. We always
|
||||
|
@ -92,12 +92,12 @@ class ArcanistConfiguration {
|
|||
// and substitute it. We do this only after trying to resolve the workflow
|
||||
// normally to prevent you from doing silly things like aliasing 'alias'
|
||||
// to something else.
|
||||
$aliases = ArcanistAliasWorkflow::getAliases($working_copy);
|
||||
$aliases = ArcanistAliasWorkflow::getAliases($configuration_manager);
|
||||
list($new_command, $args) = ArcanistAliasWorkflow::resolveAliases(
|
||||
$command,
|
||||
$this,
|
||||
$args,
|
||||
$working_copy);
|
||||
$configuration_manager);
|
||||
|
||||
$full_alias = idx($aliases, $command, array());
|
||||
$full_alias = implode(' ', $full_alias);
|
||||
|
|
248
src/configuration/ArcanistConfigurationManager.php
Normal file
248
src/configuration/ArcanistConfigurationManager.php
Normal file
|
@ -0,0 +1,248 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This class holds everything related to configuration and configuration files.
|
||||
*
|
||||
* @group config
|
||||
*/
|
||||
final class ArcanistConfigurationManager {
|
||||
|
||||
private $runtimeConfig = array();
|
||||
private $workingCopy = null;
|
||||
|
||||
public function setWorkingCopyIdentity(
|
||||
ArcanistWorkingCopyIdentity $working_copy) {
|
||||
$this->workingCopy = $working_copy;
|
||||
}
|
||||
|
||||
/* -( Get config )--------------------------------------------------------- */
|
||||
|
||||
const CONFIG_SOURCE_RUNTIME = 'runtime';
|
||||
const CONFIG_SOURCE_LOCAL = 'local';
|
||||
const CONFIG_SOURCE_PROJECT = 'project';
|
||||
const CONFIG_SOURCE_USER = 'user';
|
||||
const CONFIG_SOURCE_SYSTEM = 'system';
|
||||
|
||||
public function getProjectConfig($key) {
|
||||
if ($this->workingCopy) {
|
||||
return $this->workingCopy->getConfig($key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getLocalConfig($key) {
|
||||
if ($this->workingCopy) {
|
||||
return $this->workingCopy->getLocalConfig($key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getWorkingCopyIdentity() {
|
||||
return $this->workingCopy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a configuration directive from any available configuration source.
|
||||
* This includes the directive in local, user and system configuration in
|
||||
* addition to project configuration, and configuration provided as command
|
||||
* arguments ("runtime").
|
||||
* The precedence is runtime > local > project > user > system
|
||||
*
|
||||
* @param key Key to read.
|
||||
* @param wild Default value if key is not found.
|
||||
* @return wild Value, or default value if not found.
|
||||
*
|
||||
* @task config
|
||||
*/
|
||||
public function getConfigFromAnySource($key, $default = null) {
|
||||
$all = $this->getConfigFromAllSources($key);
|
||||
return empty($all) ? $default : head($all);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the advanced case where you want customized configuratin handling.
|
||||
*
|
||||
* Reads the configuration from all available sources, returning a map (array)
|
||||
* of results, with the source as key. Missing values will not be in the map,
|
||||
* so an empty array will be returned if no results are found.
|
||||
*
|
||||
* The map is ordered by the cannonical sources precedence, which is:
|
||||
* runtime > local > project > user > system
|
||||
*
|
||||
* @param key Key to read
|
||||
* @return array Mapping of source => value read. Sources with no value are
|
||||
* not in the array.
|
||||
*
|
||||
* @task config
|
||||
*/
|
||||
public function getConfigFromAllSources($key) {
|
||||
$results = array();
|
||||
$settings = new ArcanistSettings();
|
||||
|
||||
$pval = idx($this->runtimeConfig, $key);
|
||||
if ($pval !== null) {
|
||||
$results[self::CONFIG_SOURCE_RUNTIME] =
|
||||
$settings->willReadValue($key, $pval);
|
||||
}
|
||||
|
||||
$pval = $this->getLocalConfig($key);
|
||||
if ($pval !== null) {
|
||||
$results[self::CONFIG_SOURCE_LOCAL] =
|
||||
$settings->willReadValue($key, $pval);
|
||||
}
|
||||
|
||||
$pval = $this->getProjectConfig($key);
|
||||
if ($pval !== null) {
|
||||
$results[self::CONFIG_SOURCE_PROJECT] =
|
||||
$settings->willReadValue($key, $pval);
|
||||
}
|
||||
|
||||
$user_config = $this->readUserArcConfig();
|
||||
$pval = idx($user_config, $key);
|
||||
if ($pval !== null) {
|
||||
$results[self::CONFIG_SOURCE_USER] =
|
||||
$settings->willReadValue($key, $pval);
|
||||
}
|
||||
|
||||
$system_config = $this->readSystemArcConfig();
|
||||
$pval = idx($system_config, $key);
|
||||
if ($pval !== null) {
|
||||
$results[self::CONFIG_SOURCE_SYSTEM] =
|
||||
$settings->willReadValue($key, $pval);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a runtime config value that takes precedence over any static
|
||||
* config values.
|
||||
*
|
||||
* @param key Key to set.
|
||||
* @param value The value of the key.
|
||||
*
|
||||
* @task config
|
||||
*/
|
||||
public function setRuntimeConfig($key, $value) {
|
||||
$this->runtimeConfig[$key] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/* -( Read/write config )--------------------------------------------------- */
|
||||
|
||||
public function readLocalArcConfig() {
|
||||
if ($this->workingCopy) {
|
||||
return $this->workingCopy->readLocalArcConfig();
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function writeLocalArcConfig(array $config) {
|
||||
if ($this->workingCopy) {
|
||||
return $this->workingCopy->writeLocalArcConfig($config);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is probably not the method you're looking for; try
|
||||
* @{method:readUserArcConfig}.
|
||||
*/
|
||||
public function readUserConfigurationFile() {
|
||||
$user_config = array();
|
||||
$user_config_path = self::getUserConfigurationFileLocation();
|
||||
if (Filesystem::pathExists($user_config_path)) {
|
||||
|
||||
if (!phutil_is_windows()) {
|
||||
$mode = fileperms($user_config_path);
|
||||
if (!$mode) {
|
||||
throw new Exception("Unable to get perms of '{$user_config_path}'!");
|
||||
}
|
||||
if ($mode & 0177) {
|
||||
// Mode should allow only owner access.
|
||||
$prompt = "File permissions on your ~/.arcrc are too open. ".
|
||||
"Fix them by chmod'ing to 600?";
|
||||
if (!phutil_console_confirm($prompt, $default_no = false)) {
|
||||
throw new ArcanistUsageException("Set ~/.arcrc to file mode 600.");
|
||||
}
|
||||
execx('chmod 600 %s', $user_config_path);
|
||||
|
||||
// Drop the stat cache so we don't read the old permissions if
|
||||
// we end up here again. If we don't do this, we may prompt the user
|
||||
// to fix permissions multiple times.
|
||||
clearstatcache();
|
||||
}
|
||||
}
|
||||
|
||||
$user_config_data = Filesystem::readFile($user_config_path);
|
||||
$user_config = json_decode($user_config_data, true);
|
||||
if (!is_array($user_config)) {
|
||||
throw new ArcanistUsageException(
|
||||
"Your '~/.arcrc' file is not a valid JSON file.");
|
||||
}
|
||||
}
|
||||
return $user_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is probably not the method you're looking for; try
|
||||
* @{method:writeUserArcConfig}.
|
||||
*/
|
||||
public function writeUserConfigurationFile($config) {
|
||||
$json_encoder = new PhutilJSON();
|
||||
$json = $json_encoder->encodeFormatted($config);
|
||||
|
||||
$path = self::getUserConfigurationFileLocation();
|
||||
Filesystem::writeFile($path, $json);
|
||||
|
||||
if (!phutil_is_windows()) {
|
||||
execx('chmod 600 %s', $path);
|
||||
}
|
||||
}
|
||||
|
||||
public function getUserConfigurationFileLocation() {
|
||||
if (phutil_is_windows()) {
|
||||
return getenv('APPDATA').'/.arcrc';
|
||||
} else {
|
||||
return getenv('HOME').'/.arcrc';
|
||||
}
|
||||
}
|
||||
|
||||
public function readUserArcConfig() {
|
||||
return idx(self::readUserConfigurationFile(), 'config', array());
|
||||
}
|
||||
|
||||
public function writeUserArcConfig(array $options) {
|
||||
$config = self::readUserConfigurationFile();
|
||||
$config['config'] = $options;
|
||||
self::writeUserConfigurationFile($config);
|
||||
}
|
||||
|
||||
|
||||
public function getSystemArcConfigLocation() {
|
||||
if (phutil_is_windows()) {
|
||||
return Filesystem::resolvePath(
|
||||
'Phabricator/Arcanist/config',
|
||||
getenv('ProgramData'));
|
||||
} else {
|
||||
return '/etc/arcconfig';
|
||||
}
|
||||
}
|
||||
|
||||
public function readSystemArcConfig() {
|
||||
$system_config = array();
|
||||
$system_config_path = self::getSystemArcConfigLocation();
|
||||
if (Filesystem::pathExists($system_config_path)) {
|
||||
$file = Filesystem::readFile($system_config_path);
|
||||
if ($file) {
|
||||
$system_config = json_decode($file, true);
|
||||
}
|
||||
}
|
||||
return $system_config;
|
||||
}
|
||||
|
||||
}
|
|
@ -347,9 +347,8 @@ final class ArcanistScriptAndRegexLinter extends ArcanistLinter {
|
|||
* @task config
|
||||
*/
|
||||
private function getConfiguredScript() {
|
||||
$working_copy = $this->getEngine()->getWorkingCopy();
|
||||
$key = 'linter.scriptandregex.script';
|
||||
$config = $working_copy->getConfigFromAnySource($key);
|
||||
$config = $this->getConfigFromAnySource($key);
|
||||
|
||||
if (!$config) {
|
||||
throw new ArcanistUsageException(
|
||||
|
@ -373,9 +372,8 @@ final class ArcanistScriptAndRegexLinter extends ArcanistLinter {
|
|||
* @task config
|
||||
*/
|
||||
private function getConfiguredRegex() {
|
||||
$working_copy = $this->getEngine()->getWorkingCopy();
|
||||
$key = 'linter.scriptandregex.regex';
|
||||
$config = $working_copy->getConfigFromAnySource($key);
|
||||
$config = $this->getConfigFromAnySource($key);
|
||||
|
||||
if (!$config) {
|
||||
throw new ArcanistUsageException(
|
||||
|
|
|
@ -1630,7 +1630,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
|
|||
$global_string = $global->getConcreteString();
|
||||
$globals_map[$global_string] = true;
|
||||
$names[] = array(
|
||||
'global',
|
||||
'user',
|
||||
$global_string,
|
||||
$global,
|
||||
|
||||
|
|
|
@ -38,10 +38,10 @@ final class ArcanistBaseCommitParser {
|
|||
|
||||
public function resolveBaseCommit(array $specs) {
|
||||
$specs += array(
|
||||
'args' => '',
|
||||
'runtime' => '',
|
||||
'local' => '',
|
||||
'project' => '',
|
||||
'global' => '',
|
||||
'user' => '',
|
||||
'system' => '',
|
||||
);
|
||||
|
||||
|
@ -50,10 +50,10 @@ final class ArcanistBaseCommitParser {
|
|||
}
|
||||
|
||||
$this->try = array(
|
||||
'args',
|
||||
'runtime',
|
||||
'local',
|
||||
'project',
|
||||
'global',
|
||||
'user',
|
||||
'system',
|
||||
);
|
||||
|
||||
|
@ -116,6 +116,8 @@ final class ArcanistBaseCommitParser {
|
|||
* Handle resolving "arc:*" rules.
|
||||
*/
|
||||
private function resolveArcRule($rule, $name, $source) {
|
||||
$name = $this->updateLegacyRuleName($name);
|
||||
|
||||
switch ($name) {
|
||||
case 'verbose':
|
||||
$this->verbose = true;
|
||||
|
@ -126,9 +128,9 @@ final class ArcanistBaseCommitParser {
|
|||
$this->api->setBaseCommitExplanation($reason);
|
||||
return phutil_console_prompt('Against which commit?');
|
||||
case 'local':
|
||||
case 'global':
|
||||
case 'user':
|
||||
case 'project':
|
||||
case 'args':
|
||||
case 'runtime':
|
||||
case 'system':
|
||||
// Push the other source on top of the list.
|
||||
array_unshift($this->try, $name);
|
||||
|
@ -175,4 +177,17 @@ final class ArcanistBaseCommitParser {
|
|||
}
|
||||
}
|
||||
|
||||
private function updateLegacyRuleName($name) {
|
||||
$updated = array(
|
||||
'global' => 'user',
|
||||
'args' => 'runtime',
|
||||
);
|
||||
$new_name = idx($updated, $name);
|
||||
if ($new_name) {
|
||||
$this->log("translating legacy name '$name' to '$new_name'");
|
||||
return $new_name;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ final class ArcanistBaseCommitParserTestCase extends ArcanistTestCase {
|
|||
'Literal',
|
||||
'xyz',
|
||||
array(
|
||||
'args' => 'literal:xyz',
|
||||
'runtime' => 'literal:xyz',
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,8 @@ final class ArcanistBaseCommitParserTestCase extends ArcanistTestCase {
|
|||
array(
|
||||
'local' => 'literal:n',
|
||||
'project' => 'literal:n',
|
||||
'args' => 'literal:y',
|
||||
'global' => 'literal:n',
|
||||
'runtime' => 'literal:y',
|
||||
'user' => 'literal:n',
|
||||
));
|
||||
|
||||
$this->assertCommit(
|
||||
|
@ -42,7 +42,7 @@ final class ArcanistBaseCommitParserTestCase extends ArcanistTestCase {
|
|||
array(
|
||||
'project' => 'literal:n',
|
||||
'local' => 'literal:y',
|
||||
'global' => 'literal:n',
|
||||
'user' => 'literal:n',
|
||||
));
|
||||
|
||||
$this->assertCommit(
|
||||
|
@ -50,17 +50,42 @@ final class ArcanistBaseCommitParserTestCase extends ArcanistTestCase {
|
|||
'y',
|
||||
array(
|
||||
'project' => 'literal:y',
|
||||
'global' => 'literal:n',
|
||||
'user' => 'literal:n',
|
||||
));
|
||||
|
||||
$this->assertCommit(
|
||||
'Order: Global',
|
||||
'y',
|
||||
array(
|
||||
'global' => 'literal:y',
|
||||
'user' => 'literal:y',
|
||||
));
|
||||
}
|
||||
|
||||
public function testLegacyRule() {
|
||||
// 'global' should translate to 'user'
|
||||
$this->assertCommit(
|
||||
'"global" name',
|
||||
'y',
|
||||
array(
|
||||
'runtime' => 'arc:global, arc:halt',
|
||||
'local' => 'arc:halt',
|
||||
'project' => 'arc:halt',
|
||||
'user' => 'literal:y',
|
||||
));
|
||||
|
||||
// 'args' should translate to 'runtime'
|
||||
$this->assertCommit(
|
||||
'"args" name',
|
||||
'y',
|
||||
array(
|
||||
'runtime' => 'arc:project, literal:y',
|
||||
'local' => 'arc:halt',
|
||||
'project' => 'arc:args',
|
||||
'user' => 'arc:halt',
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
public function testHalt() {
|
||||
|
||||
// 'arc:halt' should halt all processing.
|
||||
|
@ -69,7 +94,7 @@ final class ArcanistBaseCommitParserTestCase extends ArcanistTestCase {
|
|||
'Halt',
|
||||
null,
|
||||
array(
|
||||
'args' => 'arc:halt',
|
||||
'runtime' => 'arc:halt',
|
||||
'local' => 'literal:xyz',
|
||||
));
|
||||
}
|
||||
|
@ -82,17 +107,17 @@ final class ArcanistBaseCommitParserTestCase extends ArcanistTestCase {
|
|||
'Yield',
|
||||
'xyz',
|
||||
array(
|
||||
'args' => 'arc:yield, literal:abc',
|
||||
'runtime' => 'arc:yield, literal:abc',
|
||||
'local' => 'literal:xyz',
|
||||
));
|
||||
|
||||
// This one should return to 'args' after exhausting 'local'.
|
||||
// This one should return to 'runtime' after exhausting 'local'.
|
||||
|
||||
$this->assertCommit(
|
||||
'Yield + Return',
|
||||
'abc',
|
||||
array(
|
||||
'args' => 'arc:yield, literal:abc',
|
||||
'runtime' => 'arc:yield, literal:abc',
|
||||
'local' => 'arc:skip',
|
||||
));
|
||||
}
|
||||
|
@ -105,25 +130,25 @@ final class ArcanistBaseCommitParserTestCase extends ArcanistTestCase {
|
|||
'Jump',
|
||||
'abc',
|
||||
array(
|
||||
'args' => 'arc:project, arc:halt',
|
||||
'runtime' => 'arc:project, arc:halt',
|
||||
'local' => 'literal:abc',
|
||||
'project' => 'arc:global, arc:halt',
|
||||
'global' => 'arc:local, arc:halt',
|
||||
'project' => 'arc:user, arc:halt',
|
||||
'user' => 'arc:local, arc:halt',
|
||||
));
|
||||
}
|
||||
|
||||
public function testJumpReturn() {
|
||||
|
||||
// After jumping to project, we should return to 'args'.
|
||||
// After jumping to project, we should return to 'runtime'.
|
||||
|
||||
$this->assertCommit(
|
||||
'Jump Return',
|
||||
'xyz',
|
||||
array(
|
||||
'args' => 'arc:project, literal:xyz',
|
||||
'runtime' => 'arc:project, literal:xyz',
|
||||
'local' => 'arc:halt',
|
||||
'project' => '',
|
||||
'global' => 'arc:halt',
|
||||
'user' => 'arc:halt',
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -140,8 +165,11 @@ final class ArcanistBaseCommitParserTestCase extends ArcanistTestCase {
|
|||
// isolation for repository-oriented test cases.
|
||||
|
||||
$root = dirname(phutil_get_library_root('arcanist'));
|
||||
$copy = ArcanistWorkingCopyIdentity::newFromPath($root);
|
||||
$repo = ArcanistRepositoryAPI::newAPIFromWorkingCopyIdentity($copy);
|
||||
$working_copy = ArcanistWorkingCopyIdentity::newFromPath($root);
|
||||
$configuration_manager = new ArcanistConfigurationManager();
|
||||
$configuration_manager->setWorkingCopyIdentity($working_copy);
|
||||
$repo = ArcanistRepositoryAPI::newAPIFromConfigurationManager(
|
||||
$configuration_manager);
|
||||
|
||||
return new ArcanistBaseCommitParser($repo);
|
||||
}
|
||||
|
|
|
@ -78,8 +78,11 @@ final class ArcanistBundleTestCase extends ArcanistTestCase {
|
|||
$fixture_path = $fixture->getPath();
|
||||
$working_copy = ArcanistWorkingCopyIdentity::newFromPath($fixture_path);
|
||||
|
||||
$repository_api = ArcanistRepositoryAPI::newAPIFromWorkingCopyIdentity(
|
||||
$working_copy);
|
||||
$configuration_manager = new ArcanistConfigurationManager();
|
||||
$configuration_manager->setWorkingCopyIdentity($working_copy);
|
||||
$repository_api = ArcanistRepositoryAPI::newAPIFromConfigurationManager(
|
||||
$configuration_manager);
|
||||
|
||||
$repository_api->setBaseCommitArgumentRules('arc:this');
|
||||
$diff = $repository_api->getFullGitDiff();
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
|
|||
}
|
||||
|
||||
if ($this->getBaseCommitArgumentRules() ||
|
||||
$this->getWorkingCopyIdentity()->getConfigFromAnySource('base')) {
|
||||
$this->getConfigurationManager()->getConfigFromAnySource('base')) {
|
||||
$base = $this->resolveBaseCommit();
|
||||
if (!$base) {
|
||||
throw new ArcanistUsageException(
|
||||
|
|
|
@ -28,7 +28,7 @@ abstract class ArcanistRepositoryAPI {
|
|||
protected $path;
|
||||
protected $diffLinesOfContext = 0x7FFF;
|
||||
private $baseCommitExplanation = '???';
|
||||
private $workingCopyIdentity;
|
||||
private $configurationManager;
|
||||
private $baseCommitArgumentRules;
|
||||
|
||||
private $uncommittedStatusCache;
|
||||
|
@ -49,11 +49,22 @@ abstract class ArcanistRepositoryAPI {
|
|||
}
|
||||
|
||||
public function getWorkingCopyIdentity() {
|
||||
return $this->workingCopyIdentity;
|
||||
return $this->configurationManager->getWorkingCopyIdentity();
|
||||
}
|
||||
|
||||
public static function newAPIFromWorkingCopyIdentity(
|
||||
ArcanistWorkingCopyIdentity $working_copy) {
|
||||
public function getConfigurationManager() {
|
||||
return $this->configurationManager;
|
||||
}
|
||||
|
||||
public static function newAPIFromConfigurationManager(
|
||||
ArcanistConfigurationManager $configuration_manager) {
|
||||
|
||||
$working_copy = $configuration_manager->getWorkingCopyIdentity();
|
||||
|
||||
if (!$working_copy) {
|
||||
throw new Exception(
|
||||
"Trying to create a RepositoryApi without a working copy");
|
||||
}
|
||||
|
||||
$root = $working_copy->getProjectRoot();
|
||||
|
||||
|
@ -65,7 +76,7 @@ abstract class ArcanistRepositoryAPI {
|
|||
|
||||
if (Filesystem::pathExists($root.'/.hg')) {
|
||||
$api = new ArcanistMercurialAPI($root);
|
||||
$api->workingCopyIdentity = $working_copy;
|
||||
$api->configurationManager = $configuration_manager;
|
||||
return $api;
|
||||
}
|
||||
|
||||
|
@ -78,7 +89,7 @@ abstract class ArcanistRepositoryAPI {
|
|||
}
|
||||
|
||||
$api = new ArcanistGitAPI($root);
|
||||
$api->workingCopyIdentity = $working_copy;
|
||||
$api->configurationManager = $configuration_manager;
|
||||
return $api;
|
||||
}
|
||||
|
||||
|
@ -86,7 +97,7 @@ abstract class ArcanistRepositoryAPI {
|
|||
foreach (Filesystem::walkToRoot($root) as $dir) {
|
||||
if (Filesystem::pathExists($dir . '/.svn')) {
|
||||
$api = new ArcanistSubversionAPI($root);
|
||||
$api->workingCopyIdentity = $working_copy;
|
||||
$api->configurationManager = $configuration_manager;
|
||||
return $api;
|
||||
}
|
||||
}
|
||||
|
@ -643,19 +654,19 @@ abstract class ArcanistRepositoryAPI {
|
|||
}
|
||||
|
||||
public function resolveBaseCommit() {
|
||||
$working_copy = $this->getWorkingCopyIdentity();
|
||||
$global_config = ArcanistBaseWorkflow::readGlobalArcConfig();
|
||||
$system_config = ArcanistBaseWorkflow::readSystemArcConfig();
|
||||
$base_commit_rules = array(
|
||||
'runtime' => $this->getBaseCommitArgumentRules(),
|
||||
'local' => '',
|
||||
'project' => '',
|
||||
'user' => '',
|
||||
'system' => '',
|
||||
);
|
||||
$all_sources = $this->configurationManager->getConfigFromAllSources('base');
|
||||
|
||||
$base_commit_rules = $all_sources + $base_commit_rules;
|
||||
|
||||
$parser = new ArcanistBaseCommitParser($this);
|
||||
$commit = $parser->resolveBaseCommit(
|
||||
array(
|
||||
'args' => $this->getBaseCommitArgumentRules(),
|
||||
'local' => $working_copy->getLocalConfig('base', ''),
|
||||
'project' => $working_copy->getConfig('base', ''),
|
||||
'global' => idx($global_config, 'base', ''),
|
||||
'system' => idx($system_config, 'base', ''),
|
||||
));
|
||||
$commit = $parser->resolveBaseCommit($base_commit_rules);
|
||||
|
||||
return $commit;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,11 @@ final class ArcanistRepositoryAPIStateTestCase extends ArcanistTestCase {
|
|||
|
||||
$fixture_path = $fixture->getPath();
|
||||
$working_copy = ArcanistWorkingCopyIdentity::newFromPath($fixture_path);
|
||||
$configuration_manager = new ArcanistConfigurationManager();
|
||||
$configuration_manager->setWorkingCopyIdentity($working_copy);
|
||||
$api = ArcanistRepositoryAPI::newAPIFromConfigurationManager(
|
||||
$configuration_manager);
|
||||
|
||||
$api = ArcanistRepositoryAPI::newAPIFromWorkingCopyIdentity(
|
||||
$working_copy);
|
||||
$api->setBaseCommitArgumentRules('arc:this');
|
||||
|
||||
if ($api instanceof ArcanistSubversionAPI) {
|
||||
|
|
|
@ -59,27 +59,29 @@ EOTEXT
|
|||
);
|
||||
}
|
||||
|
||||
public static function getAliases($working_copy) {
|
||||
$working_copy_config_aliases = $working_copy->getConfig('aliases');
|
||||
public static function getAliases(
|
||||
ArcanistConfigurationManager $configuration_manager) {
|
||||
|
||||
$working_copy_config_aliases =
|
||||
$configuration_manager->getProjectConfig('aliases');
|
||||
if (!$working_copy_config_aliases) {
|
||||
$working_copy_config_aliases = array();
|
||||
}
|
||||
$user_config_aliases =
|
||||
idx(self::readUserConfigurationFile(), 'aliases', array());
|
||||
$user_config_aliases = idx(
|
||||
$configuration_manager->readUserConfigurationFile(),
|
||||
'aliases',
|
||||
array());
|
||||
return $user_config_aliases + $working_copy_config_aliases;
|
||||
}
|
||||
|
||||
private function writeAliases(array $aliases) {
|
||||
$config = self::readUserConfigurationFile();
|
||||
$config = $this->getConfigurationManager()->readUserConfigurationFile();
|
||||
$config['aliases'] = $aliases;
|
||||
self::writeUserConfigurationFile($config);
|
||||
$this->getConfigurationManager()->writeUserConfigurationFile($config);
|
||||
}
|
||||
|
||||
public function run() {
|
||||
// We might not be in a working directory, so we don't want to require a
|
||||
// working copy identity here.
|
||||
$working_copy = ArcanistWorkingCopyIdentity::newFromPath(getcwd());
|
||||
$aliases = self::getAliases($working_copy);
|
||||
$aliases = self::getAliases($this->getConfigurationManager());
|
||||
|
||||
$argv = $this->getArgument('argv');
|
||||
if (count($argv) == 0) {
|
||||
|
@ -140,9 +142,9 @@ EOTEXT
|
|||
$command,
|
||||
ArcanistConfiguration $config,
|
||||
array $argv,
|
||||
ArcanistWorkingCopyIdentity $working_copy) {
|
||||
ArcanistConfigurationManager $configuration_manager) {
|
||||
|
||||
$aliases = ArcanistAliasWorkflow::getAliases($working_copy);
|
||||
$aliases = ArcanistAliasWorkflow::getAliases($configuration_manager);
|
||||
if (!isset($aliases[$command])) {
|
||||
return array(null, $argv);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
private $userPHID;
|
||||
private $userName;
|
||||
private $repositoryAPI;
|
||||
private $configurationManager;
|
||||
private $workingCopy;
|
||||
private $arguments;
|
||||
private $passedArguments;
|
||||
|
@ -182,8 +183,8 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
$this->conduit->setTimeout($this->conduitTimeout);
|
||||
}
|
||||
|
||||
$user = $this->getConfigFromWhateverSourceAvailiable('http.basicauth.user');
|
||||
$pass = $this->getConfigFromWhateverSourceAvailiable('http.basicauth.pass');
|
||||
$user = $this->getConfigFromAnySource('http.basicauth.user');
|
||||
$pass = $this->getConfigFromAnySource('http.basicauth.pass');
|
||||
if ($user !== null && $pass !== null) {
|
||||
$this->conduit->setBasicAuthCredentials($user, $pass);
|
||||
}
|
||||
|
@ -191,21 +192,8 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
return $this;
|
||||
}
|
||||
|
||||
final public function getConfigFromWhateverSourceAvailiable($key) {
|
||||
if ($this->requiresWorkingCopy()) {
|
||||
$working_copy = $this->getWorkingCopy();
|
||||
return $working_copy->getConfigFromAnySource($key);
|
||||
} else {
|
||||
$global_config = self::readGlobalArcConfig();
|
||||
$pval = idx($global_config, $key);
|
||||
|
||||
if ($pval === null) {
|
||||
$system_config = self::readSystemArcConfig();
|
||||
$pval = idx($system_config, $key);
|
||||
}
|
||||
|
||||
return $pval;
|
||||
}
|
||||
final public function getConfigFromAnySource($key) {
|
||||
return $this->configurationManager->getConfigFromAnySource($key);
|
||||
}
|
||||
|
||||
|
||||
|
@ -513,6 +501,17 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
return $this->arcanistConfiguration;
|
||||
}
|
||||
|
||||
public function setConfigurationManager(
|
||||
ArcanistConfigurationManager $arcanist_configuration_manager) {
|
||||
|
||||
$this->configurationManager = $arcanist_configuration_manager;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getConfigurationManager() {
|
||||
return $this->configurationManager;
|
||||
}
|
||||
|
||||
public function requiresWorkingCopy() {
|
||||
return false;
|
||||
}
|
||||
|
@ -565,6 +564,7 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
$workflow = $arc_config->buildWorkflow($command);
|
||||
$workflow->setParentWorkflow($this);
|
||||
$workflow->setCommand($command);
|
||||
$workflow->setConfigurationManager($this->getConfigurationManager());
|
||||
|
||||
if ($this->repositoryAPI) {
|
||||
$workflow->setRepositoryAPI($this->repositoryAPI);
|
||||
|
@ -732,13 +732,14 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
}
|
||||
|
||||
public function getWorkingCopy() {
|
||||
if (!$this->workingCopy) {
|
||||
$working_copy = $this->getConfigurationManager()->getWorkingCopyIdentity();
|
||||
if (!$working_copy) {
|
||||
$workflow = get_class($this);
|
||||
throw new Exception(
|
||||
"This workflow ('{$workflow}') requires a working copy, override ".
|
||||
"requiresWorkingCopy() to return true.");
|
||||
}
|
||||
return $this->workingCopy;
|
||||
return $working_copy;
|
||||
}
|
||||
|
||||
public function setWorkingCopy(
|
||||
|
@ -856,7 +857,7 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
$api->addToCommit($unstaged);
|
||||
$must_commit += array_flip($unstaged);
|
||||
} else {
|
||||
$permit_autostash = $this->getWorkingCopy()->getConfigFromAnySource(
|
||||
$permit_autostash = $this->getConfigFromAnySource(
|
||||
'arc.autostash',
|
||||
false);
|
||||
if ($permit_autostash && $api->canStashChanges()) {
|
||||
|
@ -1167,114 +1168,6 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
return $argv;
|
||||
}
|
||||
|
||||
public static function getSystemArcConfigLocation() {
|
||||
if (phutil_is_windows()) {
|
||||
return Filesystem::resolvePath(
|
||||
'Phabricator/Arcanist/config',
|
||||
getenv('ProgramData'));
|
||||
} else {
|
||||
return '/etc/arcconfig';
|
||||
}
|
||||
}
|
||||
|
||||
public static function readSystemArcConfig() {
|
||||
$system_config = array();
|
||||
$system_config_path = self::getSystemArcConfigLocation();
|
||||
if (Filesystem::pathExists($system_config_path)) {
|
||||
$file = Filesystem::readFile($system_config_path);
|
||||
if ($file) {
|
||||
$system_config = json_decode($file, true);
|
||||
}
|
||||
}
|
||||
return $system_config;
|
||||
}
|
||||
public static function getUserConfigurationFileLocation() {
|
||||
if (phutil_is_windows()) {
|
||||
return getenv('APPDATA').'/.arcrc';
|
||||
} else {
|
||||
return getenv('HOME').'/.arcrc';
|
||||
}
|
||||
}
|
||||
|
||||
public static function readUserConfigurationFile() {
|
||||
$user_config = array();
|
||||
$user_config_path = self::getUserConfigurationFileLocation();
|
||||
if (Filesystem::pathExists($user_config_path)) {
|
||||
|
||||
if (!phutil_is_windows()) {
|
||||
$mode = fileperms($user_config_path);
|
||||
if (!$mode) {
|
||||
throw new Exception("Unable to get perms of '{$user_config_path}'!");
|
||||
}
|
||||
if ($mode & 0177) {
|
||||
// Mode should allow only owner access.
|
||||
$prompt = "File permissions on your ~/.arcrc are too open. ".
|
||||
"Fix them by chmod'ing to 600?";
|
||||
if (!phutil_console_confirm($prompt, $default_no = false)) {
|
||||
throw new ArcanistUsageException("Set ~/.arcrc to file mode 600.");
|
||||
}
|
||||
execx('chmod 600 %s', $user_config_path);
|
||||
|
||||
// Drop the stat cache so we don't read the old permissions if
|
||||
// we end up here again. If we don't do this, we may prompt the user
|
||||
// to fix permissions multiple times.
|
||||
clearstatcache();
|
||||
}
|
||||
}
|
||||
|
||||
$user_config_data = Filesystem::readFile($user_config_path);
|
||||
$user_config = json_decode($user_config_data, true);
|
||||
if (!is_array($user_config)) {
|
||||
throw new ArcanistUsageException(
|
||||
"Your '~/.arcrc' file is not a valid JSON file.");
|
||||
}
|
||||
}
|
||||
return $user_config;
|
||||
}
|
||||
|
||||
|
||||
public static function writeUserConfigurationFile($config) {
|
||||
$json_encoder = new PhutilJSON();
|
||||
$json = $json_encoder->encodeFormatted($config);
|
||||
|
||||
$path = self::getUserConfigurationFileLocation();
|
||||
Filesystem::writeFile($path, $json);
|
||||
|
||||
if (!phutil_is_windows()) {
|
||||
execx('chmod 600 %s', $path);
|
||||
}
|
||||
}
|
||||
|
||||
public static function readGlobalArcConfig() {
|
||||
return idx(self::readUserConfigurationFile(), 'config', array());
|
||||
}
|
||||
|
||||
public static function writeGlobalArcConfig(array $options) {
|
||||
$config = self::readUserConfigurationFile();
|
||||
$config['config'] = $options;
|
||||
self::writeUserConfigurationFile($config);
|
||||
}
|
||||
|
||||
public function readLocalArcConfig() {
|
||||
$local = array();
|
||||
$file = $this->readScratchFile('config');
|
||||
if ($file) {
|
||||
$local = json_decode($file, true);
|
||||
}
|
||||
|
||||
return $local;
|
||||
}
|
||||
|
||||
public function writeLocalArcConfig(array $config) {
|
||||
$json_encoder = new PhutilJSON();
|
||||
$json = $json_encoder->encodeFormatted($config);
|
||||
|
||||
$this->writeScratchFile('config', $json);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a message to stderr so that '--json' flags or stdout which is meant
|
||||
* to be piped somewhere aren't disrupted.
|
||||
|
@ -1288,9 +1181,8 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
|
||||
protected function isHistoryImmutable() {
|
||||
$repository_api = $this->getRepositoryAPI();
|
||||
$working_copy = $this->getWorkingCopy();
|
||||
|
||||
$config = $working_copy->getConfigFromAnySource('history.immutable');
|
||||
$config = $this->getConfigFromAnySource('history.immutable');
|
||||
if ($config !== null) {
|
||||
return $config;
|
||||
}
|
||||
|
@ -1530,7 +1422,7 @@ abstract class ArcanistBaseWorkflow extends Phobject {
|
|||
protected function newInteractiveEditor($text) {
|
||||
$editor = new PhutilInteractiveEditor($text);
|
||||
|
||||
$preferred = $this->getWorkingCopy()->getConfigFromAnySource('editor');
|
||||
$preferred = $this->getConfigFromAnySource('editor');
|
||||
if ($preferred) {
|
||||
$editor->setPreferredEditor($preferred);
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ EOTEXT
|
|||
}
|
||||
|
||||
private function getBrowserCommand() {
|
||||
$config = $this->getWorkingCopy()->getConfigFromAnySource('browser');
|
||||
$config = $this->getConfigFromAnySource('browser');
|
||||
if ($config) {
|
||||
return $config;
|
||||
}
|
||||
|
|
|
@ -42,11 +42,16 @@ EOTEXT
|
|||
|
||||
$settings = new ArcanistSettings();
|
||||
|
||||
$configuration_manager = $this->getConfigurationManager();
|
||||
$configs = array(
|
||||
'system' => self::readSystemArcConfig(),
|
||||
'global' => self::readGlobalArcConfig(),
|
||||
'project' => $this->getWorkingCopy()->getProjectConfig(),
|
||||
'local' => $this->readLocalArcConfig(),
|
||||
ArcanistConfigurationManager::CONFIG_SOURCE_SYSTEM =>
|
||||
$configuration_manager->readSystemArcConfig(),
|
||||
ArcanistConfigurationManager::CONFIG_SOURCE_USER =>
|
||||
$configuration_manager->readUserArcConfig(),
|
||||
ArcanistConfigurationManager::CONFIG_SOURCE_PROJECT =>
|
||||
$this->getWorkingCopy()->readProjectConfig(),
|
||||
ArcanistConfigurationManager::CONFIG_SOURCE_LOCAL =>
|
||||
$configuration_manager->readLocalArcConfig(),
|
||||
);
|
||||
|
||||
if ($argv) {
|
||||
|
@ -65,7 +70,7 @@ EOTEXT
|
|||
}
|
||||
foreach ($configs as $name => $config) {
|
||||
switch ($name) {
|
||||
case 'project':
|
||||
case ArcanistConfigurationManager::CONFIG_SOURCE_PROJECT:
|
||||
// Respect older names in project config.
|
||||
$val = $this->getWorkingCopy()->getConfig($key);
|
||||
break;
|
||||
|
|
|
@ -53,10 +53,11 @@ EOTEXT
|
|||
|
||||
$uri = $this->determineConduitURI();
|
||||
$this->setConduitURI($uri);
|
||||
$configuration_manager = $this->getConfigurationManager();
|
||||
|
||||
echo "Installing certificate for '{$uri}'...\n";
|
||||
|
||||
$config = self::readUserConfigurationFile();
|
||||
$config = $configuration_manager->readUserConfigurationFile();
|
||||
|
||||
echo "Trying to connect to server...\n";
|
||||
$conduit = $this->establishConduit()->getConduit();
|
||||
|
@ -106,7 +107,7 @@ EOTEXT
|
|||
);
|
||||
|
||||
echo "Writing ~/.arcrc...\n";
|
||||
self::writeUserConfigurationFile($config);
|
||||
$configuration_manager->writeUserConfigurationFile($config);
|
||||
|
||||
echo phutil_console_format(
|
||||
"<bg:green>** SUCCESS! **</bg> Certificate installed.\n");
|
||||
|
|
|
@ -242,8 +242,7 @@ EOTEXT
|
|||
$this->branch = head($branch);
|
||||
$this->keepBranch = $this->getArgument('keep-branch');
|
||||
|
||||
$working_copy = $this->getWorkingCopy();
|
||||
$update_strategy = $working_copy->getConfigFromAnySource(
|
||||
$update_strategy = $this->getConfigFromAnySource(
|
||||
'arc.land.update.default',
|
||||
'merge');
|
||||
$this->shouldUpdateWithRebase = $update_strategy == 'rebase';
|
||||
|
@ -261,7 +260,7 @@ EOTEXT
|
|||
|
||||
$onto_default = $this->isGit ? 'master' : 'default';
|
||||
$onto_default = nonempty(
|
||||
$working_copy->getConfigFromAnySource('arc.land.onto.default'),
|
||||
$this->getConfigFromAnySource('arc.land.onto.default'),
|
||||
$onto_default);
|
||||
$this->onto = $this->getArgument('onto', $onto_default);
|
||||
$this->ontoType = $this->getBranchType($this->onto);
|
||||
|
|
|
@ -182,10 +182,11 @@ EOTEXT
|
|||
public function run() {
|
||||
$console = PhutilConsole::getConsole();
|
||||
$working_copy = $this->getWorkingCopy();
|
||||
$configuration_manager = $this->getConfigurationManager();
|
||||
|
||||
$engine = $this->getArgument('engine');
|
||||
if (!$engine) {
|
||||
$engine = $working_copy->getConfigFromAnySource('lint.engine');
|
||||
$engine = $configuration_manager->getConfigFromAnySource('lint.engine');
|
||||
}
|
||||
|
||||
if (!$engine) {
|
||||
|
@ -210,7 +211,7 @@ EOTEXT
|
|||
"flag lints every file.");
|
||||
}
|
||||
if ($use_cache === null) {
|
||||
$use_cache = (bool)$working_copy->getConfigFromAnySource(
|
||||
$use_cache = (bool)$configuration_manager->getConfigFromAnySource(
|
||||
'arc.lint.cache',
|
||||
false);
|
||||
}
|
||||
|
@ -260,7 +261,7 @@ EOTEXT
|
|||
|
||||
$engine = newv($engine, array());
|
||||
$this->engine = $engine;
|
||||
$engine->setWorkingCopy($working_copy);
|
||||
$engine->setWorkingCopy($working_copy); // todo setConfig?
|
||||
$engine->setMinimumSeverity(
|
||||
$this->getArgument('severity', self::DEFAULT_SEVERITY));
|
||||
|
||||
|
|
|
@ -23,12 +23,12 @@ EOTEXT
|
|||
Supports: cli
|
||||
Sets an arc configuration option.
|
||||
|
||||
Options are either global (apply to all arc commands you invoke
|
||||
Options are either user (apply to all arc commands you invoke
|
||||
from the current user) or local (apply only to the current working
|
||||
copy). By default, global configuration is written. Use __--local__
|
||||
copy). By default, user configuration is written. Use __--local__
|
||||
to write local configuration.
|
||||
|
||||
Global values are written to '~/.arcrc' on Linux and Mac OS X, and an
|
||||
User values are written to '~/.arcrc' on Linux and Mac OS X, and an
|
||||
undisclosed location on Windows. Local values are written to an arc
|
||||
directory under either .git, .hg, or .svn as appropriate.
|
||||
|
||||
|
@ -44,7 +44,7 @@ EOTEXT
|
|||
'help' => 'Show available configuration values.',
|
||||
),
|
||||
'local' => array(
|
||||
'help' => 'Set a local config value instead of a global one',
|
||||
'help' => 'Set a local config value instead of a user one',
|
||||
),
|
||||
'*' => 'argv',
|
||||
);
|
||||
|
@ -64,15 +64,16 @@ EOTEXT
|
|||
throw new ArcanistUsageException(
|
||||
"Specify a key and a value, or --show.");
|
||||
}
|
||||
$configuration_manager = $this->getConfigurationManager();
|
||||
|
||||
$is_local = $this->getArgument('local');
|
||||
|
||||
if ($is_local) {
|
||||
$config = $this->readLocalArcConfig();
|
||||
$config = $configuration_manager->readLocalArcConfig();
|
||||
$which = 'local';
|
||||
} else {
|
||||
$config = self::readGlobalArcConfig();
|
||||
$which = 'global';
|
||||
$config = $configuration_manager->readUserArcConfig();
|
||||
$which = 'user';
|
||||
}
|
||||
|
||||
$key = $argv[0];
|
||||
|
@ -88,9 +89,9 @@ EOTEXT
|
|||
if (!strlen($val)) {
|
||||
unset($config[$key]);
|
||||
if ($is_local) {
|
||||
$this->writeLocalArcConfig($config);
|
||||
$configuration_manager->writeLocalArcConfig($config);
|
||||
} else {
|
||||
self::writeGlobalArcConfig($config);
|
||||
$configuration_manager->writeUserArcConfig($config);
|
||||
}
|
||||
|
||||
$old = $settings->formatConfigValueForDisplay($key, $old);
|
||||
|
@ -105,9 +106,9 @@ EOTEXT
|
|||
|
||||
$config[$key] = $val;
|
||||
if ($is_local) {
|
||||
$this->writeLocalArcConfig($config);
|
||||
$configuration_manager->writeLocalArcConfig($config);
|
||||
} else {
|
||||
self::writeGlobalArcConfig($config);
|
||||
$configuration_manager->writeUserArcConfig($config);
|
||||
}
|
||||
|
||||
$val = $settings->formatConfigValueForDisplay($key, $val);
|
||||
|
@ -124,7 +125,7 @@ EOTEXT
|
|||
}
|
||||
|
||||
private function show() {
|
||||
$config = self::readGlobalArcConfig();
|
||||
$config = $this->getConfigurationManager()->readUserArcConfig();
|
||||
|
||||
$settings = new ArcanistSettings();
|
||||
|
||||
|
@ -143,7 +144,7 @@ EOTEXT
|
|||
echo phutil_console_format(" Example: %s\n", $example);
|
||||
}
|
||||
if (strlen($value)) {
|
||||
echo phutil_console_format(" Global Setting: %s\n", $value);
|
||||
echo phutil_console_format(" User Setting: %s\n", $value);
|
||||
}
|
||||
echo "\n";
|
||||
echo phutil_console_wrap($help, 4);
|
||||
|
|
|
@ -60,8 +60,11 @@ EOTEXT
|
|||
// but commands can raise more detailed errors.
|
||||
$working_copy = ArcanistWorkingCopyIdentity::newFromPath(getcwd());
|
||||
if ($working_copy->getProjectRoot()) {
|
||||
$repository_api = ArcanistRepositoryAPI::newAPIFromWorkingCopyIdentity(
|
||||
$working_copy);
|
||||
$configuration_manager = $this->getConfigurationManager();
|
||||
$configuration_manager->setWorkingCopyIdentity($working_copy);
|
||||
$repository_api = ArcanistRepositoryAPI::newAPIFromConfigurationManager(
|
||||
$configuration_manager);
|
||||
|
||||
$vcs = $repository_api->getSourceControlSystemName();
|
||||
}
|
||||
|
||||
|
@ -88,8 +91,8 @@ EOTEXT
|
|||
}
|
||||
|
||||
// Also permit autocompletion of "arc alias" commands.
|
||||
foreach (
|
||||
ArcanistAliasWorkflow::getAliases($working_copy) as $key => $value) {
|
||||
$aliases = ArcanistAliasWorkflow::getAliases($configuration_manager);
|
||||
foreach ($aliases as $key => $value) {
|
||||
$complete[] = $key;
|
||||
}
|
||||
|
||||
|
@ -102,7 +105,7 @@ EOTEXT
|
|||
$argv[1],
|
||||
$arc_config,
|
||||
array_slice($argv, 2),
|
||||
$working_copy);
|
||||
$configuration_manager);
|
||||
if ($new_command) {
|
||||
$workflow = $arc_config->buildWorkflow($new_command);
|
||||
}
|
||||
|
|
|
@ -173,6 +173,7 @@ EOTEXT
|
|||
|
||||
$working_copy = ArcanistWorkingCopyIdentity::newFromRootAndConfigFile(
|
||||
$project_root,
|
||||
$this->getConfigurationManager(),
|
||||
$config,
|
||||
$config_file." (svnlook: {$transaction} {$repository})");
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ EOTEXT
|
|||
|
||||
$engine_class = $this->getArgument(
|
||||
'engine',
|
||||
$working_copy->getConfigFromAnySource('unit.engine'));
|
||||
$this->getConfigurationManager()->getConfigFromAnySource('unit.engine'));
|
||||
|
||||
if (!$engine_class) {
|
||||
throw new ArcanistNoEngineException(
|
||||
|
|
|
@ -47,8 +47,10 @@ EOTEXT
|
|||
|
||||
$working_copy = ArcanistWorkingCopyIdentity::newFromPath($root);
|
||||
|
||||
$repository_api = ArcanistRepositoryAPI::newAPIFromWorkingCopyIdentity(
|
||||
$working_copy);
|
||||
$configuration_manager = clone $this->getConfigurationManager();
|
||||
$configuration_manager->setWorkingCopyIndentity($working_copy);
|
||||
$repository_api = ArcanistRepositoryAPI::newAPIFromConfigurationManager(
|
||||
$configuration_manager);
|
||||
|
||||
$this->setRepositoryAPI($repository_api);
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@ final class ArcanistWorkingCopyIdentity {
|
|||
|
||||
protected $localConfig;
|
||||
protected $projectConfig;
|
||||
protected $runtimeConfig;
|
||||
protected $projectRoot;
|
||||
protected $localMetaDir;
|
||||
|
||||
public static function newDummyWorkingCopy() {
|
||||
return new ArcanistWorkingCopyIdentity('/', array());
|
||||
return new ArcanistWorkingCopyIdentity('/', array());
|
||||
}
|
||||
|
||||
public static function newFromPath($path) {
|
||||
|
@ -93,7 +93,7 @@ final class ArcanistWorkingCopyIdentity {
|
|||
$this->projectRoot = $root;
|
||||
$this->projectConfig = $config;
|
||||
$this->localConfig = array();
|
||||
$this->runtimeConfig = array();
|
||||
$this->localMetaDir = null;
|
||||
|
||||
$vc_dirs = array(
|
||||
'.git',
|
||||
|
@ -107,15 +107,11 @@ final class ArcanistWorkingCopyIdentity {
|
|||
$this->projectRoot);
|
||||
if (Filesystem::pathExists($meta_path)) {
|
||||
$found_meta_dir = true;
|
||||
$this->localMetaDir = $meta_path;
|
||||
$local_path = Filesystem::resolvePath(
|
||||
'arc/config',
|
||||
$meta_path);
|
||||
if (Filesystem::pathExists($local_path)) {
|
||||
$file = Filesystem::readFile($local_path);
|
||||
if ($file) {
|
||||
$this->localConfig = json_decode($file, true);
|
||||
}
|
||||
}
|
||||
$this->localConfig = $this->readLocalArcConfig();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -123,14 +119,15 @@ final class ArcanistWorkingCopyIdentity {
|
|||
if (!$found_meta_dir) {
|
||||
// Try for a single higher-level .svn directory as used by svn 1.7+
|
||||
foreach (Filesystem::walkToRoot($this->projectRoot) as $parent_path) {
|
||||
$meta_path = Filesystem::resolvePath(
|
||||
'.svn',
|
||||
$parent_path);
|
||||
$local_path = Filesystem::resolvePath(
|
||||
'.svn/arc/config',
|
||||
$parent_path);
|
||||
if (Filesystem::pathExists($local_path)) {
|
||||
$file = Filesystem::readFile($local_path);
|
||||
if ($file) {
|
||||
$this->localConfig = json_decode($file, true);
|
||||
}
|
||||
$this->localMetaDir = $meta_path;
|
||||
$this->localConfig = $this->readLocalArcConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -149,14 +146,10 @@ final class ArcanistWorkingCopyIdentity {
|
|||
return $this->projectRoot.'/'.$to_file;
|
||||
}
|
||||
|
||||
public function getConduitURI() {
|
||||
return $this->getConfig('conduit_uri');
|
||||
}
|
||||
|
||||
|
||||
/* -( Config )------------------------------------------------------------- */
|
||||
|
||||
public function getProjectConfig() {
|
||||
public function readProjectConfig() {
|
||||
return $this->projectConfig;
|
||||
}
|
||||
|
||||
|
@ -195,7 +188,6 @@ final class ArcanistWorkingCopyIdentity {
|
|||
return $pval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a configuration directive from local configuration. This
|
||||
* reads ONLY the per-working copy configuration,
|
||||
|
@ -210,69 +202,46 @@ final class ArcanistWorkingCopyIdentity {
|
|||
return idx($this->localConfig, $key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a configuration directive from any available configuration source.
|
||||
* In contrast to @{method:getConfig}, this will look for the directive in
|
||||
* local and user configuration in addition to project configuration.
|
||||
* The precedence is local > project > user
|
||||
*
|
||||
* @param key Key to read.
|
||||
* @param wild Default value if key is not found.
|
||||
* @return wild Value, or default value if not found.
|
||||
*
|
||||
* @task config
|
||||
*/
|
||||
public function getConfigFromAnySource($key, $default = null) {
|
||||
$settings = new ArcanistSettings();
|
||||
|
||||
// try runtime config first
|
||||
$pval = idx($this->runtimeConfig, $key);
|
||||
|
||||
// try local config
|
||||
if ($pval === null) {
|
||||
$pval = $this->getLocalConfig($key);
|
||||
public function readLocalArcConfig() {
|
||||
if (strlen($this->localMetaDir)) {
|
||||
$local_path = Filesystem::resolvePath(
|
||||
'arc/config',
|
||||
$this->localMetaDir);
|
||||
if (Filesystem::pathExists($local_path)) {
|
||||
$file = Filesystem::readFile($local_path);
|
||||
if ($file) {
|
||||
return json_decode($file, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then per-project config
|
||||
if ($pval === null) {
|
||||
$pval = $this->getConfig($key);
|
||||
}
|
||||
|
||||
// now try global (i.e. user-level) config
|
||||
if ($pval === null) {
|
||||
$global_config = ArcanistBaseWorkflow::readGlobalArcConfig();
|
||||
$pval = idx($global_config, $key);
|
||||
}
|
||||
|
||||
// Finally, try system-level config.
|
||||
if ($pval === null) {
|
||||
$system_config = ArcanistBaseWorkflow::readSystemArcConfig();
|
||||
$pval = idx($system_config, $key);
|
||||
}
|
||||
|
||||
if ($pval === null) {
|
||||
$pval = $default;
|
||||
} else {
|
||||
$pval = $settings->willReadValue($key, $pval);
|
||||
}
|
||||
|
||||
return $pval;
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a runtime config value that takes precedence over any static
|
||||
* config values.
|
||||
*
|
||||
* @param key Key to set.
|
||||
* @param value The value of the key.
|
||||
*
|
||||
* @task config
|
||||
*/
|
||||
public function setRuntimeConfig($key, $value) {
|
||||
$this->runtimeConfig[$key] = $value;
|
||||
public function writeLocalArcConfig(array $config) {
|
||||
$dir = $this->localMetaDir;
|
||||
if (!strlen($dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this;
|
||||
if (!Filesystem::pathExists($dir)) {
|
||||
try {
|
||||
Filesystem::createDirectory($dir);
|
||||
} catch (Exception $ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$json_encoder = new PhutilJSON();
|
||||
$json = $json_encoder->encodeFormatted($config);
|
||||
|
||||
$config_file = Filesystem::resolvePath('arc/config', $dir);
|
||||
try {
|
||||
Filesystem::writeFile($config_file, $json);
|
||||
} catch (FilesystemException $ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue