Page MenuHomePhabricator

D15751.id37960.diff
No OneTemporary

D15751.id37960.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -192,6 +192,7 @@
'PhutilExcessiveServiceCallsDaemon' => 'daemon/torture/PhutilExcessiveServiceCallsDaemon.php',
'PhutilExecChannel' => 'channel/PhutilExecChannel.php',
'PhutilExecPassthru' => 'future/exec/PhutilExecPassthru.php',
+ 'PhutilExecutableFuture' => 'future/exec/PhutilExecutableFuture.php',
'PhutilExecutionEnvironment' => 'utils/PhutilExecutionEnvironment.php',
'PhutilExtensionsTestCase' => 'moduleutils/__tests__/PhutilExtensionsTestCase.php',
'PhutilFacebookAuthAdapter' => 'auth/PhutilFacebookAuthAdapter.php',
@@ -576,7 +577,7 @@
'ConduitClientException' => 'Exception',
'ConduitClientTestCase' => 'PhutilTestCase',
'ConduitFuture' => 'FutureProxy',
- 'ExecFuture' => 'Future',
+ 'ExecFuture' => 'PhutilExecutableFuture',
'ExecFutureTestCase' => 'PhutilTestCase',
'ExecPassthruTestCase' => 'PhutilTestCase',
'FileFinder' => 'Phobject',
@@ -736,7 +737,8 @@
'PhutilExampleBufferedIterator' => 'PhutilBufferedIterator',
'PhutilExcessiveServiceCallsDaemon' => 'PhutilTortureTestDaemon',
'PhutilExecChannel' => 'PhutilChannel',
- 'PhutilExecPassthru' => 'Phobject',
+ 'PhutilExecPassthru' => 'PhutilExecutableFuture',
+ 'PhutilExecutableFuture' => 'Future',
'PhutilExecutionEnvironment' => 'Phobject',
'PhutilExtensionsTestCase' => 'PhutilTestCase',
'PhutilFacebookAuthAdapter' => 'PhutilOAuthAuthAdapter',
diff --git a/src/future/exec/ExecFuture.php b/src/future/exec/ExecFuture.php
--- a/src/future/exec/ExecFuture.php
+++ b/src/future/exec/ExecFuture.php
@@ -19,7 +19,7 @@
* @task interact Interacting With Commands
* @task internal Internals
*/
-final class ExecFuture extends Future {
+final class ExecFuture extends PhutilExecutableFuture {
private $pipes = array();
private $proc = null;
@@ -35,8 +35,6 @@
private $stdoutPos = 0;
private $stderrPos = 0;
private $command = null;
- private $env = null;
- private $cwd;
private $readBufferSize;
private $stdoutSizeLimit = PHP_INT_MAX;
@@ -181,59 +179,6 @@
/**
- * Set the current working directory to use when executing the command.
- *
- * @param string Directory to set as CWD before executing the command.
- * @return this
- * @task config
- */
- public function setCWD($cwd) {
- $this->cwd = $cwd;
- return $this;
- }
-
-
- /**
- * Set the environment variables to use when executing the command.
- *
- * @param array Environment variables to use when executing the command.
- * @return this
- * @task config
- */
- public function setEnv($env, $wipe_process_env = false) {
- if ($wipe_process_env) {
- $this->env = $env;
- } else {
- $this->env = $env + $_ENV;
- }
- return $this;
- }
-
-
- /**
- * Set the value of a specific environmental variable for this command.
- *
- * @param string Environmental variable name.
- * @param string|null New value, or null to remove this variable.
- * @return this
- * @task config
- */
- public function updateEnv($key, $value) {
- if (!is_array($this->env)) {
- $this->env = $_ENV;
- }
-
- if ($value === null) {
- unset($this->env[$key]);
- } else {
- $this->env[$key] = $value;
- }
-
- return $this;
- }
-
-
- /**
* Set whether to use non-blocking streams on Windows.
*
* @param bool Whether to use non-blocking streams.
@@ -659,26 +604,14 @@
}
}
-
- // NOTE: Convert all the environmental variables we're going to pass
- // into strings before we install PhutilErrorTrap. If something in here
- // is really an object which is going to throw when we try to turn it
- // into a string, we want the exception to escape here -- not after we
- // start trapping errors.
- $env = $this->env;
- if ($env !== null) {
- foreach ($env as $key => $value) {
- $env[$key] = (string)$value;
- }
- }
-
- // Same for the working directory.
- if ($this->cwd === null) {
- $cwd = null;
+ if ($this->hasEnv()) {
+ $env = $this->getEnv();
} else {
- $cwd = (string)$this->cwd;
+ $env = null;
}
+ $cwd = $this->getCWD();
+
// NOTE: See note above about Phage.
if (class_exists('PhutilErrorTrap')) {
$trap = new PhutilErrorTrap();
diff --git a/src/future/exec/PhutilExecPassthru.php b/src/future/exec/PhutilExecPassthru.php
--- a/src/future/exec/PhutilExecPassthru.php
+++ b/src/future/exec/PhutilExecPassthru.php
@@ -17,13 +17,12 @@
* @{method:setCWD}, and set the environment with @{method:setEnv}.
*
* @task command Executing Passthru Commands
- * @task config Configuring Passthru Commands
*/
-final class PhutilExecPassthru extends Phobject {
+final class PhutilExecPassthru extends PhutilExecutableFuture {
+
private $command;
- private $env;
- private $cwd;
+ private $passthruResult;
/* -( Executing Passthru Commands )---------------------------------------- */
@@ -72,8 +71,13 @@
$unmasked_command = $command;
}
- $env = $this->env;
- $cwd = $this->cwd;
+ if ($this->hasEnv()) {
+ $env = $this->getEnv();
+ } else {
+ $env = null;
+ }
+
+ $cwd = $this->getCWD();
$options = array();
if (phutil_is_windows()) {
@@ -115,50 +119,23 @@
}
-/* -( Configuring Passthru Commands )-------------------------------------- */
+/* -( Future )------------------------------------------------------------- */
- /**
- * Set environmental variables for the subprocess.
- *
- * By default, variables are added to the environment of this process. You
- * can optionally wipe the environment and pass only the specified values.
- *
- * // Env will have "X" and current env ("PATH", etc.)
- * $exec->setEnv(array('X' => 'y'));
- *
- * // Env will have ONLY "X".
- * $exec->setEnv(array('X' => 'y'), $wipe_process_env = true);
- *
- * @param dict Dictionary of environmental variables.
- * @param bool Optionally, pass true to wipe the existing environment clean.
- * @return this
- *
- * @task config
- */
- public function setEnv(array $env, $wipe_process_env = false) {
- if ($wipe_process_env) {
- $this->env = $env;
- } else {
- $this->env = $env + $_ENV;
+ public function isReady() {
+ // This isn't really a future because it executes synchronously and has
+ // full control of the console. We're just implementing the interfaces to
+ // make it easier to share code with ExecFuture.
+
+ if ($this->passthruResult === null) {
+ $this->passthruResult = $this->execute();
}
- return $this->env;
- }
+ return true;
+ }
- /**
- * Set the current working directory for the subprocess (that is, set where
- * the subprocess will execute). If not set, the default value is the parent's
- * current working directory.
- *
- * @param string Directory to execute the subprocess in.
- * @return this
- *
- * @task config
- */
- public function setCWD($cwd) {
- $this->cwd = $cwd;
- return $this;
+ protected function getResult() {
+ return $this->passthruResult;
}
}
diff --git a/src/future/exec/PhutilExecutableFuture.php b/src/future/exec/PhutilExecutableFuture.php
new file mode 100644
--- /dev/null
+++ b/src/future/exec/PhutilExecutableFuture.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @task config Configuring the Command
+ */
+abstract class PhutilExecutableFuture extends Future {
+
+
+ private $env;
+ private $cwd;
+
+
+ /**
+ * Set environmental variables for the command.
+ *
+ * By default, variables are added to the environment of this process. You
+ * can optionally wipe the environment and pass only the specified values.
+ *
+ * // Env will have "X" and current env ("PATH", etc.)
+ * $exec->setEnv(array('X' => 'y'));
+ *
+ * // Env will have ONLY "X".
+ * $exec->setEnv(array('X' => 'y'), $wipe_process_env = true);
+ *
+ * @param map<string, string> Dictionary of environmental variables.
+ * @param bool Optionally, pass `true` to replace the existing environment.
+ * @return this
+ *
+ * @task config
+ */
+ final public function setEnv(array $env, $wipe_process_env = false) {
+ // Force values to strings here. The underlying PHP commands get upset if
+ // they are handed non-string values as environmental variables.
+ foreach ($env as $key => $value) {
+ $env[$key] = (string)$value;
+ }
+
+ if (!$wipe_process_env) {
+ $env = $env + $this->getEnv();
+ }
+
+ $this->env = $env;
+
+ return $this;
+ }
+
+
+ /**
+ * Set the value of a specific environmental variable for this command.
+ *
+ * @param string Environmental variable name.
+ * @param string|null New value, or null to remove this variable.
+ * @return this
+ * @task config
+ */
+ final public function updateEnv($key, $value) {
+ $env = $this->getEnv();
+
+ if ($value === null) {
+ unset($env[$key]);
+ } else {
+ $env[$key] = (string)$value;
+ }
+
+ $this->env = $env;
+
+ return $this;
+ }
+
+
+ /**
+ * Returns `true` if this command has a configured environment.
+ *
+ * @return bool True if this command has an environment.
+ * @task config
+ */
+ final public function hasEnv() {
+ return ($this->env !== null);
+ }
+
+
+ /**
+ * Get the configured environment.
+ *
+ * @return map<string, string> Effective environment for this command.
+ * @task config
+ */
+ final public function getEnv() {
+ if (!$this->hasEnv()) {
+ $this->setEnv($_ENV, $wipe_process_env = true);
+ }
+
+ return $this->env;
+ }
+
+
+ /**
+ * Set the current working directory for the subprocess (that is, set where
+ * the subprocess will execute). If not set, the default value is the parent's
+ * current working directory.
+ *
+ * @param string Directory to execute the subprocess in.
+ * @return this
+ * @task config
+ */
+ final public function setCWD($cwd) {
+ $this->cwd = (string)$cwd;
+ return $this;
+ }
+
+
+ /**
+ * Get the command's current working directory.
+ *
+ * @return string Working directory.
+ * @task config
+ */
+ final public function getCWD() {
+ return $this->cwd;
+ }
+
+}
diff --git a/src/phage/bootloader/PhagePHPAgentBootloader.php b/src/phage/bootloader/PhagePHPAgentBootloader.php
--- a/src/phage/bootloader/PhagePHPAgentBootloader.php
+++ b/src/phage/bootloader/PhagePHPAgentBootloader.php
@@ -47,6 +47,7 @@
'xsprintf/PhutilCommandString.php',
'future/Future.php',
'future/FutureIterator.php',
+ 'future/exec/PhutilExecutableFuture.php',
'future/exec/ExecFuture.php',
'future/exec/CommandException.php',
'channel/PhutilChannel.php',

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 5, 9:40 PM (12 h, 7 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6718477
Default Alt Text
D15751.id37960.diff (10 KB)

Event Timeline