Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F105209385
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
Sat, Mar 15, 11:26
Size
3 KB
Mime Type
text/x-php
Expires
Mon, Mar 17, 11:26 (2 d)
Engine
blob
Format
Raw Data
Handle
24944360
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
*/
final
class
PhutilExecPassthru
extends
PhutilExecutableFuture
{
private
$command
;
private
$passthruResult
;
/* -( 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
;
}
if
(
$this
->
hasEnv
())
{
$env
=
$this
->
getEnv
();
}
else
{
$env
=
null
;
}
$cwd
=
$this
->
getCWD
();
$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
;
}
/* -( Future )------------------------------------------------------------- */
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
true
;
}
protected
function
getResult
()
{
return
$this
->
passthruResult
;
}
}
Event Timeline
Log In to Comment