Changeset View
Changeset View
Standalone View
Standalone View
src/config/ArcanistConfigurationSourceList.php
- This file was added.
| <?php | |||||
| final class ArcanistConfigurationSourceList | |||||
| extends Phobject { | |||||
| private $sources = array(); | |||||
| private $configOptions; | |||||
| public function addSource(ArcanistConfigurationSource $source) { | |||||
| $this->sources[] = $source; | |||||
| return $this; | |||||
| } | |||||
| public function getSources() { | |||||
| return $this->sources; | |||||
| } | |||||
| private function getSourcesWithScopes($scopes) { | |||||
| if ($scopes !== null) { | |||||
| $scopes = array_fuse($scopes); | |||||
| } | |||||
| $results = array(); | |||||
| foreach ($this->getSources() as $source) { | |||||
| if ($scopes !== null) { | |||||
| $scope = $source->getConfigurationSourceScope(); | |||||
| if ($scope === null) { | |||||
| continue; | |||||
| } | |||||
| if (!isset($scopes[$scope])) { | |||||
| continue; | |||||
| } | |||||
| } | |||||
| $results[] = $source; | |||||
| } | |||||
| return $results; | |||||
| } | |||||
| public function getWritableSourceFromScope($scope) { | |||||
| $sources = $this->getSourcesWithScopes(array($scope)); | |||||
| $writable = array(); | |||||
| foreach ($sources as $source) { | |||||
| if (!$source->isWritableConfigurationSource()) { | |||||
| continue; | |||||
| } | |||||
| $writable[] = $source; | |||||
| } | |||||
| if (!$writable) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Unable to write configuration: there is no writable configuration '. | |||||
| 'source in the "%s" scope.', | |||||
| $scope)); | |||||
| } | |||||
| if (count($writable) > 1) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Unable to write configuration: more than one writable source '. | |||||
| 'exists in the "%s" scope.', | |||||
| $scope)); | |||||
| } | |||||
| return head($writable); | |||||
| } | |||||
| public function getConfig($key) { | |||||
| $option = $this->getConfigOption($key); | |||||
| $values = $this->getStorageValueList($key); | |||||
| return $option->getValueFromStorageValueList($values); | |||||
| } | |||||
| public function getConfigFromScopes($key, array $scopes) { | |||||
| $option = $this->getConfigOption($key); | |||||
| $values = $this->getStorageValueListFromScopes($key, $scopes); | |||||
| return $option->getValueFromStorageValueList($values); | |||||
| } | |||||
| public function getStorageValueList($key) { | |||||
| return $this->getStorageValueListFromScopes($key, null); | |||||
| } | |||||
| private function getStorageValueListFromScopes($key, $scopes) { | |||||
| $values = array(); | |||||
| foreach ($this->getSourcesWithScopes($scopes) as $source) { | |||||
| if ($source->hasValueForKey($key)) { | |||||
| $value = $source->getValueForKey($key); | |||||
| $values[] = new ArcanistConfigurationSourceValue( | |||||
| $source, | |||||
| $source->getValueForKey($key)); | |||||
| } | |||||
| } | |||||
| return $values; | |||||
| } | |||||
| public function getConfigOption($key) { | |||||
| $options = $this->getConfigOptions(); | |||||
| if (!isset($options[$key])) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Configuration option ("%s") is unrecognized. You can only read '. | |||||
| 'recognized configuration options.', | |||||
| $key)); | |||||
| } | |||||
| return $options[$key]; | |||||
| } | |||||
| public function setConfigOptions(array $config_options) { | |||||
| assert_instances_of($config_options, 'ArcanistConfigOption'); | |||||
| $config_options = mpull($config_options, null, 'getKey'); | |||||
| $this->configOptions = $config_options; | |||||
| return $this; | |||||
| } | |||||
| public function getConfigOptions() { | |||||
| if ($this->configOptions === null) { | |||||
| throw new PhutilInvalidStateException('setConfigOptions'); | |||||
| } | |||||
| return $this->configOptions; | |||||
| } | |||||
| public function validateConfiguration(ArcanistRuntime $runtime) { | |||||
| $options = $this->getConfigOptions(); | |||||
| $aliases = array(); | |||||
| foreach ($options as $key => $option) { | |||||
| foreach ($option->getAliases() as $alias) { | |||||
| $aliases[$alias] = $key; | |||||
| } | |||||
| } | |||||
| // TOOLSETS: Handle the case where config specifies both a value and an | |||||
| // alias for that value. The alias should be ignored and we should emit | |||||
| // a warning. This also needs to be implemented when actually reading | |||||
| // configuration. | |||||
| $value_lists = array(); | |||||
| foreach ($this->getSources() as $source) { | |||||
| $keys = $source->getAllKeys(); | |||||
| foreach ($keys as $key) { | |||||
| $resolved_key = idx($aliases, $key, $key); | |||||
| $option = idx($options, $resolved_key); | |||||
| // If there's no option object for this config, this value is | |||||
| // unrecognized. Sources are free to handle this however they want: | |||||
| // for config files we emit a warning; for "--config" we fatal. | |||||
| if (!$option) { | |||||
| $source->didReadUnknownOption($runtime, $key); | |||||
| continue; | |||||
| } | |||||
| $raw_value = $source->getValueForKey($key); | |||||
| // Make sure we can convert whatever value the configuration source is | |||||
| // providing into a legitimate runtime value. | |||||
| try { | |||||
| $value = $raw_value; | |||||
| if ($source->isStringSource()) { | |||||
| $value = $option->getStorageValueFromStringValue($value); | |||||
| } | |||||
| $option->getValueFromStorageValue($value); | |||||
| $value_lists[$resolved_key][] = new ArcanistConfigurationSourceValue( | |||||
| $source, | |||||
| $raw_value); | |||||
| } catch (Exception $ex) { | |||||
| throw new PhutilProxyException( | |||||
| pht( | |||||
| 'Configuration value ("%s") defined in source "%s" is not '. | |||||
| 'valid.', | |||||
| $key, | |||||
| $source->getSourceDisplayName()), | |||||
| $ex); | |||||
| } | |||||
| } | |||||
| } | |||||
| // Make sure each value list can be merged. | |||||
| foreach ($value_lists as $key => $value_list) { | |||||
| try { | |||||
| $options[$key]->getValueFromStorageValueList($value_list); | |||||
| } catch (Exception $ex) { | |||||
| throw $ex; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||