Increase the power of bin/config
				
					
				
			Summary: Fixes T2254. Make the CLI for config more powerful: - Add validation for `set`. - Add `get`. - Add `list`. - Add `delete`. The `get` command produces fairly verbose JSON to support flags like `--all`, or `--source database` later. The other commands are straightforward. Test Plan: Tested `config set`: $ ./bin/config set Usage Exception: Specify a configuration key and a value to set it to. $ ./bin/config set x Usage Exception: Specify a value to set the key 'x' to. $ ./bin/config set phabricator.base-uri Usage Exception: Specify a value to set the key 'phabricator.base-uri' to. $ ./bin/config set phabricator.base-uri x Usage Exception: Config option 'phabricator.base-uri' is invalid. The URI must start with 'http://' or 'https://'. $ ./bin/config set phabricator.base-uri http://x Usage Exception: Config option 'phabricator.base-uri' is invalid. The URI must contain a dot ('.'), like 'http://example.com/', not just a bare name like 'http://example/'. Some web browsers will not set cookies on domains with no TLD. $ ./bin/config set phabricator.base-uri http://x.com Set 'phabricator.base-uri' in local configuration. $ Tested `config get`: $ ./bin/config get pygments.enabled { "config" : [] } $ ./bin/config set pygments.enabled true Set 'pygments.enabled' in local configuration. $ ./bin/config get pygments.enabled { "config" : [ { "key" : "pygments.enabled", "source" : "local", "value" : true } ] } $ Tested `config delete`: $ ./bin/config delete Usage Exception: Specify a configuration key to delete. $ ./bin/config delete x x Usage Exception: Too many arguments: expected one key. $ ./bin/config delete x Usage Exception: No such configuration key 'x'! Use `config list` to list all keys. $ ./bin/config delete pygments.enabled Deleted 'pygments.enabled' from local configuration. $ ./bin/config delete pygments.enabled Usage Exception: Configuration key 'pygments.enabled' is not set in local configuration! $ Tested `config list`: $ ./bin/config list account.editable account.minimum-password-length amazon-ec2.access-key amazon-ec2.secret-key amazon-s3.access-key amazon-s3.endpoint amazon-s3.secret-key amazon-ses.access-key amazon-ses.secret-key aphront.default-application-configuration-class audit.can-author-close-audit auth.email-domains auth.login-message auth.password-auth-enabled auth.require-email-verification auth.sessions.conduit auth.sessions.web auth.sshkeys.enabled cache.enable-deflate celerity.force-disk-reads celerity.minify celerity.resource-hash celerity.resource-path config.hide config.lock config.mask controller.oauth-registration darkconsole.always-on darkconsole.enabled debug.profile-rate debug.stop-on-redirect differential.allow-reopen differential.allow-self-accept differential.always-allow-close differential.anonymous-access differential.custom-remarkup-block-rules differential.custom-remarkup-rules differential.days-fresh differential.days-stale differential.enable-email-accept differential.expose-emails-prudently differential.field-selector differential.generated-paths differential.require-test-plan-field differential.revision-custom-detail-renderer differential.show-host-field differential.show-test-plan-field differential.whitespace-matters disqus.application-id disqus.application-secret disqus.auth-enabled disqus.auth-permanent disqus.registration-enabled disqus.shortname environment.append-paths events.listeners facebook.application-id facebook.application-secret facebook.auth-enabled facebook.auth-permanent facebook.registration-enabled facebook.require-https-auth feed.http-hooks feed.public files.image-mime-types files.viewable-mime-types gcdaemon.ttl.daemon-logs gcdaemon.ttl.differential-parse-cache gcdaemon.ttl.general-cache gcdaemon.ttl.herald-transcripts gcdaemon.ttl.markup-cache gcdaemon.ttl.task-archive github.application-id github.application-secret github.auth-enabled github.auth-permanent github.registration-enabled google.application-id google.application-secret google.auth-enabled google.auth-permanent google.registration-enabled ldap.activedirectory_domain ldap.anonymous-user-name ldap.anonymous-user-password ldap.auth-enabled ldap.base_dn ldap.hostname ldap.port ldap.real_name_attributes ldap.referrals ldap.search-first ldap.search_attribute ldap.start-tls ldap.username-attribute ldap.version load-libraries log.access.format log.access.path maniphest.custom-fields maniphest.custom-task-extensions-class maniphest.default-priority maniphest.enabled metamta.can-send-as-user metamta.default-address metamta.differential.attach-patches metamta.differential.inline-patches metamta.differential.patch-format metamta.differential.reply-handler metamta.differential.reply-handler-domain metamta.differential.subject-prefix metamta.differential.unified-comment-context metamta.diffusion.attach-patches metamta.diffusion.byte-limit metamta.diffusion.inline-patches metamta.diffusion.reply-handler metamta.diffusion.reply-handler-domain metamta.diffusion.subject-prefix metamta.diffusion.time-limit metamta.domain metamta.herald.show-hints metamta.insecure-auth-with-reply-to metamta.macro.reply-handler-domain metamta.macro.subject-prefix metamta.mail-adapter metamta.maniphest.default-public-author metamta.maniphest.public-create-email metamta.maniphest.reply-handler metamta.maniphest.reply-handler-domain metamta.maniphest.subject-prefix metamta.one-mail-per-recipient metamta.package.reply-handler metamta.package.subject-prefix metamta.pholio.reply-handler-domain metamta.pholio.subject-prefix metamta.placeholder-to-recipient metamta.precedence-bulk metamta.public-replies metamta.re-prefix metamta.recipients.show-hints metamta.reply.show-hints metamta.send-immediately metamta.single-reply-handler-prefix metamta.user-address-format metamta.vary-subjects mysql.configuration-provider mysql.host mysql.implementation mysql.pass mysql.user notification.client-uri notification.debug notification.enabled notification.log notification.pidfile notification.server-uri notification.user phabricator.application-id phabricator.application-secret phabricator.auth-enabled phabricator.auth-permanent phabricator.base-uri phabricator.csrf-key phabricator.env phabricator.mail-key phabricator.oauth-uri phabricator.production-uri phabricator.registration-enabled phabricator.serious-business phabricator.setup phabricator.show-beta-applications phabricator.show-error-callout phabricator.show-stack-traces phabricator.timezone phame.skins phd.log-directory phd.pid-directory phd.start-taskmasters phd.trace phd.verbose phid.external-loaders phpmailer.mailer phpmailer.smtp-host phpmailer.smtp-password phpmailer.smtp-port phpmailer.smtp-protocol phpmailer.smtp-user phriction.enabled policy.allow-public pygments.dropdown-choices pygments.enabled recaptcha.enabled recaptcha.private-key recaptcha.public-key remarkup.enable-embedded-youtube repository.default-local-path search.elastic.host search.engine-selector security.alternate-file-domain security.hmac-key security.require-https sendgrid.api-key sendgrid.api-user storage.default-namespace storage.engine-selector storage.local-disk.path storage.mysql-engine.max-size storage.s3.bucket storage.upload-size-limit style.monospace syntax-highlighter.engine syntax.filemap test.value tokenizer.ondemand translation.override translation.provider uri.allowed-protocols $ Reviewers: btrahan, codeblock Reviewed By: btrahan CC: aran Maniphest Tasks: T2254 Differential Revision: https://secure.phabricator.com/D4570
