/[drupal]/contributions/modules/drush/includes/drush.inc
ViewVC logotype

Contents of /contributions/modules/drush/includes/drush.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.57 - (show annotations) (download) (as text)
Fri Oct 30 06:13:21 2009 UTC (4 weeks, 1 day ago) by weitzman
Branch: MAIN
Changes since 1.56: +2 -2 lines
File MIME type: text/x-php
Clarify a couple messages in sql sync and minor misc.
1 <?php
2 // $Id: drush.inc,v 1.56 2009/10/26 02:26:37 weitzman Exp $
3
4 /**
5 * @file
6 * The drush API implementation and helpers.
7 */
8
9
10 /**
11 * Dispatch a given set of commands.
12 * Modules can add commands by implementing hook_drush_command().
13 *
14 * @param
15 * Command whose callback you want to call, defaults to current command.
16 */
17 function drush_dispatch($command = NULL) {
18 $command = ($command) ? $command : drush_get_command();
19 $return = FALSE;
20
21 if ($command) {
22 // Call the callback function of the active command.
23 $return = call_user_func_array($command['callback'], $command['arguments']);
24 }
25
26 // prevent a '1' at the end of the output
27 if ($return === TRUE) {
28 $return = '';
29 }
30
31 // Add a final log entry, just so a timestamp appears.
32 drush_log(dt('Command dispatch complete'), 'notice');
33
34 return $return;
35 }
36
37 /**
38 * Include a file, selecting a version specific file if available.
39 *
40 * For example, if you pass the path "/var/drush" and the name
41 * "update" when bootstrapped on a Drupal 6 site it will first check for
42 * the presence of "/var/drush/update_6.inc" in include it if exists. If this
43 * file does NOT exist it will proceed and check for "/var/drush/update.inc".
44 * If neither file exists, it will return FALSE.
45 *
46 * @param $path
47 * The path you want to search.
48 * @param $name
49 * The file base name you want to include (not including a version suffix
50 * or extension).
51 * @param $version
52 * The version suffix you want to include (could be specific to the software
53 * or platform your are connecting to) - defaults to the current Drupal core
54 * major version.
55 * @param $extension
56 * The extension - defaults to ".inc".
57 *
58 * @return
59 * TRUE if the file was found and included.
60 */
61 function drush_include($path, $name, $version = NULL, $extension = 'inc') {
62 $version = ($version) ? $version : drush_drupal_major_version();
63 $file = sprintf("%s/%s_%s.%s", $path, $name, $version, $extension);
64 if (file_exists($file)) {
65 drush_log(dt('Including version specific file : @file', array('@file' => $file)));
66 include_once($file);
67 return TRUE;
68 }
69 $file = sprintf("%s/%s.%s", $path, $name, $extension);
70 if (file_exists($file)) {
71 drush_log(dt('Including non-version specific file : @file', array('@file' => $file)));
72 include_once($file);
73 return TRUE;
74 }
75 }
76
77 /**
78 * Return a structured array of engines of a specific type from commandfiles
79 * implementing hook_drush_engine_$type.
80 *
81 * Engines are pluggable subsystems. Each engine of a specific type will
82 * implement the same set of API functions and perform the same high-level
83 * task using a different backend or approach.
84 *
85 * This function/hook is useful when you have a selection of several mutually
86 * exclusive options to present to a user to select from.
87 *
88 * Other commands are able to extend this list and provide their own engines.
89 * The hook can return useful information to help users decide which engine
90 * they need, such as description or list of available engine options.
91 *
92 * The engine path element will automatically default to a subdirectory (within
93 * the directory of the commandfile that implemented the hook) with the name of
94 * the type of engine - e.g. an engine "wget" of type "handler" provided by
95 * the "pm" commandfile would automatically be found if the file
96 * "pm/handler/wget.inc" exists and a specific path is not provided.
97 *
98 * @param $type
99 * The type of engine.
100 *
101 * @return
102 * A structured array of engines.
103 */
104 function drush_get_engines($type) {
105 $engines = array();
106 $list = drush_commandfile_list();
107 foreach ($list as $commandfile => $path) {
108 if (drush_command_hook($commandfile, 'drush_engine_' . $type)) {
109 $function = $commandfile . '_drush_engine_' . $type;
110 $result = $function();
111 foreach ((array)$result as $key => $engine) {
112 // Add some defaults
113 $engine += array(
114 'commandfile' => $commandfile,
115 // Engines by default live in a subdirectory of the commandfile that
116 // declared them, named as per the type of engine they are.
117 'path' => sprintf("%s/%s", dirname($path), $type),
118 );
119 $engines[$key] = $engine;
120 }
121 }
122 }
123 return $engines;
124 }
125
126 /**
127 * Include the engine code for a specific named engine of a certain type.
128 *
129 * If the engine type has implemented hook_drush_engine_$type the path to the
130 * engine specified in the array will be used.
131 *
132 * If you don't need to present any user options for selecting the engine
133 * (which is common if the selection is implied by the running environment)
134 * and you don't need to allow other modules to define their own engines you can
135 * simply pass the $path to the directory where the engines are, and the
136 * appropriate one will be included.
137 *
138 * Unlike drush_include this function will set errors if the requested engine
139 * cannot be found.
140 *
141 * @param $type
142 * The type of engine.
143 * @param $engine
144 * The key for the engine to be included.
145 * @param $version
146 * The version of the engine to be included - defaults to the current Drupal core
147 * major version.
148 * @param $path
149 * A path to include from, if the engine has no corresponding
150 * hook_drush_engine_$type item path.
151 * @return unknown_type
152 */
153 function drush_include_engine($type, $engine, $version = NULL, $path = NULL) {
154 $engines = drush_get_engines($type);
155 if (!$path && isset($engines[$engine])) {
156 $path = $engines[$engine]['path'];
157 }
158 if (!$path) {
159 return drush_set_error('DRUSH_ENGINE INCLUDE_NO_PATH', dt('No !path was set for including the !type engine !engine.', array('!path' => $path, '!type' => $type, '!engine' => $engine)));
160 }
161 if (drush_include($path, $engine, $version)) {
162 return TRUE;
163 }
164 return drush_set_error('DRUSH_ENGINE INCLUDE_FAILED', dt('Unable to include the !type engine !engine from !path.' , array('!path' => $path, '!type' => $type, '!engine' => $engine)));
165 }
166
167 /**
168 * Detects the version number of the current Drupal installation,
169 * if any. Returns false if there is no current Drupal installation,
170 * or it is somehow broken.
171 *
172 * This function relies on the presence of DRUPAL_ROOT/modules/system/system.module
173 *
174 * @return
175 * A string containing the version number of the current
176 * Drupal installation, if any. Otherwise, return false.
177 */
178 function drush_drupal_version() {
179 static $version = FALSE;
180
181 if (!$version) {
182 if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
183 if (file_exists($drupal_root . '/modules/system/system.module')) {
184 // We can safely include system.module as it contains defines and functions only.
185 require_once($drupal_root . '/modules/system/system.module');
186 // We just might be dealing with an early Drupal version (pre 4.7)
187 if (defined('VERSION')) {
188 $version = VERSION;
189 }
190 }
191 }
192 }
193 return $version;
194 }
195
196 /**
197 * Returns the Drupal major version number (5, 6, 7 ...)
198 */
199 function drush_drupal_major_version() {
200 $major_version = FALSE;
201 if ($version = drush_drupal_version()) {
202 $version_parts = explode('.', $version);
203 if (is_numeric($version_parts[0])) {
204 $major_version = (integer)$version_parts[0];
205 }
206 }
207 return $major_version;
208 }
209
210 /**
211 * A db_result() that works for any version of Drupal.
212 *
213 * @param
214 * A Database result object.
215 */
216 function drush_db_result($result) {
217 return drush_drupal_major_version() >= 7 ? $result->fetchField() : db_result($result);
218 }
219
220 /**
221 * A db_fetch_object() that works for any version of Drupal.
222 *
223 * @param
224 * A Database result object.
225 */
226 function drush_db_fetch_object($result) {
227 return drush_drupal_major_version() >= 7 ? $result->fetchObject() : db_fetch_object($result);
228 }
229
230 /**
231 * Save a string to a temporary file. Does not depend on Drupal's API.
232 *
233 * @param string $data
234 * @return string
235 * A path to the file.
236 */
237 function drush_save_data_to_temp_file($data) {
238 static $fp;
239
240 $fp = tmpfile();
241 fwrite($fp, $data);
242 $meta_data = stream_get_meta_data($fp);
243 return $meta_data['uri'];
244 }
245
246 /**
247 * Calls a given function, passing through all arguments unchanged.
248 *
249 * This should be used when calling possibly mutative or destructive functions
250 * (e.g. unlink() and other file system functions) so that can be suppressed
251 * if the simulation mode is enabled.
252 *
253 * @param $function
254 * The name of the function.
255 * @return
256 * The return value of the function, or TRUE if simulation mode is enabled.
257 */
258 function drush_op($function) {
259 $args = func_get_args();
260 array_shift($args); // Skip function name
261
262 if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
263 drush_print("Calling $function(". implode(", ", $args) .')');
264 }
265
266 if (drush_get_context('DRUSH_SIMULATE')) {
267 return TRUE;
268 }
269
270 return call_user_func_array($function, $args);
271 }
272
273 /**
274 * Rudimentary replacement for Drupal API t() function.
275 *
276 * @param string
277 * String to process, possibly with replacement item.
278 * @param array
279 * An associative array of replacement items.
280 *
281 * @return
282 * The processed string.
283 *
284 * @see t()
285 */
286 function dt($string, $args = array()) {
287 if (function_exists('t')) {
288 return t($string, $args);
289 }
290 else {
291 if (!empty($args)) {
292 return strtr($string, $args);
293 }
294 else {
295 return $string;
296 }
297 }
298 }
299
300 /**
301 * Get the available options for Drush for use by help page.
302 *
303 * @return
304 * An associative array containing the option definition as the key, and the description as the value,
305 * for each of the available options.
306 */
307 function drush_get_option_help() {
308 // TODO: Add a hook for this, to allow other modules to add their options
309 $options['-r <path>, --root=<path>'] = dt("Drupal root directory to use (default: current directory)");
310 $options['-l <uri>, --uri=http://example.com'] = dt('URI of the drupal site to use (only needed in multisite environments)');
311 $options['-v, --verbose'] = dt('Display extra information about the command.');
312 $options['-d, --debug'] = dt('Display even more information, including internal messages.');
313 $options['-q, --quiet'] = dt('Hide all output');
314 $options['-y, --yes'] = dt("Assume 'yes' as answer to all prompts");
315 $options['-s, --simulate'] = dt("Simulate all relevant actions (don't actually change the system)");
316 $options['-i, --include'] = dt("A list of paths to search for drush commands");
317 $options['-c, --config'] = dt("Specify a config file to use. See example.drushrc.php");
318 $options['-u, --user'] = dt("Specify a user to login with. May be a name or a number.");
319 $options['-b, --backend'] = dt("Hide all output and return structured data (internal use only).");
320 $options['-p, --pipe'] = dt("Emit a compact representation of the command for scripting.");
321 $options['-n, --nocolor'] = dt("Suppress color highlighting on log messages.");
322 $options['-h, --help'] = dt("The absolute path to your PHP intepreter.");
323 return $options;
324 }
325
326 /**
327 * Prints out help for a given command.
328 */
329 function drush_show_help($commands) {
330 $phases = _drush_bootstrap_phases();
331
332 $commandstring = implode(" ", $commands);
333
334 foreach ($phases as $phase_index) {
335 if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE')) {
336 drush_bootstrap($phase_index);
337 }
338 if (!drush_get_error()) {
339 $commands = drush_get_commands();
340 if (array_key_exists($commandstring, $commands)) {
341 $command = $commands[$commandstring];
342
343 // Merge in engine specific help.
344 foreach ($command['engines'] as $type => $description) {
345 $all_engines = drush_get_engines($type);
346 foreach ($all_engines as $name => $engine) {
347 $command = array_merge_recursive($command, $engine);
348 }
349 }
350
351 $help = drush_command_invoke_all('drush_help', 'drush:'. $command['command']);
352 if (!empty($help)) {
353 drush_print(wordwrap(implode("\n", $help), drush_get_context('DRUSH_COLUMNS', 80)));
354 drush_print();
355
356 // TODO: Let commands define additional sections.
357 $sections = array(
358 'examples' => 'Examples',
359 'arguments' => 'Arguments',
360 'options' => 'Options',
361 );
362
363 foreach ($sections as $key => $value) {
364 if (!empty($command[$key])) {
365 drush_print(dt($value) . ':');
366 foreach ($command[$key] as $name => $description) {
367 // '[command] is a token representing the current command. @see pm_drush_engine_version_control().
368 $rows[] = array(str_replace('[command]', $commandstring, $name), dt($description));
369 }
370 drush_print_table($rows, false, array(40));
371 unset($rows);
372 drush_print();
373 }
374 }
375
376 // Append aliases if any.
377 if ($command['aliases']) {
378 drush_print(dt("Aliases: ") . implode(', ', $command['aliases']));
379 }
380
381 return TRUE;
382 }
383 else {
384 drush_print("No help available for command '$commandstring'.");
385 return TRUE;
386 }
387 }
388 }
389 else {
390 break;
391 }
392 }
393 return drush_set_error('DRUSH_COMMAND_NOT_FOUND', dt('Invalid command !command.', array('!command' => $commandstring)));
394 }
395
396 /**
397 * Executes a shell command.
398 * Output is only printed if in verbose mode.
399 * Output is stored and can be retrieved using drush_shell_exec_output().
400 * If in simulation mode, no action is taken.
401 *
402 * @param $cmd
403 * The command to execute. May include placeholders used for sprintf.
404 * @param ...
405 * 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.
406 * @return
407 * 0 if success.
408 */
409 function drush_shell_exec($cmd) {
410 if (drush_get_context('DRUSH_SIMULATE')) {
411 return true;
412 }
413 $args = func_get_args();
414
415 //do not change the command itself, just the parameters.
416 for ($x = 1; $x < sizeof($args); $x++) {
417 $args[$x] = escapeshellarg($args[$x]);
418 }
419 $command = call_user_func_array('sprintf', $args);
420
421 if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
422 drush_log('Executing: ' . $command);
423 }
424
425 exec($command . ' 2>&1', $output, $result);
426
427 _drush_shell_exec_output_set($output);
428
429 if (drush_get_context('DRUSH_VERBOSE')) {
430 foreach ($output as $line) {
431 drush_print($line, 2);
432 }
433 }
434
435 // Exit code 0 means success.
436 return ($result == 0);
437 }
438
439 /**
440 * Stores output for the most recent shell command.
441 * This should only be run from drush_shell_exec().
442 *
443 * @param $output
444 * The output of the most recent shell command.
445 * If this is not set the stored value will be returned.
446 */
447 function _drush_shell_exec_output_set($output = FALSE) {
448 static $stored_output;
449 if (!$output) return $stored_output;
450 $stored_output = $output;
451 }
452
453 /**
454 * Returns the output of the most recent shell command as an array of lines.
455 */
456 function drush_shell_exec_output() {
457 return _drush_shell_exec_output_set();
458 }
459
460 /**
461 * Exits with a message. In general, you should use drush_set_error() instead of
462 * this function. That lets drush proceed with other tasks.
463 * TODO: Exit with a correct status code.
464 */
465 function drush_die($msg = NULL, $status = NULL) {
466 die($msg ? "drush: $msg\n" : '');
467 }
468
469 /**
470 * Prints a message with optional indentation. In general,
471 * drush_log($message, 'ok') is often a better choice than this function.
472 * That gets your confirmation message (for example) into the logs for this
473 * drush request. Consider that drush requests may be executed remotely and
474 * non interactively.
475 *
476 * @param $message
477 * The message to print.
478 * @param $indent
479 * The indentation (space chars)
480 */
481 function drush_print($message = '', $indent = 0) {
482 print str_repeat(' ', $indent) . (string)$message . "\n";
483 }
484
485 /**
486 * Stores a message which is printed during drush_shutdown() if in compact mode.
487 * @param $message
488 * The message to print.
489 */
490 function drush_print_pipe($message = '') {
491 $buffer = &drush_get_context('DRUSH_PIPE_BUFFER' , '');
492 $buffer .= $message;
493 }
494
495 /**
496 * Prints an array or string.
497 * @param $array
498 * The array to print.
499 */
500 function drush_print_r($array) {
501 print_r($array);
502 }
503
504 /**
505 * Ask the user a basic yes/no question.
506 *
507 * @param $msg The question to ask
508 * @return TRUE if the user entered 'y', FALSE if he entered 'n'
509 */
510 function drush_confirm($msg, $indent = 0) {
511 print str_repeat(' ', $indent) . (string)$msg . " (y/n): ";
512
513 if (drush_get_context('DRUSH_AFFIRMATIVE')) {
514 print "y\n";
515 return TRUE;
516 }
517 // See http://drupal.org/node/499758 before changing this.
518 $stdin = fopen("php://stdin","r");
519
520 while ($line = fgets($stdin)) {
521 $line = trim($line);
522 if ($line == 'y') {
523 return TRUE;
524 }
525 if ($line == 'n') {
526 return FALSE;
527 }
528 print str_repeat(' ', $indent) . (string)$msg . " (y/n): ";
529 }
530 }
531
532 /**
533 * Print a formatted table.
534 *
535 * @param $rows
536 * The rows to print.
537 * @param $header
538 * If TRUE, the first line will be treated as table header and therefore be
539 * underlined.
540 * @param $widths
541 * The widths of each column (in characters) to use - if not specified this
542 * will be determined automatically, based on a "best fit" algorithm.
543 */
544 function drush_print_table($rows, $header = FALSE, $widths = array()) {
545 $tbl = new Console_Table(CONSOLE_TABLE_ALIGN_LEFT , '');
546
547 $auto_widths = drush_table_column_autowidth($rows, $widths);
548
549 // Do wordwrap on all cells.
550 $newrows = array();
551 foreach ($rows as $rowkey => $row) {
552 foreach ($row as $col_num => $cell) {
553 $newrows[$rowkey][$col_num] = wordwrap($cell, $auto_widths[$col_num], "\n", TRUE);
554 if (isset($widths[$col_num])) {
555 $newrows[$rowkey][$col_num] = str_pad($newrows[$rowkey][$col_num], $widths[$col_num]);
556 }
557 }
558 }
559 if ($header) {
560 $headers = array_shift($newrows);
561 $tbl->setHeaders($headers);
562 }
563
564 $tbl->addData($newrows);
565 print $tbl->getTable();
566 }
567
568 /**
569 * Determine the best fit for column widths.
570 *
571 * @param $rows
572 * The rows to use for calculations.
573 * @param $widths
574 * Manually specified widths of each column (in characters) - these will be
575 * left as is.
576 */
577 function drush_table_column_autowidth($rows, $widths) {
578 $auto_widths = $widths;
579
580 // First we determine the distribution of row lengths in each column.
581 // This is an array of descending character length keys (i.e. starting at
582 // the rightmost character column), with the value indicating the number
583 // of rows where that character column is present.
584 $col_dist = array();
585 foreach ($rows as $rowkey => $row) {
586 foreach ($row as $col_num => $cell) {
587 if (empty($widths[$col_num])) {
588 $length = strlen($cell);
589 while ($length > 0) {
590 if (!isset($col_dist[$col_num][$length])) {
591 $col_dist[$col_num][$length] = 0;
592 }
593 $col_dist[$col_num][$length]++;
594 $length--;
595 }
596 }
597 }
598 }
599 foreach ($col_dist as $col_num => $count) {
600 // Sort the distribution in decending key order.
601 krsort($col_dist[$col_num]);
602 // Initially we set all columns to their "ideal" longest width
603 // - i.e. the width of their longest column.
604 $auto_widths[$col_num] = max(array_keys($col_dist[$col_num]));
605 }
606
607 // We determine what width we have available to use, and what width the
608 // above "ideal" columns take up.
609 $available_width = drush_get_context('DRUSH_COLUMNS', 80) - (count($auto_widths) * 2);
610 $auto_width_current = array_sum($auto_widths);
611
612 // If we need to reduce a column so that we can fit the space we use this
613 // loop to figure out which column will cause the "least wrapping",
614 // (relative to the other columns) and reduce the width of that column.
615 while ($auto_width_current > $available_width) {
616 $count = 0;
617 $width = 0;
618 foreach ($col_dist as $col_num => $counts) {
619 // If we are just starting out, select the first column.
620 if ($count == 0 ||
621 // OR: if this column would cause less wrapping than the currently
622 // selected column, then select it.
623 (current($counts) < $count) ||
624 // OR: if this column would cause the same amount of wrapping, but is
625 // longer, then we choose to wrap the longer column (proportionally
626 // less wrapping, and helps avoid triple line wraps).
627 (current($counts) == $count && key($counts) > $width)) {
628 // Select the column number, and record the count and current width
629 // for later comparisons.
630 $column = $col_num;
631 $count = current($counts);
632 $width = key($counts);
633 }
634 }
635 if ($width <= 1) {
636 // If we have reached a width of 1 then give up, so wordwrap can still progress.
637 break;
638 }
639 // Reduce the width of the selected column.
640 $auto_widths[$column]--;
641 // Reduce our overall table width counter.
642 $auto_width_current--;
643 // Remove the corresponding data from the disctribution, so next time
644 // around we use the data for the row to the left.
645 unset($col_dist[$column][$width]);
646 }
647 return $auto_widths;
648 }
649
650 /**
651 * @defgroup logging Logging information to be provided as output.
652 * @{
653 *
654 * These functions are primarily for diagnostic purposes, but also provide an overview of tasks that were taken
655 * by drush.
656 */
657
658 /**
659 * Add a log message to the log history.
660 *
661 * This function calls the callback stored in the 'DRUSH_LOG_CALLBACK' context with
662 * the resulting entry at the end of execution.
663 *
664 * This allows you to replace it with custom logging implementations if needed,
665 * such as logging to a file or logging to a database (drupal or otherwise).
666 *
667 * The default callback is the _drush_print_log() function with prints the messages
668 * to the shell.
669 *
670 * @param message
671 * String containing the message to be logged.
672 * @param type
673 * The type of message to be logged. Common types are 'warning', 'error', 'success' and 'notice'.
674 * A type of 'failed' can also be supplied to flag as an 'error'.
675 * A type of 'ok' or 'completed' can also be supplied to flag as a 'success'
676 * All other types of messages will be assumed to be notices.
677 */
678 function drush_log($message, $type = 'notice', $error = null) {
679 $log =& drush_get_context('DRUSH_LOG', array());
680 $callback = drush_get_context('DRUSH_LOG_CALLBACK', '_drush_print_log');
681 $entry = array(
682 'type' => $type,
683 'message' => $message,
684 'timestamp' => microtime(TRUE),
685 );
686 $entry['error'] = $error;
687 $log[] = $entry;
688 return $callback($entry);
689 }
690
691 /**
692 * Retrieve the log messages from the log history
693 *
694 * @return
695 * Entire log history
696 */
697 function drush_get_log() {
698 return drush_get_context('DRUSH_LOG', array());
699 }
700
701 /**
702 * Run print_r on a variable and log the output.
703 */
704 function dlm($object) {
705 ob_start();
706 print_r($object);
707 $contents = ob_get_contents();
708 ob_end_clean();
709
710 drush_log($contents);
711 }
712
713 /*
714 * Display the pipe output for the current request.
715 */
716 function drush_pipe_output() {
717 $pipe = drush_get_context('DRUSH_PIPE_BUFFER');
718 drush_print_r($pipe);
719 }
720
721 /**
722 * Display the log message
723 *
724 * By default, only warnings and errors will be displayed, if 'verbose' is specified, it will also display notices.
725 *
726 * @param
727 * The associative array for the entry.
728 *
729 * @return
730 * False in case of an error or failed type, True in all other cases.
731 */
732 function _drush_print_log($entry) {
733 if (drush_get_context('DRUSH_NOCOLOR')) {
734 $red = "[%s]";
735 $yellow = "[%s]";
736 $green = "[%s]";
737 }
738 else {
739 $red = "\033[31;40m\033[1m[%s]\033[0m";
740 $yellow = "\033[1;33;40m\033[1m[%s]\033[0m";
741 $green = "\033[0;33;40m\033[1m[%s]\033[0m";
742 }
743
744 $verbose = drush_get_context('DRUSH_VERBOSE');
745 $debug = drush_get_context('DRUSH_DEBUG');
746
747 $return = TRUE;
748 switch ($entry['type']) {
749 case 'warning' :
750 $type_msg = sprintf($yellow, $entry['type']);
751 break;
752 case 'failed' :
753 case 'error' :
754 $type_msg = sprintf($red, $entry['type']);
755 $return = FALSE;
756 break;
757 case 'ok' :
758 case 'completed' :
759 case 'success' :
760 $type_msg = sprintf($green, $entry['type']);
761 break;
762 case 'notice' :
763 case 'message' :
764 if (!$verbose) {
765 // print nothing. exit cleanly.
766 return TRUE;
767 }
768 $type_msg = sprintf("[%s]", $entry['type']);
769 break;
770 default :
771 if (!$debug) {
772 // print nothing. exit cleanly.
773 return TRUE;
774 }
775 $type_msg = sprintf("[%s]", $entry['type']);
776 break;
777 }
778
779 // When running in backend mode, log messages are not displayed, as they will
780 // be returned in the JSON encoded associative array.
781 if (drush_get_context('DRUSH_BACKEND')) {
782 return $return;
783 }
784
785 $columns = drush_get_context('DRUSH_COLUMNS', 80);
786
787 $width[1] = 11;
788 // Append timer value.
789 if ($debug) {
790 $timer = sprintf('[%s sec]', round($entry['timestamp']-DRUSH_REQUEST_TIME, 3));
791 $entry['message'] = $entry['message'] . ' ' . $timer;
792 }
793
794 $width[0] = ($columns - 11);
795
796 $format = sprintf("%%-%ds%%%ds", $width[0], $width[1]);
797
798 // Place the status message right aligned with the top line of the error message.
799 $message = wordwrap($entry['message'], $width[0]);
800 $lines = explode("\n", $message);
801 $lines[0] = sprintf($format, $lines[0], $type_msg);
802 $message = implode("\n", $lines);
803 drush_print($message);
804 return $return;
805 }
806
807 // Log all timers for the request except standard page timer.
808 // Useful for migrate commands. Lets see if others find it useful.
809 // Called at end of request. @see drush.php
810 function drush_log_timers() {
811 global $timers;
812 foreach ((array)$timers as $name => $timerec) {
813 drush_log("Timer '$name' is " . sprintf('%s sec.', round(timer_read($name)/1000, 3)), 'timer');
814 }
815 }
816 /**
817 * Turn drupal_set_message errors into drush_log errors
818 */
819 function _drush_log_drupal_messages() {
820 if (function_exists('drupal_get_messages')) {
821
822 $messages = drupal_get_messages();
823
824 if (array_key_exists('error', $messages)) {
825 //Drupal message errors.
826 foreach ((array) $messages['error'] as $error) {
827 $error = strip_tags($error);
828 if (preg_match('/^warning: Cannot modify header information - headers already sent by /i', $error)) {
829 //This is a special case for an unavoidable warning
830 //that is generated by generating output before Drupal is bootstrapped.
831 //Simply ignore it.
832 continue;
833 }
834 elseif (preg_match('/^warning:/i', $error)) {
835 drush_log(preg_replace('/^warning: /i', '', $error), 'warning');
836 }
837 elseif (preg_match('/^notice:/i', $error)) {
838 drush_log(preg_replace('/^notice: /i', '', $error), 'notice');
839 }
840 elseif (preg_match('/^user warning:/i', $error)) {
841 // This is a special case. PHP logs sql errors as 'User Warnings', not errors.
842 drush_set_error('DRUSH_DRUPAL_ERROR_MESSAGE', preg_replace('/^user warning: /i', '', $error));
843 }
844 else {
845 drush_set_error('DRUSH_DRUPAL_ERROR_MESSAGE', $error);
846 }
847 }
848 }
849 }
850 }
851
852 /**
853 * Log the return value of Drupal hook_update_n functions.
854 *
855 * This is used during install and update to log the output
856 * of the update process to the logging system.
857 */
858 function _drush_log_update_sql($ret) {
859 if (sizeof($ret)) {
860 foreach ($ret as $info) {
861 if (is_array($info)) {
862 if (!$info['success']) {
863 drush_set_error('DRUPAL_UPDATE_FAILED', $info['query']);
864 }
865 else {
866 drush_log($info['query'], ($info['success']) ? 'success' : 'error');
867 }
868 }
869 }
870 }
871 }
872
873 /**
874 * @} End of "defgroup logging".
875 */
876
877 /**
878 * @name Error status definitions
879 * @{
880 * Error code definitions for interpreting the current error status.
881 * @see drush_set_error(), drush_get_error(), drush_get_error_log(), drush_cmp_error()
882 */
883
884 /** The command completed successfully. */
885 define('DRUSH_SUCCESS', 0);
886 /** The command could not be completed because the framework has specified errors that have occured. */
887 define('DRUSH_FRAMEWORK_ERROR', 1);
888 /** The command that was executed resulted in an application error,
889 The most commom causes for this is invalid PHP or a broken SSH
890 pipe when using drush_backend_invoke in a distributed manner. */
891 define('DRUSH_APPLICATION_ERROR', 255);
892
893 /**
894 * @} End of "name Error status defintions".
895 */
896
897 /**
898 * @defgroup errorhandling Managing errors that occur in the Drush framework.
899 * @{
900 * Functions that manage the current error status of the Drush framework.
901 *
902 * These functions operate by maintaining a static variable that is a equal to the constant DRUSH_FRAMEWORK_ERROR if an
903 * error has occurred.
904 * This error code is returned at the end of program execution, and provide the shell or calling application with
905 * more information on how to diagnose any problems that may have occurred.
906 */
907
908 /**
909 * Set an error code for the error handling system.
910 *
911 * @param error
912 * A text string identifying the type of error.
913 *
914 * @param message
915 * Optional. Error message to be logged. If no message is specified, hook_drush_help will be consulted,
916 * using a key of 'error:MY_ERROR_STRING'.
917 *
918 * @return
919 * Always returns FALSE, to allow you to return with false in the calling functions,
920 * such as <code>return drush_set_error('DRUSH_FRAMEWORK_ERROR')</code>
921 */
922 function drush_set_error($error, $message = null) {
923 $error_code =& drush_get_context('DRUSH_ERROR_CODE', DRUSH_SUCCESS);
924 $error_code = DRUSH_FRAMEWORK_ERROR;
925
926 $error_log =& drush_get_context('DRUSH_ERROR_LOG', array());
927
928 if (is_numeric($error)) {
929 $error = 'DRUSH_FRAMEWORK_ERROR';
930 }
931
932 $message = ($message) ? $message : drush_command_invoke_all('drush_help', 'error:' . $error);
933
934 if (is_array($message)) {
935 $message = implode("\n", $message);
936 }
937
938 $error_log[$error][] = $message;
939 drush_log(($message) ? $message : $error, 'error', $error);
940
941 return FALSE;
942 }
943
944 /**
945 * Return the current error handling status
946 *
947 * @return
948 * The current aggregate error status
949 */
950 function drush_get_error() {
951 return drush_get_context('DRUSH_ERROR_CODE', DRUSH_SUCCESS);
952 }
953
954 /**
955 * Return the current list of errors that have occurred.
956 *
957 * @return
958 * An associative array of error messages indexed by the type of message.
959 */
960 function drush_get_error_log() {
961 return drush_get_context('DRUSH_ERROR_LOG', array());
962 }
963
964 /**
965 * Check if a specific error status has been set.
966 *
967 * @param error
968 * A text string identifying the error that has occurred.
969 * @return
970 * TRUE if the specified error has been set, FALSE if not
971 */
972 function drush_cmp_error($error) {
973 $error_log = drush_get_error_log();
974
975 if (is_numeric($error)) {
976 $error = 'DRUSH_FRAMEWORK_ERROR';
977 }
978
979 return array_key_exists($error, $error_log);
980 }
981
982 /**
983 * Turn PHP error handling off.
984 *
985 * This is commonly used while bootstrapping Drupal for install
986 * or updates.
987 */
988 function drush_errors_off() {
989 $errors =& drush_get_context('DRUSH_ERROR_REPORTING', 0);
990 $errors = error_reporting(0);
991 ini_set('display_errors', FALSE);
992 }
993
994 /**
995 * Turn PHP error handling on.
996 */
997 function drush_errors_on() {
998 $errors =& drush_get_context('DRUSH_ERROR_REPORTING', E_ALL ^ E_NOTICE);
999 $errors = error_reporting($errors);
1000 ini_set('display_errors', TRUE);
1001 }
1002
1003 /**
1004 * @} End of "defgroup errorhandling".
1005 */
1006

  ViewVC Help
Powered by ViewVC 1.1.2