Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2680362
PhutilExecutableFuture.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
5 KB
Referenced Files
None
Subscribers
None
PhutilExecutableFuture.php
View Options
<?php
/**
* @task config Configuring the Command
*/
abstract
class
PhutilExecutableFuture
extends
Future
{
private
$command
;
private
$env
;
private
$cwd
;
private
$resolveOnError
=
true
;
final
public
function
__construct
(
$pattern
/* , ... */
)
{
$args
=
func_get_args
(
)
;
if
(
$pattern
instanceof
PhutilCommandString
)
{
if
(
count
(
$args
)
!==
1
)
{
throw
new
Exception
(
pht
(
'Command (of class "%s") was constructed with a '
.
'"PhutilCommandString", but also passed arguments. '
.
'When using a prebuilt command, you must not pass '
.
'arguments.'
,
get_class
(
$this
)
)
)
;
}
$this
->
command
=
$pattern
;
}
else
{
$this
->
command
=
call_user_func_array
(
'csprintf'
,
$args
)
;
}
$this
->
didConstruct
(
)
;
}
protected
function
didConstruct
(
)
{
return
;
}
final
public
function
setResolveOnError
(
$resolve_on_error
)
{
$this
->
resolveOnError
=
$resolve_on_error
;
return
$this
;
}
final
public
function
getResolveOnError
(
)
{
return
$this
->
resolveOnError
;
}
final
public
function
getCommand
(
)
{
return
$this
->
command
;
}
/**
* 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> $env Dictionary of environmental variables.
* @param bool $wipe_process_env (optional) 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 $key Environmental variable name.
* @param string|null $value 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
(
)
)
{
$default_env
=
$_ENV
;
// If `variables_order` does not include "E", the $_ENV superglobal
// does not build and there's no apparent reasonable way for us to
// rebuild it (we could perhaps parse the output of `export`).
// For now, explicitly populate variables which we rely on and which
// we know may exist. After T12071, we should be able to rely on
// $_ENV and no longer need to do this.
$known_keys
=
array
(
'PHABRICATOR_ENV'
,
'PHABRICATOR_INSTANCE'
,
)
;
foreach
(
$known_keys
as
$known_key
)
{
$value
=
getenv
(
$known_key
)
;
if
(
strlen
(
$value
)
)
{
$default_env
[
$known_key
]
=
$value
;
}
}
$this
->
setEnv
(
$default_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 $cwd Directory to execute the subprocess in.
* @return $this
* @task config
*/
final
public
function
setCWD
(
$cwd
)
{
$cwd
=
phutil_string_cast
(
$cwd
)
;
try
{
Filesystem
::
assertExists
(
$cwd
)
;
}
catch
(
FilesystemException
$ex
)
{
throw
new
PhutilProxyException
(
pht
(
'Unable to run a command in directory "%s".'
,
$cwd
)
,
$ex
)
;
}
if
(
!
is_dir
(
$cwd
)
)
{
throw
new
Exception
(
pht
(
'Preparing to run a command in directory "%s", but that path is '
.
'not a directory.'
,
$cwd
)
)
;
}
// Although you don't technically need read permission to "chdir()" into
// a directory, it is almost certainly a mistake to execute a subprocess
// in a CWD we can't read. Refuse to do this. If callers have some
// exceptionally clever scheme up their sleeves they can always have the
// subprocess "cd" or "chdir()" explicitly.
if
(
!
is_readable
(
$cwd
)
)
{
throw
new
Exception
(
pht
(
'Preparing to run a command in directory "%s", but that directory '
.
'is not readable (the current process does not have "+r" '
.
'permission).'
,
$cwd
)
)
;
}
if
(
phutil_is_windows
(
)
)
{
// Do nothing. On Windows, calling "is_executable(...)" on a directory
// always appears to return "false". Skip this check under Windows.
}
else
if
(
!
is_executable
(
$cwd
)
)
{
throw
new
Exception
(
pht
(
'Preparing to run a command in directory "%s", but that directory '
.
'is not executable (the current process does not have "+x" '
.
'permission).'
,
$cwd
)
)
;
}
$this
->
cwd
=
$cwd
;
return
$this
;
}
/**
* Get the command's current working directory.
*
* @return string Working directory.
* @task config
*/
final
public
function
getCWD
(
)
{
return
$this
->
cwd
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Thu, Dec 19, 17:00 (22 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1014833
Default Alt Text
PhutilExecutableFuture.php (5 KB)
Attached To
Mode
rARC Arcanist
Attached
Detach File
Event Timeline
Log In to Comment