Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F5182383
Masterwork From Distant Lands
No One
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Authored By
alexmv
Sep 14 2017, 10:17 PM
2017-09-14 22:17:30 (UTC+0)
Size
5 KB
Referenced Files
None
Subscribers
None
Masterwork From Distant Lands
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 569a906..64490e7 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -48,6 +48,8 @@ phutil_register_library_map(array(
'ConduitClientException' => 'conduit/ConduitClientException.php',
'ConduitClientTestCase' => 'conduit/__tests__/ConduitClientTestCase.php',
'ConduitFuture' => 'conduit/ConduitFuture.php',
+ 'ConsoleConfirmFuture' => 'future/ConsoleConfirmFuture.php',
+ 'ConsolePromptFuture' => 'future/ConsolePromptFuture.php',
'ExecFuture' => 'future/exec/ExecFuture.php',
'ExecFutureTestCase' => 'future/exec/__tests__/ExecFutureTestCase.php',
'ExecPassthruTestCase' => 'future/exec/__tests__/ExecPassthruTestCase.php',
@@ -647,6 +649,8 @@ phutil_register_library_map(array(
'ConduitClientException' => 'Exception',
'ConduitClientTestCase' => 'PhutilTestCase',
'ConduitFuture' => 'FutureProxy',
+ 'ConsoleConfirmFuture' => 'ConsolePromptFuture',
+ 'ConsolePromptFuture' => 'FutureProxy',
'ExecFuture' => 'PhutilExecutableFuture',
'ExecFutureTestCase' => 'PhutilTestCase',
'ExecPassthruTestCase' => 'PhutilTestCase',
diff --git a/src/future/ConsoleConfirmFuture.php b/src/future/ConsoleConfirmFuture.php
new file mode 100644
index 0000000..efb3909
--- /dev/null
+++ b/src/future/ConsoleConfirmFuture.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * Dropbox addition. This class replicates the behavior of
+ * phutil_console_confirm, but as a Future.
+ *
+ * TODO: It differs in that it only prompts once, even if the answer is neither
+ * 'y' nor 'n' nor ''.
+ */
+final class ConsoleConfirmFuture extends ConsolePromptFuture {
+ protected $defaultNo;
+
+ public function __construct($prompt, $default_no = true) {
+ $this->defaultNo = $default_no;
+ $prompt_options = $default_no ? '[y/N]' : '[Y/n]';
+ $prompt .= " $prompt_options";
+ parent::__construct($prompt);
+ }
+
+ protected function didReceiveResult($result) {
+ if ($this->defaultNo) {
+ return ($result == 'y');
+ } else {
+ return ($result != 'n');
+ }
+ }
+}
diff --git a/src/future/ConsolePromptFuture.php b/src/future/ConsolePromptFuture.php
new file mode 100644
index 0000000..ecbb749
--- /dev/null
+++ b/src/future/ConsolePromptFuture.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * Dropbox addition. This class replicates the behavior of
+ * phutil_console_prompt, but as a Future.
+ *
+ * @concrete-extensible
+ */
+class ConsolePromptFuture extends FutureProxy {
+ public function __construct($prompt, $history = '') {
+ $prompt = phutil_console_wrap($prompt.' ', 4);
+
+ try {
+ phutil_console_require_tty();
+ } catch (PhutilConsoleStdinNotInteractiveException $ex) {
+ // Throw after echoing the prompt so the user has some idea what happened.
+ echo $prompt;
+ throw $ex;
+ }
+
+ if (phutil_is_windows()) {
+ throw new Exception('Cannot use prompt as a future on Windows.');
+ } else {
+ // Test if bash is available by seeing if it can run `true`.
+ list($err) = exec_manual('bash -c %s', 'true');
+ if ($err) {
+ throw new Exception('Cannot use prompt as a future without bash.');
+ }
+ }
+
+ // See `terminate`, below, for an explanation of the first `echo`
+ $shell_future = new ExecFuture(
+ 'bash -c %s',
+ csprintf(
+ 'echo $$; '.
+ 'echo -ne "\n\n" >&2; '.
+ 'history -r %s 2>/dev/null; '.
+ 'read -e -p %s; '.
+ 'echo "$REPLY" 2>/dev/null; '.
+ 'history -s "$REPLY" 2>/dev/null; '.
+ 'history -w %s 2>/dev/null',
+ $history,
+ $prompt,
+ $history));
+
+ // `read` writes its prompt to STDERR, and reads from STDIN; hook those up
+ // to what we believe them to be for us, while consuming STDOUT so we can
+ // determine the output.
+ $shell_future->setDescriptors(array(
+ 0 => array('file', 'php://stdin', 'r'),
+ 1 => array('pipe', 'w'),
+ 2 => array('file', 'php://stderr', 'w'),
+ ));
+
+ $this->setProxiedFuture($shell_future);
+ }
+
+ protected function didReceiveResult($result) {
+ list($err, $stdout) = $result;
+ list($pid, $stdout) = explode("\n", $stdout);
+ return $stdout;
+ }
+
+ final public function terminate() {
+ // The first output of the command is the PID of the bash with the readline,
+ // which is called from a `/bin/sh` set up by PHP. Terminating the outer
+ // /bin/sh leaves the inner `bash` still running, and still attached to
+ // `/dev/tty` -- unless we kill that inner process it thus consumes the
+ // first character after PHP exits.
+ list($stdout) = $this->getProxiedFuture()->read();
+ list($pid) = explode("\n", $stdout);
+ $this->setProxiedFuture(new ImmediateFuture(null));
+ // SIGHUP, but PCNTL isn't always available so we can't use that constant;
+ // hardcode the signal number.
+ posix_kill($pid, 1);
+ // Make sure we reset terminal echo, etc.
+ exec('stty sane');
+ }
+
+ public function __destruct() {
+ $this->terminate();
+ }
+}
File Metadata
Details
Attached
Mime Type
text/plain; charset=utf-8
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
780636
Default Alt Text
Masterwork From Distant Lands (5 KB)
Attached To
Mode
P2074 Masterwork From Distant Lands
Attached
Detach File
Event Timeline
Log In to Comment