Changeset View
Changeset View
Standalone View
Standalone View
src/toolset/ArcanistPrompt.php
| Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | public function execute() { | ||||
| $query = $this->getQuery(); | $query = $this->getQuery(); | ||||
| if (!strlen($query)) { | if (!strlen($query)) { | ||||
| throw new Exception( | throw new Exception( | ||||
| pht( | pht( | ||||
| 'Prompt ("%s") has no query text!', | 'Prompt ("%s") has no query text!', | ||||
| $this->getKey())); | $this->getKey())); | ||||
| } | } | ||||
| $options = '[y/N]'; | $options = '[y/N/?]'; | ||||
| $default = 'N'; | $default = 'n'; | ||||
| $saved_response = $this->getSavedResponse(); | |||||
| try { | try { | ||||
| phutil_console_require_tty(); | phutil_console_require_tty(); | ||||
| } catch (PhutilConsoleStdinNotInteractiveException $ex) { | } catch (PhutilConsoleStdinNotInteractiveException $ex) { | ||||
| // TOOLSETS: Clean this up to provide more details to the user about how | // TOOLSETS: Clean this up to provide more details to the user about how | ||||
| // they can configure prompts to be answered. | // they can configure prompts to be answered. | ||||
| // Throw after echoing the prompt so the user has some idea what happened. | // Throw after echoing the prompt so the user has some idea what happened. | ||||
| Show All 13 Lines | public function execute() { | ||||
| $ok = stream_set_blocking($stdin, false); | $ok = stream_set_blocking($stdin, false); | ||||
| if (!$ok) { | if (!$ok) { | ||||
| throw new Exception(pht('Unable to set stdin nonblocking.')); | throw new Exception(pht('Unable to set stdin nonblocking.')); | ||||
| } | } | ||||
| echo "\n"; | echo "\n"; | ||||
| $result = null; | $result = null; | ||||
| $is_saved = false; | |||||
| while (true) { | while (true) { | ||||
| if ($saved_response !== null) { | |||||
| $is_saved = true; | |||||
| $response = $saved_response; | |||||
| $saved_response = null; | |||||
| } else { | |||||
| echo tsprintf( | echo tsprintf( | ||||
| '**<bg:cyan> %s </bg>** %s %s ', | '**<bg:cyan> %s </bg>** %s %s ', | ||||
| '>>>', | '>>>', | ||||
| $query, | $query, | ||||
| $options); | $options); | ||||
| while (true) { | while (true) { | ||||
| $is_saved = false; | |||||
| $read = array($stdin); | $read = array($stdin); | ||||
| $write = array(); | $write = array(); | ||||
| $except = array(); | $except = array(); | ||||
| $ok = @stream_select($read, $write, $except, 1); | $ok = @stream_select($read, $write, $except, 1); | ||||
| if ($ok === false) { | if ($ok === false) { | ||||
| // NOTE: We may be interrupted by a system call, particularly if | // NOTE: We may be interrupted by a system call, particularly if | ||||
| // the window is resized while a prompt is shown and the terminal | // the window is resized while a prompt is shown and the terminal | ||||
| // sends SIGWINCH. | // sends SIGWINCH. | ||||
| // If we are, just continue below and try to read from stdin. If | // If we are, just continue below and try to read from stdin. If | ||||
| // we were interrupted, we should read nothing and continue | // we were interrupted, we should read nothing and continue | ||||
| // normally. If the pipe is broken, the read should fail. | // normally. If the pipe is broken, the read should fail. | ||||
| } | } | ||||
| $response = ''; | $response = ''; | ||||
| while (true) { | while (true) { | ||||
| $bytes = fread($stdin, 8192); | $bytes = fread($stdin, 8192); | ||||
| if ($bytes === false) { | if ($bytes === false) { | ||||
| throw new Exception( | throw new Exception( | ||||
| pht('fread() from stdin failed with an error.')); | pht('fread() from stdin failed with an error.')); | ||||
| } | } | ||||
| if (!strlen($bytes)) { | if (!strlen($bytes)) { | ||||
| break; | break; | ||||
| } | } | ||||
| $response .= $bytes; | $response .= $bytes; | ||||
| } | } | ||||
| if (!strlen($response)) { | if (!strlen($response)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| $response = trim($response); | $response = trim($response); | ||||
| if (!strlen($response)) { | if (!strlen($response)) { | ||||
| $response = $default; | $response = $default; | ||||
| } | } | ||||
| } | |||||
| $save_scope = null; | |||||
| if (!$is_saved) { | |||||
| $matches = null; | |||||
| if (preg_match('(^(.*)([!*])\z)', $response, $matches)) { | |||||
| $response = $matches[1]; | |||||
| if ($matches[2] === '*') { | |||||
| $save_scope = ArcanistConfigurationSource::SCOPE_USER; | |||||
| } else { | |||||
| $save_scope = ArcanistConfigurationSource::SCOPE_WORKING_COPY; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (phutil_utf8_strtolower($response) == 'y') { | if (phutil_utf8_strtolower($response) == 'y') { | ||||
| $result = true; | $result = true; | ||||
| break; | break; | ||||
| } | } | ||||
| if (phutil_utf8_strtolower($response) == 'n') { | if (phutil_utf8_strtolower($response) == 'n') { | ||||
| $result = false; | $result = false; | ||||
| break; | break; | ||||
| } | } | ||||
| if (phutil_utf8_strtolower($response) == '?') { | |||||
| echo tsprintf( | |||||
| "\n<bg:green>** %s **</bg> **%s**\n\n", | |||||
| pht('PROMPT'), | |||||
| $this->getKey()); | |||||
| echo tsprintf( | |||||
| "%s\n", | |||||
| $this->getDescription()); | |||||
| echo tsprintf("\n"); | |||||
| echo tsprintf( | |||||
| "%s\n", | |||||
| pht( | |||||
| 'The default response to this prompt is "%s".', | |||||
| $default)); | |||||
| echo tsprintf("\n"); | |||||
| echo tsprintf( | |||||
| "%?\n", | |||||
| pht( | |||||
| 'Use "*" after a response to save it in user configuration.')); | |||||
| echo tsprintf( | |||||
| "%?\n", | |||||
| pht( | |||||
| 'Use "!" after a response to save it in working copy '. | |||||
| 'configuration.')); | |||||
| echo tsprintf( | |||||
| "%?\n", | |||||
| pht( | |||||
| 'Run "arc help prompts" for detailed help on configuring '. | |||||
| 'responses.')); | |||||
| echo tsprintf("\n"); | |||||
| continue; | |||||
| } | |||||
| } | |||||
| if ($save_scope !== null) { | |||||
| $this->saveResponse($save_scope, $response); | |||||
| } | |||||
| if ($is_saved) { | |||||
| echo tsprintf( | |||||
| "<bg:cyan>** %s **</bg> %s **<%s>**\n". | |||||
| "<bg:cyan>** %s **</bg> (%s)\n\n", | |||||
| '>>>', | |||||
| $query, | |||||
| $response, | |||||
| '>>>', | |||||
| pht( | |||||
| 'Using saved response to prompt "%s".', | |||||
| $this->getKey())); | |||||
| } | } | ||||
| if (!$result) { | if (!$result) { | ||||
| throw new ArcanistUserAbortException(); | throw new ArcanistUserAbortException(); | ||||
| } | } | ||||
| } | |||||
| private function getSavedResponse() { | |||||
| $config_key = ArcanistArcConfigurationEngineExtension::KEY_PROMPTS; | |||||
| $workflow = $this->getWorkflow(); | |||||
| $config = $workflow->getConfig($config_key); | |||||
| $prompt_key = $this->getKey(); | |||||
| $prompt_response = null; | |||||
| foreach ($config as $response) { | |||||
| if ($response->getPrompt() === $prompt_key) { | |||||
| $prompt_response = $response; | |||||
| } | |||||
| } | |||||
| if ($prompt_response === null) { | |||||
| return null; | |||||
| } | |||||
| return $prompt_response->getResponse(); | |||||
| } | |||||
| private function saveResponse($scope, $response_value) { | |||||
| $config_key = ArcanistArcConfigurationEngineExtension::KEY_PROMPTS; | |||||
| $workflow = $this->getWorkflow(); | |||||
| echo tsprintf( | |||||
| "<bg:green>** %s **</bg> %s\n", | |||||
| pht('SAVE PROMPT'), | |||||
| pht( | |||||
| 'Saving response "%s" to prompt "%s".', | |||||
| $response_value, | |||||
| $this->getKey())); | |||||
| $source_list = $workflow->getConfigurationSourceList(); | |||||
| $source = $source_list->getWritableSourceFromScope($scope); | |||||
| $response_list = $source_list->getConfigFromScopes( | |||||
| $config_key, | |||||
| array($scope)); | |||||
| foreach ($response_list as $key => $response) { | |||||
| if ($response->getPrompt() === $this->getKey()) { | |||||
| unset($response_list[$key]); | |||||
| } | |||||
| } | |||||
| if ($response_value !== null) { | |||||
| $response_list[] = id(new ArcanistPromptResponse()) | |||||
| ->setPrompt($this->getKey()) | |||||
| ->setResponse($response_value); | |||||
| } | |||||
| $option = $source_list->getConfigOption($config_key); | |||||
| $option->writeValue($source, $response_list); | |||||
| } | } | ||||
| } | } | ||||