Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F92664864
PhutilExecPassthru.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Nov 22, 13:37
Size
4 KB
Mime Type
text/x-php
Expires
Sun, Nov 24, 13:37 (1 d, 18 h)
Engine
blob
Format
Raw Data
Handle
22482034
Attached To
rPHU libphutil
PhutilExecPassthru.php
View Options
<?php
/**
* Execute a command which takes over stdin, stdout and stderr, similar to
* `passthru()`, but which preserves TTY semantics, escapes arguments, and is
* traceable.
*
* Passthru commands use the `STDIN`, `STDOUT` and `STDERR` of the parent
* process, so input can be read from the console and output is printed to it.
* This is primarily useful for executing things like `$EDITOR` from command
* line scripts.
*
* $exec = new PhutilExecPassthru('ls %s', $dir);
* $err = $exec->execute();
*
* You can set the current working directory for the command with
* @{method:setCWD}, and set the environment with @{method:setEnv}.
*
* @task command Executing Passthru Commands
* @task config Configuring Passthru Commands
*/
final
class
PhutilExecPassthru
extends
Phobject
{
private
$command
;
private
$env
;
private
$cwd
;
/* -( Executing Passthru Commands )---------------------------------------- */
/**
* Build a new passthru command.
*
* $exec = new PhutilExecPassthru('ls %s', $dir);
*
* @param string Command pattern. See @{function:csprintf}.
* @param ... Pattern arguments.
*
* @task command
*/
public
function
__construct
(
$pattern
/* , ... */
)
{
$args
=
func_get_args
();
$this
->
command
=
call_user_func_array
(
'csprintf'
,
$args
);
}
/**
* Execute this command.
*
* @return int Error code returned by the subprocess.
*
* @task command
*/
public
function
execute
()
{
$command
=
$this
->
command
;
$profiler
=
PhutilServiceProfiler
::
getInstance
();
$call_id
=
$profiler
->
beginServiceCall
(
array
(
'type'
=>
'exec'
,
'subtype'
=>
'passthru'
,
'command'
=>
$command
,
));
$spec
=
array
(
STDIN
,
STDOUT
,
STDERR
);
$pipes
=
array
();
if
(
$command
instanceof
PhutilCommandString
)
{
$unmasked_command
=
$command
->
getUnmaskedString
();
}
else
{
$unmasked_command
=
$command
;
}
$env
=
$this
->
env
;
$cwd
=
$this
->
cwd
;
$options
=
array
();
if
(
phutil_is_windows
())
{
// Without 'bypass_shell', things like launching vim don't work properly,
// and we can't execute commands with spaces in them, and all commands
// invoked from git bash fail horridly, and everything is a mess in
// general.
$options
[
'bypass_shell'
]
=
true
;
}
$trap
=
new
PhutilErrorTrap
();
$proc
=
@
proc_open
(
$unmasked_command
,
$spec
,
$pipes
,
$cwd
,
$env
,
$options
);
$errors
=
$trap
->
getErrorsAsString
();
$trap
->
destroy
();
if
(!
is_resource
(
$proc
))
{
throw
new
Exception
(
pht
(
'Failed to passthru %s: %s'
,
'proc_open()'
,
$errors
));
}
$err
=
proc_close
(
$proc
);
$profiler
->
endServiceCall
(
$call_id
,
array
(
'err'
=>
$err
,
));
return
$err
;
}
/* -( Configuring Passthru Commands )-------------------------------------- */
/**
* 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
;
}
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
*/
public
function
setCWD
(
$cwd
)
{
$this
->
cwd
=
$cwd
;
return
$this
;
}
}
Event Timeline
Log In to Comment