412cc5f965aee585029f26564a2f221387240503
[yaffs-website] / vendor / drush / drush / includes / exec.inc
1 <?php
2
3 /**
4  * @file
5  *   Functions for executing system commands. (e.g. exec(), system(), ...).
6  */
7
8 use Drush\Log\LogLevel;
9
10 /**
11  * @defgroup commandwrappers Functions to execute commands.
12  * @{
13  */
14
15 /**
16  * Calls 'system()' function, passing through all arguments unchanged.
17  *
18  * This should be used when calling possibly mutative or destructive functions
19  * (e.g. unlink() and other file system functions) so that can be suppressed
20  * if the simulation mode is enabled.
21  *
22  * @param $exec
23  *   The shell command to execute.  Parameters should already be escaped.
24  * @return
25  *   The result code from system():  0 == success.
26  *
27  * @see drush_shell_exec()
28  */
29 function drush_op_system($exec) {
30   if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
31     drush_print("Calling system($exec);", 0, STDERR);
32   }
33   if (drush_get_context('DRUSH_SIMULATE')) {
34     return 0;
35   }
36
37   // Throw away output.  Use drush_shell_exec() to capture output.
38   system($exec, $result_code);
39
40   return $result_code;
41 }
42
43 /**
44  * Executes a shell command at a new working directory.
45  * The old cwd is restored on exit.
46  *
47  * @param $effective_wd
48  *   The new working directory to execute the shell command at.
49  * @param $cmd
50  *   The command to execute. May include placeholders used for sprintf.
51  * @param ...
52  *   Values for the placeholders specified in $cmd. Each of these will be passed through escapeshellarg() to ensure they are safe to use on the command line.
53  * @return
54  *   TRUE on success, FALSE on failure
55  */
56 function drush_shell_cd_and_exec($effective_wd, $cmd) {
57   $args = func_get_args();
58
59   $effective_wd = array_shift($args);
60   $cwd = getcwd();
61   drush_op('chdir', $effective_wd);
62   $result = call_user_func_array('drush_shell_exec', $args);
63   drush_op('chdir', $cwd);
64   return $result;
65 }
66
67 /**
68  * Executes a shell command.
69  * Output is only printed if in verbose mode.
70  * Output is stored and can be retrieved using drush_shell_exec_output().
71  * If in simulation mode, no action is taken.
72  *
73  * @param $cmd
74  *   The command to execute. May include placeholders used for sprintf.
75  * @param ...
76  *   Values for the placeholders specified in $cmd. Each of these will be passed through escapeshellarg() to ensure they are safe to use on the command line.
77  * @return
78  *   TRUE on success, FALSE on failure
79  */
80 function drush_shell_exec($cmd) {
81   return _drush_shell_exec(func_get_args());
82 }
83
84 /**
85  * Returns executable code for invoking preferred test editor.
86  *
87  * The next line after calling this function is usually
88  *   @code drush_shell_exec_interactive($exec, $filepath, $filepath) @endcode
89  *
90  * @see drush_config_edit()
91  */
92 function drush_get_editor() {
93   $bg = drush_get_option('bg') ? '&' : '';
94   // see http://drupal.org/node/1740294
95   $exec = drush_get_option('editor', '${VISUAL-${EDITOR-vi}}') . " %s $bg";
96   return $exec;
97 }
98
99 /**
100  * Executes a command in interactive mode.
101  *
102  * @see drush_shell_exec.
103  */
104 function drush_shell_exec_interactive($cmd) {
105   return _drush_shell_exec(func_get_args(), TRUE);
106 }
107
108 /**
109  * Internal function: executes a shell command on the
110  * local machine.  This function should not be used
111  * in instances where ssh is utilized to execute a
112  * command remotely; otherwise, remote operations would
113  * fail if executed from a Windows machine to a remote
114  * Linux server.
115  *
116  * @param $args
117  *   The command and its arguments.
118  * @param $interactive
119  *   Whether to run in
120  *
121  * @return
122  *   TRUE on success, FALSE on failure
123  *
124  * @see drush_shell_exec.
125  */
126 function _drush_shell_exec($args, $interactive = FALSE) {
127   // Do not change the command itself, just the parameters.
128   for ($x = 1; $x < count($args); $x++) {
129     $args[$x] = drush_escapeshellarg($args[$x]);
130   }
131   // Important: we allow $args to take one of two forms here.  If
132   // there is only one item in the array, it is the already-escaped
133   // command string, but otherwise sprintf is used.  In the case
134   // of pre-escaped strings, sprintf will fail if any of the escaped
135   // parameters contain '%', so we must not call sprintf unless necessary.
136   if (count($args) == 1) {
137     $command = $args[0];
138   }
139   else {
140     $command = call_user_func_array('sprintf', $args);
141   }
142
143   if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
144     drush_print('Executing: ' . $command, 0, STDERR);
145   }
146   if (!drush_get_context('DRUSH_SIMULATE')) {
147     if ($interactive) {
148       $result = drush_shell_proc_open($command);
149       return ($result == 0) ? TRUE : FALSE;
150     }
151     else {
152       exec($command . ' 2>&1', $output, $result);
153       _drush_shell_exec_output_set($output);
154
155       if (drush_get_context('DRUSH_DEBUG')) {
156         foreach ($output as $line) {
157           drush_print($line, 2);
158         }
159       }
160
161       // Exit code 0 means success.
162       return ($result == 0);
163     }
164   }
165   else {
166     return TRUE;
167   }
168 }
169
170 /**
171  * Determine whether 'which $command' can find
172  * a command on this system.
173  */
174 function drush_which($command) {
175   exec("which $command 2>&1", $output, $result);
176   return ($result == 0);
177 }
178
179 /**
180  * Build an SSH string including an optional fragment of bash. Commands that use
181  * this should also merge drush_shell_proc_build_options() into their
182  * command options. @see ssh_drush_command().
183  *
184  * @param array $site
185  *   A site alias record.
186  * @param string $command
187  *   An optional bash fragment.
188  * @param string $cd
189  *   An optional directory to change into before executing the $command. Set to
190  *   boolean TRUE to change into $site['root'] if available.
191  * @param boolean $interactive
192  *   Force creation of a tty
193  * @return string
194  *   A string suitable for execution with drush_shell_remote_exec().
195  */
196 function drush_shell_proc_build($site, $command = '', $cd = NULL, $interactive = FALSE) {
197   // Build up the command. TODO: We maybe refactor this soon.
198   $hostname = drush_remote_host($site);
199   $ssh_options = drush_sitealias_get_option($site, 'ssh-options', "-o PasswordAuthentication=no");
200   $os = drush_os($site);
201   if (drush_sitealias_get_option($site, 'tty') || $interactive) {
202     $ssh_options .= ' -t';
203   }
204
205   $cmd = "ssh " . $ssh_options . " " . $hostname;
206
207   if ($cd === TRUE) {
208     if (array_key_exists('root', $site)) {
209       $cd = $site['root'];
210     }
211     else {
212       $cd = FALSE;
213     }
214   }
215   if ($cd) {
216     $command = 'cd ' . drush_escapeshellarg($cd, $os) . ' && ' . $command;
217   }
218
219   if (!empty($command)) {
220     if (!drush_get_option('escaped', FALSE)) {
221       $cmd .= " " . drush_escapeshellarg($command, $os);
222     }
223     else {
224       $cmd .= " $command";
225     }
226   }
227
228   return $cmd;
229 }
230
231 /**
232  * Execute bash command using proc_open().
233  *
234  * @returns
235  *   Exit code from launched application
236  *     0 no error
237  *     1 general error
238  *     127 command not found
239  */
240 function drush_shell_proc_open($cmd) {
241   if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
242     drush_print("Calling proc_open($cmd);", 0, STDERR);
243   }
244   if (!drush_get_context('DRUSH_SIMULATE')) {
245     $process = proc_open($cmd, array(0 => STDIN, 1 => STDOUT, 2 => STDERR), $pipes);
246     $proc_status = proc_get_status($process);
247     $exit_code = proc_close($process);
248     return ($proc_status["running"] ? $exit_code : $proc_status["exitcode"] );
249   }
250   return 0;
251 }
252
253 /**
254  * Used by definition of ssh and other commands that call into drush_shell_proc_build()
255  * to declare their options.
256  */
257 function drush_shell_exec_proc_build_options() {
258   return array(
259    'ssh-options' => 'A string of extra options that will be passed to the ssh command (e.g. "-p 100")',
260     'tty' => 'Create a tty (e.g. to run an interactive program).',
261     'escaped' => 'Command string already escaped; do not add additional quoting.',
262   );
263 }
264
265 /**
266  * Determine the appropriate os value for the
267  * specified site record
268  *
269  * @returns
270  *   NULL for 'same as local machine', 'Windows' or 'Linux'.
271  */
272 function drush_os($site_record = NULL) {
273   // Default to $os = NULL, meaning 'same as local machine'
274   $os = NULL;
275   // If the site record has an 'os' element, use it
276   if (isset($site_record) && array_key_exists('os', $site_record)) {
277     $os = $site_record['os'];
278   }
279   // Otherwise, we will assume that all remote machines are Linux
280   // (or whatever value 'remote-os' is set to in drushrc.php).
281   elseif (isset($site_record) && array_key_exists('remote-host', $site_record) && !empty($site_record['remote-host'])) {
282     $os = drush_get_option('remote-os', 'Linux');
283   }
284
285   return $os;
286 }
287
288 /**
289  * Determine the remote host (username@hostname.tld) for
290  * the specified site.
291  */
292 function drush_remote_host($site, $prefix = '') {
293   $hostname = drush_escapeshellarg(drush_sitealias_get_option($site, 'remote-host', '', $prefix), "LOCAL");
294   $username = drush_escapeshellarg(drush_sitealias_get_option($site, 'remote-user', '', $prefix), "LOCAL");
295   return $username . (empty($username) ? '' : '@') . $hostname;
296 }
297
298 /**
299  * Make an attempt to simply wrap the arg with the
300  * kind of quote characters it does not already contain.
301  * If it contains both kinds, then this function reverts to drush_escapeshellarg.
302  */
303 function drush_wrap_with_quotes($arg) {
304   $has_double = strpos($arg, '"') !== FALSE;
305   $has_single = strpos($arg, "'") !== FALSE;
306   if ($has_double && $has_single) {
307     return drush_escapeshellarg($arg);
308   }
309   elseif ($has_double) {
310     return "'" . $arg . "'";
311   }
312   else {
313     return '"' . $arg . '"';
314   }
315 }
316
317 /**
318  * Platform-dependent version of escapeshellarg().
319  * Given the target platform, return an appropriately-escaped
320  * string. The target platform may be omitted for args that
321  * are /known/ to be for the local machine.
322  * Use raw to get an unquoted version of the escaped arg.
323  * Notice that you can't add quotes later until you know the platform.
324  */
325
326 /**
327  * Stores output for the most recent shell command.
328  * This should only be run from drush_shell_exec().
329  *
330  * @param array|bool $output
331  *   The output of the most recent shell command.
332  *   If this is not set the stored value will be returned.
333  */
334 function _drush_shell_exec_output_set($output = FALSE) {
335   static $stored_output;
336   if ($output === FALSE) return $stored_output;
337   $stored_output = $output;
338 }
339
340 /**
341  * Returns the output of the most recent shell command as an array of lines.
342  */
343 function drush_shell_exec_output() {
344   return _drush_shell_exec_output_set();
345 }
346
347 /**
348  * Starts a background browser/tab for the current site or a specified URL.
349  *
350  * Uses a non-blocking proc_open call, so Drush execution will continue.
351  *
352  * @param $uri
353  *   Optional URI or site path to open in browser. If omitted, or if a site path
354  *   is specified, the current site home page uri will be prepended if the sites
355  *   hostname resolves.
356  * @return
357  *   TRUE if browser was opened, FALSE if browser was disabled by the user or a,
358  *   default browser could not be found.
359  */
360 function drush_start_browser($uri = NULL, $sleep = FALSE, $port = FALSE) {
361   if ($browser = drush_get_option('browser', TRUE)) {
362     // We can only open a browser if we have a DISPLAY environment variable on
363     // POSIX or are running Windows or OS X.
364     if (!drush_get_context('DRUSH_SIMULATE') && !getenv('DISPLAY') && !drush_is_windows() && !drush_is_osx()) {
365       drush_log(dt('No graphical display appears to be available, not starting browser.'), LogLevel::NOTICE);
366       return FALSE;
367     }
368     $host = parse_url($uri, PHP_URL_HOST);
369     if (!$host) {
370       // Build a URI for the current site, if we were passed a path.
371       $site = drush_get_context('DRUSH_URI');
372       $host = parse_url($site, PHP_URL_HOST);
373       $uri = $site . '/' . ltrim($uri, '/');
374     }
375     // Validate that the host part of the URL resolves, so we don't attempt to
376     // open the browser for http://default or similar invalid hosts.
377     $hosterror = (gethostbynamel($host) === FALSE);
378     $iperror = (ip2long($host) && gethostbyaddr($host) == $host);
379     if (!drush_get_context('DRUSH_SIMULATE') && ($hosterror || $iperror)) {
380       drush_log(dt('!host does not appear to be a resolvable hostname or IP, not starting browser. You may need to use the --uri option in your command or site alias to indicate the correct URL of this site.', array('!host' => $host)), LogLevel::WARNING);
381       return FALSE;
382     }
383     if ($port) {
384       $uri = str_replace($host, "localhost:$port", $uri);
385     }
386     if ($browser === TRUE) {
387       // See if we can find an OS helper to open URLs in default browser.
388       if (drush_shell_exec('which xdg-open')) {
389         $browser = 'xdg-open';
390       }
391       else if (drush_shell_exec('which open')) {
392         $browser = 'open';
393       }
394       else if (!drush_has_bash()) {
395         $browser = 'start';
396       }
397       else {
398         // Can't find a valid browser.
399         $browser = FALSE;
400       }
401     }
402     $prefix = '';
403     if ($sleep) {
404       $prefix = 'sleep ' . $sleep . ' && ';
405     }
406     if ($browser) {
407       drush_log(dt('Opening browser !browser at !uri', array('!browser' => $browser, '!uri' => $uri)));
408       if (!drush_get_context('DRUSH_SIMULATE')) {
409         $pipes = array();
410         proc_close(proc_open($prefix . $browser . ' ' . drush_escapeshellarg($uri) . ' 2> ' . drush_bit_bucket() . ' &', array(), $pipes));
411       }
412       return TRUE;
413     }
414   }
415   return FALSE;
416 }
417
418 /**
419  * @} End of "defgroup commandwrappers".
420  */