Page MenuHomePhorge

No OneTemporary

diff --git a/src/toolset/ArcanistPrompt.php b/src/toolset/ArcanistPrompt.php
index 24523596..caff32c6 100644
--- a/src/toolset/ArcanistPrompt.php
+++ b/src/toolset/ArcanistPrompt.php
@@ -1,312 +1,320 @@
<?php
final class ArcanistPrompt
extends Phobject {
private $key;
private $workflow;
private $description;
private $query;
public function setKey($key) {
$this->key = $key;
return $this;
}
public function getKey() {
return $this->key;
}
public function setWorkflow(ArcanistWorkflow $workflow) {
$this->workflow = $workflow;
return $this;
}
public function getWorkflow() {
return $this->workflow;
}
public function setDescription($description) {
$this->description = $description;
return $this;
}
public function getDescription() {
return $this->description;
}
public function setQuery($query) {
$this->query = $query;
return $this;
}
public function getQuery() {
return $this->query;
}
public function execute() {
$workflow = $this->getWorkflow();
if ($workflow) {
$workflow_ok = $workflow->hasPrompt($this->getKey());
} else {
$workflow_ok = false;
}
if (!$workflow_ok) {
throw new Exception(
pht(
'Prompt ("%s") is executing, but it is not properly bound to the '.
'invoking workflow. You may have called "newPrompt()" to execute a '.
'prompt instead of "getPrompt()". Use "newPrompt()" when defining '.
'prompts and "getPrompt()" when executing them.',
$this->getKey()));
}
$query = $this->getQuery();
if (!strlen($query)) {
throw new Exception(
pht(
'Prompt ("%s") has no query text!',
$this->getKey()));
}
$options = '[y/N/?]';
$default = 'n';
$saved_response = $this->getSavedResponse();
try {
phutil_console_require_tty();
} catch (PhutilConsoleStdinNotInteractiveException $ex) {
// TOOLSETS: Clean this up to provide more details to the user about how
// they can configure prompts to be answered.
// Throw after echoing the prompt so the user has some idea what happened.
echo $query."\n";
throw $ex;
}
- // NOTE: We're making stdin nonblocking so that we can respond to signals
- // immediately. If we don't, and you ^C during a prompt, the program does
- // not handle the signal until fgets() returns.
-
$stdin = fopen('php://stdin', 'r');
if (!$stdin) {
throw new Exception(pht('Failed to open stdin for reading.'));
}
- $ok = stream_set_blocking($stdin, false);
- if (!$ok) {
- throw new Exception(pht('Unable to set stdin nonblocking.'));
+ // NOTE: We're making stdin nonblocking so that we can respond to signals
+ // immediately. If we don't, and you ^C during a prompt, the program does
+ // not handle the signal until fgets() returns.
+
+ // On Windows, we skip this because stdin can not be made nonblocking.
+
+ if (!phutil_is_windows()) {
+ $ok = stream_set_blocking($stdin, false);
+ if (!$ok) {
+ throw new Exception(pht('Unable to set stdin nonblocking.'));
+ }
}
echo "\n";
$result = null;
$is_saved = false;
while (true) {
if ($saved_response !== null) {
$is_saved = true;
$response = $saved_response;
$saved_response = null;
} else {
echo tsprintf(
'**<bg:cyan> %s </bg>** %s %s ',
'>>>',
$query,
$options);
- while (true) {
- $is_saved = false;
+ $is_saved = false;
- $read = array($stdin);
- $write = array();
- $except = array();
+ if (phutil_is_windows()) {
+ $response = fgets($stdin);
+ } else {
+ while (true) {
+ $read = array($stdin);
+ $write = array();
+ $except = array();
+
+ $ok = @stream_select($read, $write, $except, 1);
+ if ($ok === false) {
+ // NOTE: We may be interrupted by a system call, particularly if
+ // the window is resized while a prompt is shown and the terminal
+ // sends SIGWINCH.
+
+ // If we are, just continue below and try to read from stdin. If
+ // we were interrupted, we should read nothing and continue
+ // normally. If the pipe is broken, the read should fail.
+ }
- $ok = @stream_select($read, $write, $except, 1);
- if ($ok === false) {
- // NOTE: We may be interrupted by a system call, particularly if
- // the window is resized while a prompt is shown and the terminal
- // sends SIGWINCH.
+ $response = '';
+ while (true) {
+ $bytes = fread($stdin, 8192);
+ if ($bytes === false) {
+ throw new Exception(
+ pht('fread() from stdin failed with an error.'));
+ }
- // If we are, just continue below and try to read from stdin. If
- // we were interrupted, we should read nothing and continue
- // normally. If the pipe is broken, the read should fail.
- }
+ if (!strlen($bytes)) {
+ break;
+ }
- $response = '';
- while (true) {
- $bytes = fread($stdin, 8192);
- if ($bytes === false) {
- throw new Exception(
- pht('fread() from stdin failed with an error.'));
+ $response .= $bytes;
}
- if (!strlen($bytes)) {
- break;
+ if (!strlen($response)) {
+ continue;
}
- $response .= $bytes;
- }
-
- if (!strlen($response)) {
- continue;
+ break;
}
-
- break;
}
$response = trim($response);
if (!strlen($response)) {
$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') {
$result = true;
break;
}
if (phutil_utf8_strtolower($response) == 'n') {
$result = false;
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) {
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);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 19:51 (1 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1128170
Default Alt Text
(9 KB)

Event Timeline