This commit is contained in:
		| @@ -15,7 +15,10 @@ EOSYNOPSIS | |||||||
| $args->parseStandardArguments(); | $args->parseStandardArguments(); | ||||||
|  |  | ||||||
| $workflows = array( | $workflows = array( | ||||||
|  |   new PhabricatorConfigManagementListWorkflow(), | ||||||
|   new PhabricatorConfigManagementSetWorkflow(), |   new PhabricatorConfigManagementSetWorkflow(), | ||||||
|  |   new PhabricatorConfigManagementGetWorkflow(), | ||||||
|  |   new PhabricatorConfigManagementDeleteWorkflow(), | ||||||
|   new PhutilHelpArgumentWorkflow(), |   new PhutilHelpArgumentWorkflow(), | ||||||
| ); | ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -719,8 +719,11 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorConfigJSON' => 'applications/config/json/PhabricatorConfigJSON.php', |     'PhabricatorConfigJSON' => 'applications/config/json/PhabricatorConfigJSON.php', | ||||||
|     'PhabricatorConfigListController' => 'applications/config/controller/PhabricatorConfigListController.php', |     'PhabricatorConfigListController' => 'applications/config/controller/PhabricatorConfigListController.php', | ||||||
|     'PhabricatorConfigLocalSource' => 'infrastructure/env/PhabricatorConfigLocalSource.php', |     'PhabricatorConfigLocalSource' => 'infrastructure/env/PhabricatorConfigLocalSource.php', | ||||||
|     'PhabricatorConfigManagementSetWorkflow' => 'infrastructure/env/management/PhabricatorConfigManagementSetWorkflow.php', |     'PhabricatorConfigManagementDeleteWorkflow' => 'applications/config/management/PhabricatorConfigManagementDeleteWorkflow.php', | ||||||
|     'PhabricatorConfigManagementWorkflow' => 'infrastructure/env/management/PhabricatorConfigManagementWorkflow.php', |     'PhabricatorConfigManagementGetWorkflow' => 'applications/config/management/PhabricatorConfigManagementGetWorkflow.php', | ||||||
|  |     'PhabricatorConfigManagementListWorkflow' => 'applications/config/management/PhabricatorConfigManagementListWorkflow.php', | ||||||
|  |     'PhabricatorConfigManagementSetWorkflow' => 'applications/config/management/PhabricatorConfigManagementSetWorkflow.php', | ||||||
|  |     'PhabricatorConfigManagementWorkflow' => 'applications/config/management/PhabricatorConfigManagementWorkflow.php', | ||||||
|     'PhabricatorConfigOption' => 'applications/config/option/PhabricatorConfigOption.php', |     'PhabricatorConfigOption' => 'applications/config/option/PhabricatorConfigOption.php', | ||||||
|     'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php', |     'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php', | ||||||
|     'PhabricatorConfigSource' => 'infrastructure/env/PhabricatorConfigSource.php', |     'PhabricatorConfigSource' => 'infrastructure/env/PhabricatorConfigSource.php', | ||||||
| @@ -2117,6 +2120,9 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorConfigIssueViewController' => 'PhabricatorConfigController', |     'PhabricatorConfigIssueViewController' => 'PhabricatorConfigController', | ||||||
|     'PhabricatorConfigListController' => 'PhabricatorConfigController', |     'PhabricatorConfigListController' => 'PhabricatorConfigController', | ||||||
|     'PhabricatorConfigLocalSource' => 'PhabricatorConfigProxySource', |     'PhabricatorConfigLocalSource' => 'PhabricatorConfigProxySource', | ||||||
|  |     'PhabricatorConfigManagementDeleteWorkflow' => 'PhabricatorConfigManagementWorkflow', | ||||||
|  |     'PhabricatorConfigManagementGetWorkflow' => 'PhabricatorConfigManagementWorkflow', | ||||||
|  |     'PhabricatorConfigManagementListWorkflow' => 'PhabricatorConfigManagementWorkflow', | ||||||
|     'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow', |     'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow', | ||||||
|     'PhabricatorConfigManagementWorkflow' => 'PhutilArgumentWorkflow', |     'PhabricatorConfigManagementWorkflow' => 'PhutilArgumentWorkflow', | ||||||
|     'PhabricatorConfigOption' => |     'PhabricatorConfigOption' => | ||||||
|   | |||||||
| @@ -0,0 +1,56 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class PhabricatorConfigManagementDeleteWorkflow | ||||||
|  |   extends PhabricatorConfigManagementWorkflow { | ||||||
|  |  | ||||||
|  |   protected function didConstruct() { | ||||||
|  |     $this | ||||||
|  |       ->setName('delete') | ||||||
|  |       ->setExamples('**delete** __key__') | ||||||
|  |       ->setSynopsis('Delete a local configuration value.') | ||||||
|  |       ->setArguments( | ||||||
|  |         array( | ||||||
|  |           array( | ||||||
|  |             'name'      => 'args', | ||||||
|  |             'wildcard'  => true, | ||||||
|  |           ), | ||||||
|  |         )); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function execute(PhutilArgumentParser $args) { | ||||||
|  |     $console = PhutilConsole::getConsole(); | ||||||
|  |  | ||||||
|  |     $argv = $args->getArg('args'); | ||||||
|  |     if (count($argv) == 0) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "Specify a configuration key to delete."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $key = $argv[0]; | ||||||
|  |  | ||||||
|  |     if (count($argv) > 1) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "Too many arguments: expected one key."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $options = PhabricatorApplicationConfigOptions::loadAllOptions(); | ||||||
|  |     if (empty($options[$key])) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "No such configuration key '{$key}'! Use `config list` to list all ". | ||||||
|  |         "keys."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $config = new PhabricatorConfigLocalSource(); | ||||||
|  |     $values = $config->getKeys(array($key)); | ||||||
|  |     if (!$values) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "Configuration key '{$key}' is not set in local configuration!"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $config->deleteKeys(array($key)); | ||||||
|  |  | ||||||
|  |     $console->writeOut( | ||||||
|  |       pht("Deleted '%s' from local configuration.", $key)."\n"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,62 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class PhabricatorConfigManagementGetWorkflow | ||||||
|  |   extends PhabricatorConfigManagementWorkflow { | ||||||
|  |  | ||||||
|  |   protected function didConstruct() { | ||||||
|  |     $this | ||||||
|  |       ->setName('get') | ||||||
|  |       ->setExamples('**get** __key__') | ||||||
|  |       ->setSynopsis('Get a local configuration value.') | ||||||
|  |       ->setArguments( | ||||||
|  |         array( | ||||||
|  |           array( | ||||||
|  |             'name'      => 'args', | ||||||
|  |             'wildcard'  => true, | ||||||
|  |           ), | ||||||
|  |         )); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function execute(PhutilArgumentParser $args) { | ||||||
|  |     $console = PhutilConsole::getConsole(); | ||||||
|  |  | ||||||
|  |     $argv = $args->getArg('args'); | ||||||
|  |     if (count($argv) == 0) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "Specify a configuration key to get."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $key = $argv[0]; | ||||||
|  |  | ||||||
|  |     if (count($argv) > 1) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "Too many arguments: expected one key."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $options = PhabricatorApplicationConfigOptions::loadAllOptions(); | ||||||
|  |     if (empty($options[$key])) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "No such configuration key '{$key}'! Use `config list` to list all ". | ||||||
|  |         "keys."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $config = new PhabricatorConfigLocalSource(); | ||||||
|  |     $values = $config->getKeys(array($key)); | ||||||
|  |  | ||||||
|  |     $result = array(); | ||||||
|  |     foreach ($values as $key => $value) { | ||||||
|  |       $result[] = array( | ||||||
|  |         'key' => $key, | ||||||
|  |         'source' => 'local', | ||||||
|  |         'value' => $value, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |     $result = array( | ||||||
|  |       'config' => $result, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     $json = new PhutilJSON(); | ||||||
|  |     $console->writeOut($json->encodeFormatted($result)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class PhabricatorConfigManagementListWorkflow | ||||||
|  |   extends PhabricatorConfigManagementWorkflow { | ||||||
|  |  | ||||||
|  |   protected function didConstruct() { | ||||||
|  |     $this | ||||||
|  |       ->setName('list') | ||||||
|  |       ->setExamples('**list**') | ||||||
|  |       ->setSynopsis('List all configuration keys.'); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function execute(PhutilArgumentParser $args) { | ||||||
|  |     $options = PhabricatorApplicationConfigOptions::loadAllOptions(); | ||||||
|  |     ksort($options); | ||||||
|  |  | ||||||
|  |     $console = PhutilConsole::getConsole(); | ||||||
|  |     foreach ($options as $option) { | ||||||
|  |       $console->writeOut($option->getKey()."\n"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,99 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class PhabricatorConfigManagementSetWorkflow | ||||||
|  |   extends PhabricatorConfigManagementWorkflow { | ||||||
|  |  | ||||||
|  |   protected function didConstruct() { | ||||||
|  |     $this | ||||||
|  |       ->setName('set') | ||||||
|  |       ->setExamples('**set** __key__ __value__') | ||||||
|  |       ->setSynopsis('Set a local configuration value.') | ||||||
|  |       ->setArguments( | ||||||
|  |         array( | ||||||
|  |           array( | ||||||
|  |             'name'      => 'args', | ||||||
|  |             'wildcard'  => true, | ||||||
|  |           ), | ||||||
|  |         )); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function execute(PhutilArgumentParser $args) { | ||||||
|  |     $console = PhutilConsole::getConsole(); | ||||||
|  |  | ||||||
|  |     $argv = $args->getArg('args'); | ||||||
|  |     if (count($argv) == 0) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "Specify a configuration key and a value to set it to."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $key = $argv[0]; | ||||||
|  |  | ||||||
|  |     if (count($argv) == 1) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "Specify a value to set the key '{$key}' to."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $value = $argv[1]; | ||||||
|  |  | ||||||
|  |     if (count($argv) > 2) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "Too many arguments: expected one key and one value."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $options = PhabricatorApplicationConfigOptions::loadAllOptions(); | ||||||
|  |     if (empty($options[$key])) { | ||||||
|  |       throw new PhutilArgumentUsageException( | ||||||
|  |         "No such configuration key '{$key}'! Use `config list` to list all ". | ||||||
|  |         "keys."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $option = $options[$key]; | ||||||
|  |  | ||||||
|  |     $type = $option->getType(); | ||||||
|  |     switch ($type) { | ||||||
|  |       case 'string': | ||||||
|  |       case 'class': | ||||||
|  |         $value = (string)$value; | ||||||
|  |         break; | ||||||
|  |       case 'int': | ||||||
|  |         if (!ctype_digit($value)) { | ||||||
|  |           throw new PhutilArgumentUsageException( | ||||||
|  |             "Config key '{$key}' is of type '{$type}'. Specify an integer."); | ||||||
|  |         } | ||||||
|  |         $value = (int)$value; | ||||||
|  |         break; | ||||||
|  |       case 'bool': | ||||||
|  |         if ($value == 'true') { | ||||||
|  |           $value = true; | ||||||
|  |         } else if ($value == 'false') { | ||||||
|  |           $value = false; | ||||||
|  |         } else { | ||||||
|  |           throw new PhutilArgumentUsageException( | ||||||
|  |             "Config key '{$key}' is of type '{$type}'. ". | ||||||
|  |             "Specify 'true' or 'false'."); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         $value = json_decode($value, true); | ||||||
|  |         if (!is_array($value)) { | ||||||
|  |           throw new PhutilArgumentUsageException( | ||||||
|  |             "Config key '{$key}' is of type '{$type}'. Specify it in JSON."); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     try { | ||||||
|  |       $option->getGroup()->validateOption($option, $value); | ||||||
|  |     } catch (PhabricatorConfigValidationException $validation) { | ||||||
|  |       // Convert this into a usage exception so we don't dump a stack trace. | ||||||
|  |       throw new PhutilArgumentUsageException($validation->getMessage()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $config = new PhabricatorConfigLocalSource(); | ||||||
|  |     $config->setKeys(array($key => $value)); | ||||||
|  |  | ||||||
|  |     $console->writeOut( | ||||||
|  |       pht("Set '%s' in local configuration.", $key)."\n"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -38,7 +38,7 @@ abstract class PhabricatorConfigProxySource | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function deleteKeys(array $keys) { |   public function deleteKeys(array $keys) { | ||||||
|     $this->getSource()->deleteKeys(); |     $this->getSource()->deleteKeys($keys); | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,50 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| final class PhabricatorConfigManagementSetWorkflow |  | ||||||
|   extends PhabricatorConfigManagementWorkflow { |  | ||||||
|  |  | ||||||
|   protected function didConstruct() { |  | ||||||
|     $this |  | ||||||
|       ->setName('set') |  | ||||||
|       ->setExamples('**set** __key__ __value__') |  | ||||||
|       ->setSynopsis('Set a local configuration value.') |  | ||||||
|       ->setArguments( |  | ||||||
|         array( |  | ||||||
|           array( |  | ||||||
|             'name'      => 'args', |  | ||||||
|             'wildcard'  => true, |  | ||||||
|           ), |  | ||||||
|         )); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public function execute(PhutilArgumentParser $args) { |  | ||||||
|     $console = PhutilConsole::getConsole(); |  | ||||||
|  |  | ||||||
|     $argv = $args->getArg('args'); |  | ||||||
|     if (count($argv) == 0) { |  | ||||||
|       throw new PhutilArgumentUsageException( |  | ||||||
|         "Specify a configuration key and a value to set it to."); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     $key = $argv[0]; |  | ||||||
|  |  | ||||||
|     if (count($argv) == 1) { |  | ||||||
|       throw new PhutilArgumentUsageException( |  | ||||||
|         "Specify a value to set the key '{$key}' to."); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     $value = $argv[1]; |  | ||||||
|  |  | ||||||
|     if (count($argv) > 2) { |  | ||||||
|       throw new PhutilArgumentUsageException( |  | ||||||
|         "Too many arguments: expected one key and one value."); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     $config = new PhabricatorConfigLocalSource(); |  | ||||||
|     $config->setKeys(array($key => $value)); |  | ||||||
|  |  | ||||||
|     $console->writeOut( |  | ||||||
|       pht("Set '%s' to '%s' in local configuration.", $key, $value)."\n"); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley