Changeset View
Standalone View
src/config/ArcanistConfigurationSourceList.php
| <?php | <?php | ||||
| final class ArcanistConfigurationSourceList | final class ArcanistConfigurationSourceList | ||||
| extends Phobject { | extends Phobject { | ||||
| private $sources = array(); | private $sources = array(); | ||||
| private $configOptions; | |||||
| public function addSource(ArcanistConfigurationSource $source) { | public function addSource(ArcanistConfigurationSource $source) { | ||||
| $this->sources[] = $source; | $this->sources[] = $source; | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| public function getSources() { | |||||
| return $this->sources; | |||||
| } | |||||
| public function getConfig($key) { | |||||
| $option = $this->getConfigOption($key); | |||||
| $values = $this->getStorageValueList($key); | |||||
| return $option->getValueFromStorageValueList($values); | |||||
| } | |||||
| public function getStorageValueList($key) { | |||||
| $values = array(); | |||||
| foreach ($this->getSources() 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() { | |||||
| $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($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 $ex; | |||||
| } | |||||
amckinley: Why put this in a `try {}` block at all if we're catching `Exception` and then just throwing… | |||||
Done Inline ActionsCurrently, this has no effect at all (re-throwing an exception doesn't change its call stack). In the future, I anticipate needing to convert these into some kind of error object/state, save a list of them, and pass them up to the caller. If you have some bogus junk in a config file we likely want to just emit a warning and continue in at least some cases, so you can arc set-config your way out of the problem. If we actually throw here, you won't be able to fix the issue via arc set-config / arc alias / whatever. However, none of the validation can really go wrong quite yet so there's no way to actually hit this case or test it. Basically, I'm just kind of marking the blocks that probably need to do something later on, once this code is meaningfully reachable. epriestley: Currently, this has no effect at all (re-throwing an exception doesn't change its call stack). | |||||
| } | |||||
| } | |||||
| // 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; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| No newline at end of file | No newline at end of file | ||||
Not Done Inline ActionsI'm guessing we'll just fix all of these in one go once arc lint works again? amckinley: I'm guessing we'll just fix all of these in one go once `arc lint` works again? | |||||
Done Inline ActionsYeah, arc lint will probably have a lot of improvements to make once it can run again. epriestley: Yeah, `arc lint` will probably have a lot of improvements to make once it can run again. | |||||
Why put this in a try {} block at all if we're catching Exception and then just throwing again right away? Does this have any side effects aside from just making the top level of the call stack consistent?