output.inc

  1. 8.0.x includes/output.inc
  2. 6.x includes/output.inc
  3. 7.x includes/output.inc
  4. 5.x includes/output.inc
  5. master includes/output.inc

Functions

Namesort ascending Description
_drush_format_table
find_legacy_dt_args Return an array containing all of the items in the input array that begin with a '!'.
dt Rudimentary replacement for Drupal API t() function.
drush_var_export Drupal-friendly var_export(). Taken from utility.inc in Drupal 8.
drush_table_column_autowidth Determine the best fit for column widths.
drush_select_output_fields Select the fields from the input array that should be output.
drush_select_fields Select the fields that should be used.
drush_rows_of_key_value_to_array_table Convert an array of data rows, where each row contains an associative array of key : value pairs, into a table suitable for processing by drush_print_table. The provided $header determines the order that the items will appear in the output. Only data…
drush_print_table Print a formatted table.
drush_print_r Prints an array or string.
drush_print_prompt Print a prompt -- that is, a message with no trailing newline.
drush_print_pipe Stores a message which is printed during drush_shutdown() if in compact mode.
drush_print_format Format some data and print it out. Respect --format option.
drush_print_file Print the contents of a file.
drush_print Prints a message with optional indentation. In general, drush_log($message, LogLevel::OK) is often a better choice than this function. That gets your confirmation message (for example) into the logs for this drush request. Consider that drush requests…
drush_output_get_selected_field Given a table array (an associative array of associative arrays), return an array of all of the values with the specified field name.
drush_lookup_field_by_path Return a specific item inside an array, as identified by the provided path.
drush_key_value_to_array_table Convert an associative array of key : value pairs into a table suitable for processing by drush_print_table.
drush_json_encode Converts a PHP variable into its Javascript equivalent.
drush_json_decode Converts an HTML-safe JSON string into its PHP equivalent.
drush_html_to_text Convert html to readable text. Compatible API to drupal_html_to_text, but less functional. Caller might prefer to call drupal_html_to_text if there is a bootstrapped Drupal site available.
drush_hide_empty_fields Hide any fields that are empty
drush_format_table Format a table of data.
drush_format Prepares a variable for printing. Loads the requested output formatter and uses it to process the provided input.

File

includes/output.inc
View source
  1. <?php
  2. use Drush\Log\LogLevel;
  3. /**
  4. * @defgroup outputfunctions Process output text.
  5. * @{
  6. */
  7. /**
  8. * Prints a message with optional indentation. In general,
  9. * drush_log($message, LogLevel::OK) is often a better choice than this function.
  10. * That gets your confirmation message (for example) into the logs for this
  11. * drush request. Consider that drush requests may be executed remotely and
  12. * non interactively.
  13. *
  14. * @param $message
  15. * The message to print.
  16. * @param $indent
  17. * The indentation (space chars)
  18. * @param $handle
  19. * File handle to write to. NULL will write
  20. * to standard output, STDERR will write to the standard
  21. * error. See http://php.net/manual/en/features.commandline.io-streams.php
  22. * @param $newline
  23. * Add a "\n" to the end of the output. Defaults to TRUE.
  24. */
  25. function drush_print($message = '', $indent = 0, $handle = NULL, $newline = TRUE) {
  26. $msg = str_repeat(' ', $indent) . (string)$message;
  27. if ($newline) {
  28. $msg .= "\n";
  29. }
  30. if (($charset = drush_get_option('output_charset')) && function_exists('iconv')) {
  31. $msg = iconv('UTF-8', $charset, $msg);
  32. }
  33. if (isset($handle)) {
  34. fwrite($handle, $msg);
  35. }
  36. else {
  37. print $msg;
  38. }
  39. }
  40. /**
  41. * Print a prompt -- that is, a message with no trailing newline.
  42. */
  43. function drush_print_prompt($message, $indent = 0, $handle = NULL) {
  44. drush_print($message, $indent, $handle, FALSE);
  45. }
  46. /**
  47. * Stores a message which is printed during drush_shutdown() if in compact mode.
  48. * @param $message
  49. * The message to print. If $message is an array,
  50. * then each element of the array is printed on a
  51. * separate line.
  52. */
  53. function drush_print_pipe($message = '') {
  54. $buffer = &drush_get_context('DRUSH_PIPE_BUFFER' , '');
  55. if (is_array($message)) {
  56. $message = implode("\n", $message) . "\n";
  57. }
  58. $buffer .= $message;
  59. }
  60. /**
  61. * Prints an array or string.
  62. * @param $array
  63. * The array to print.
  64. * @param $newline
  65. * Add a "\n" to the end of the output. Defaults to TRUE.
  66. */
  67. function drush_print_r($array, $handle = NULL, $newline = TRUE) {
  68. drush_print(print_r($array, TRUE), 0, $handle, $newline);
  69. }
  70. /**
  71. * Format some data and print it out. Respect --format option.
  72. */
  73. function drush_print_format($input, $default_format, $metadata = NULL) {
  74. drush_print(drush_format($input, $metadata, drush_get_option('format', $default_format)));
  75. }
  76. /**
  77. * Prepares a variable for printing. Loads the requested output
  78. * formatter and uses it to process the provided input.
  79. *
  80. * @param mixed $input
  81. * A variable.
  82. * @param string $metadata
  83. * Optional formatting metadata. Not used by all formats.
  84. * 'label' - text to label data with in some formats (e.g. export, config)
  85. * @param string $format
  86. * Optional format; defaults to print_r.
  87. * @return string
  88. * The variable formatted according to specified format.
  89. * Ready for drush_print().
  90. */
  91. function drush_format($input, $metadata = NULL, $format = NULL) {
  92. $output = '';
  93. // Look up the format and label, and fill in default values for metadata
  94. if (is_string($metadata)) {
  95. $metadata = array('label' => $metadata);
  96. }
  97. if (!is_array($metadata)) {
  98. $metadata = array();
  99. }
  100. $metadata += array(
  101. 'metameta' => array(),
  102. );
  103. if (isset($metadata['format'])) {
  104. // If the format is set in metadata, then it will
  105. // override whatever is passed in via the $format parameter.
  106. $format = $metadata['format'];
  107. }
  108. if (!isset($format)) {
  109. // TODO: we shouldn't ever call drush_get_option here.
  110. // Get rid of this once we confirm that there are no
  111. // callers that still need it.
  112. $format = drush_get_option('format', 'print-r');
  113. }
  114. $formatter = drush_load_engine('outputformat', $format);
  115. if ($formatter) {
  116. if ($formatter === TRUE) {
  117. return drush_set_error(dt('No outputformat class defined for !format', array('!format' => $format)));
  118. }
  119. $output = $formatter->process($input, $metadata);
  120. }
  121. return $output;
  122. }
  123. /**
  124. * Rudimentary replacement for Drupal API t() function.
  125. *
  126. * @param string
  127. * String to process, possibly with replacement item.
  128. * @param array
  129. * An associative array of replacement items.
  130. *
  131. * @return
  132. * The processed string.
  133. *
  134. * @see t()
  135. */
  136. function dt($string, $args = array()) {
  137. $output = NULL;
  138. if (function_exists('t') && drush_drupal_major_version() == 7) {
  139. $output = t($string, $args);
  140. }
  141. // The language system requires a working container which has the string
  142. // translation service.
  143. else if (drush_drupal_major_version() >= 8 && \Drupal::hasService('string_translation')) {
  144. // Drupal 8 removes !var replacements, creating a user-level error when
  145. // these are used, so we'll pre-replace these before calling translate().
  146. $legacy_args = find_legacy_dt_args($args);
  147. $string = strtr($string, $legacy_args);
  148. // Remove the legacy replacements.
  149. foreach (array_keys($legacy_args) as $legacy_arg_key) {
  150. unset($args[$legacy_arg_key]);
  151. }
  152. $output = \Drupal::translation()->translate($string, $args);
  153. }
  154. else if (function_exists('t') && drush_drupal_major_version() <= 7 && function_exists('theme')) {
  155. $output = t($string, $args);
  156. }
  157. // If Drupal's t() function unavailable.
  158. if (!isset($output)) {
  159. if (!empty($args)) {
  160. $output = strtr($string, $args);
  161. }
  162. else {
  163. $output = $string;
  164. }
  165. }
  166. return $output;
  167. }
  168. /**
  169. * Return an array containing all of the items in the input
  170. * array that begin with a '!'.
  171. *
  172. * Since array_filter operates on the array value, and there
  173. * is no corresponding function that operates on the key, we
  174. * will flip the array twice to filter on the key.
  175. */
  176. function find_legacy_dt_args($args) {
  177. $legacy_args = [];
  178. foreach ($args as $arg => $replacement) {
  179. if ($arg[0] == '!') {
  180. $legacy_args[$arg] = $replacement;
  181. }
  182. }
  183. return $legacy_args;
  184. }
  185. /**
  186. * Convert html to readable text. Compatible API to
  187. * drupal_html_to_text, but less functional. Caller
  188. * might prefer to call drupal_html_to_text if there
  189. * is a bootstrapped Drupal site available.
  190. *
  191. * @param string $html
  192. * The html text to convert.
  193. *
  194. * @return string
  195. * The plain-text representation of the input.
  196. */
  197. function drush_html_to_text($html, $allowed_tags = NULL) {
  198. $replacements = array(
  199. '<hr>' => '------------------------------------------------------------------------------',
  200. '<li>' => ' * ',
  201. '<h1>' => '===== ',
  202. '</h1>' => ' =====',
  203. '<h2>' => '---- ',
  204. '</h2>' => ' ----',
  205. '<h3>' => '::: ',
  206. '</h3>' => ' :::',
  207. '<br/>' => "\n",
  208. );
  209. $text = str_replace(array_keys($replacements), array_values($replacements), $html);
  210. return html_entity_decode(preg_replace('/ *<[^>]*> */', ' ', $text));
  211. }
  212. /**
  213. * Print a formatted table.
  214. *
  215. * @param $rows
  216. * The rows to print.
  217. * @param $header
  218. * If TRUE, the first line will be treated as table header.
  219. * @param $widths
  220. * An associative array whose keys are column IDs and values are widths of each column (in characters).
  221. * If not specified this will be determined automatically, based on a "best fit" algorithm.
  222. * @param $handle
  223. * File handle to write to. NULL will write
  224. * to standard output, STDERR will write to the standard
  225. * error. See http://php.net/manual/en/features.commandline.io-streams.php
  226. * @return $tbl
  227. * Use $tbl->getTable() to get the output from the return value.
  228. */
  229. function drush_print_table($rows, $header = FALSE, $widths = array(), $handle = NULL) {
  230. $tbl = _drush_format_table($rows, $header, $widths);
  231. $output = $tbl->getTable();
  232. if (!stristr(PHP_OS, 'WIN')) {
  233. $output = str_replace("\r\n", PHP_EOL, $output);
  234. }
  235. drush_print(rtrim($output), 0, $handle);
  236. return $tbl;
  237. }
  238. /**
  239. * Format a table of data.
  240. *
  241. * @param $rows
  242. * The rows to print.
  243. * @param $header
  244. * If TRUE, the first line will be treated as table header.
  245. * @param $widths
  246. * An associative array whose keys are column IDs and values are widths of each column (in characters).
  247. * If not specified this will be determined automatically, based on a "best fit" algorithm.
  248. * @param array $console_table_options
  249. * An array that is passed along when constructing a Console_Table instance.
  250. * @return $output
  251. * The formatted output.
  252. */
  253. function drush_format_table($rows, $header = FALSE, $widths = array(), $console_table_options = array()) {
  254. $tbl = _drush_format_table($rows, $header, $widths, $console_table_options);
  255. $output = $tbl->getTable();
  256. if (!drush_is_windows()) {
  257. $output = str_replace("\r\n", PHP_EOL, $output);
  258. }
  259. return $output;
  260. }
  261. function _drush_format_table($rows, $header = FALSE, $widths = array(), $console_table_options = array()) {
  262. // Add defaults.
  263. $tbl = new ReflectionClass('Console_Table');
  264. $console_table_options += array(CONSOLE_TABLE_ALIGN_LEFT , '');
  265. $tbl = $tbl->newInstanceArgs($console_table_options);
  266. $auto_widths = drush_table_column_autowidth($rows, $widths);
  267. // Do wordwrap on all cells.
  268. $newrows = array();
  269. foreach ($rows as $rowkey => $row) {
  270. foreach ($row as $col_num => $cell) {
  271. $newrows[$rowkey][$col_num] = wordwrap($cell, $auto_widths[$col_num], "\n", TRUE);
  272. if (isset($widths[$col_num])) {
  273. $newrows[$rowkey][$col_num] = str_pad($newrows[$rowkey][$col_num], $widths[$col_num]);
  274. }
  275. }
  276. }
  277. if ($header) {
  278. $headers = array_shift($newrows);
  279. $tbl->setHeaders($headers);
  280. }
  281. $tbl->addData($newrows);
  282. return $tbl;
  283. }
  284. /**
  285. * Convert an associative array of key : value pairs into
  286. * a table suitable for processing by drush_print_table.
  287. *
  288. * @param $keyvalue_table
  289. * An associative array of key : value pairs.
  290. * @param $metadata
  291. * 'key-value-item': If the value is an array, then
  292. * the item key determines which item from the value
  293. * will appear in the output.
  294. * @return
  295. * An array of arrays, where the keys from the input
  296. * array are stored in the first column, and the values
  297. * are stored in the third. A second colum is created
  298. * specifically to hold the ':' separator.
  299. */
  300. function drush_key_value_to_array_table($keyvalue_table, $metadata = array()) {
  301. if (!is_array($keyvalue_table)) {
  302. return drush_set_error('DRUSH_INVALID_FORMAT', dt("Data not compatible with selected key-value output format."));
  303. }
  304. if (!is_array($metadata)) {
  305. $metadata = array('key-value-item' => $metadata);
  306. }
  307. $item_key = array_key_exists('key-value-item', $metadata) ? $metadata['key-value-item'] : NULL;
  308. $metadata += array(
  309. 'format' => 'list',
  310. 'separator' => ' ',
  311. );
  312. $table = array();
  313. foreach ($keyvalue_table as $key => $value) {
  314. if (isset($value)) {
  315. if (is_array($value) && isset($item_key)) {
  316. $value = $value[$item_key];
  317. }
  318. // We should only have simple values here, but if
  319. // we don't, use drush_format() to flatten as a fallback.
  320. if (is_array($value)) {
  321. $value = drush_format($value, $metadata, 'list');
  322. }
  323. }
  324. if (isset($metadata['include-field-labels']) && !$metadata['include-field-labels']) {
  325. $table[] = array(isset($value) ? $value : '');
  326. }
  327. elseif (isset($value)) {
  328. $table[] = array($key, ' :', $value);
  329. }
  330. else {
  331. $table[] = array($key . ':', '', '');
  332. }
  333. }
  334. return $table;
  335. }
  336. /**
  337. * Select the fields that should be used.
  338. */
  339. function drush_select_fields($all_field_labels, $fields, $strict = TRUE) {
  340. $field_labels = array();
  341. foreach ($fields as $field) {
  342. if (array_key_exists($field, $all_field_labels)) {
  343. $field_labels[$field] = $all_field_labels[$field];
  344. }
  345. else {
  346. // Allow the user to select fields via their human-readable names.
  347. // This is less convenient than the field name (since the human-readable
  348. // names may contain spaces, and must therefore be quoted), but these are
  349. // the values that the user sees in the command output. n.b. the help
  350. // text lists fields by their more convenient machine names.
  351. $key = array_search(strtolower($field), array_map('strtolower', $all_field_labels));
  352. if ($key !== FALSE) {
  353. $field_labels[$key] = $all_field_labels[$key];
  354. }
  355. elseif (!$strict) {
  356. $field_labels[$field] = $field;
  357. }
  358. }
  359. }
  360. return $field_labels;
  361. }
  362. /**
  363. * Select the fields from the input array that should be output.
  364. *
  365. * @param $input
  366. * An associative array of key:value pairs to be output
  367. * @param $fields
  368. * An associative array that maps FROM a field in $input
  369. * TO the corresponding field name in $output.
  370. * @param $mapping
  371. * An associative array that maps FROM a field in $fields
  372. * TO the actual field in $input to use in the preceeding
  373. * translation described above.
  374. * @return
  375. * The input array, re-ordered and re-keyed per $fields
  376. */
  377. function drush_select_output_fields($input, $fields, $mapping = array(), $default_value = NULL) {
  378. $result = array();
  379. if (empty($fields)) {
  380. $result = $input;
  381. }
  382. else {
  383. foreach ($fields as $key => $label) {
  384. $value = drush_lookup_field_by_path($input, $key, $mapping, $default_value);
  385. if (isset($value)) {
  386. $result[$label] = $value;
  387. }
  388. }
  389. }
  390. return $result;
  391. }
  392. /**
  393. * Return a specific item inside an array, as identified
  394. * by the provided path.
  395. *
  396. * @param $input:
  397. * An array of items, potentially multiple layers deep.
  398. * @param $path:
  399. * A specifier of array keys, either in an array or separated by
  400. * a '/', that list the elements of the array to access. This
  401. * works much like a very simple version of xpath for arrays, with
  402. * all items being treated identically (like elements).
  403. * @param $mapping:
  404. * (optional) An array whose keys may correspond to the $path parameter and
  405. * whose values are the corresponding paths to be used in $input.
  406. *
  407. * Example 1:
  408. *
  409. * $input = array('#name' => 'site.dev', '#id' => '222');
  410. * $path = '#name';
  411. * result: 'site.dev';
  412. *
  413. * Example 2:
  414. *
  415. * $input = array('ca' => array('sf' => array('mission'=>array('1700'=>'woodward'))));
  416. * $path = 'ca/sf/mission/1701';
  417. * result: 'woodward'
  418. *
  419. * Example 3:
  420. *
  421. * $input = array('#name' => 'site.dev', '#id' => '222');
  422. * $path = 'name';
  423. * $mapping = array('name' => '#name');
  424. * result: 'site.dev';
  425. */
  426. function drush_lookup_field_by_path($input, $path, $mapping = array(), $default_value = NULL) {
  427. $result = '';
  428. if (isset($mapping[$path])) {
  429. $path = $mapping[$path];
  430. }
  431. if (!is_array($path)) {
  432. $parts = explode('/', $path);
  433. }
  434. if (!empty($parts)) {
  435. $result = $input;
  436. foreach ($parts as $key) {
  437. if ((is_array($result)) && (isset($result[$key]))) {
  438. $result = $result[$key];
  439. }
  440. else {
  441. return $default_value;
  442. }
  443. }
  444. }
  445. return $result;
  446. }
  447. /**
  448. * Given a table array (an associative array of associative arrays),
  449. * return an array of all of the values with the specified field name.
  450. */
  451. function drush_output_get_selected_field($input, $field_name, $default_value = '') {
  452. $result = array();
  453. foreach ($input as $key => $data) {
  454. if (is_array($data) && isset($data[$field_name])) {
  455. $result[] = $data[$field_name];
  456. }
  457. else {
  458. $result[] = $default_value;
  459. }
  460. }
  461. return $result;
  462. }
  463. /**
  464. * Hide any fields that are empty
  465. */
  466. function drush_hide_empty_fields($input, $fields) {
  467. $has_data = array();
  468. foreach ($input as $key => $data) {
  469. foreach ($fields as $field => $label) {
  470. if (isset($data[$field]) && !empty($data[$field])) {
  471. $has_data[$field] = TRUE;
  472. }
  473. }
  474. }
  475. foreach ($fields as $field => $label) {
  476. if (!isset($has_data[$field])) {
  477. unset($fields[$field]);
  478. }
  479. }
  480. return $fields;
  481. }
  482. /**
  483. * Convert an array of data rows, where each row contains an
  484. * associative array of key : value pairs, into
  485. * a table suitable for processing by drush_print_table.
  486. * The provided $header determines the order that the items
  487. * will appear in the output. Only data items listed in the
  488. * header will be placed in the output.
  489. *
  490. * @param $rows_of_keyvalue_table
  491. * array(
  492. * 'row1' => array('col1' => 'data', 'col2' => 'data'),
  493. * 'row2' => array('col1' => 'data', 'col2' => 'data'),
  494. * )
  495. * @param $header
  496. * array('col1' => 'Column 1 Label', 'col2' => 'Column 2 Label')
  497. * @param $metadata
  498. * (optional) An array of special options, all optional:
  499. * - strip-tags: call the strip_tags function on the data
  500. * before placing it in the table
  501. * - concatenate-columns: an array of:
  502. * - dest-col: array('src-col1', 'src-col2')
  503. * Appends all of the src columns with whatever is
  504. * in the destination column. Appended columns are
  505. * separated by newlines.
  506. * - transform-columns: an array of:
  507. * - dest-col: array('from' => 'to'),
  508. * Transforms any occurance of 'from' in 'dest-col' to 'to'.
  509. * - format-cell: Drush output format name to use to format
  510. * any cell that is an array.
  511. * - process-cell: php function name to use to process
  512. * any cell that is an array.
  513. * - field-mappings: an array whose keys are some or all of the keys in
  514. * $header and whose values are the corresponding keys to use when
  515. * indexing the values of $rows_of_keyvalue_table.
  516. * @return
  517. * An array of arrays
  518. */
  519. function drush_rows_of_key_value_to_array_table($rows_of_keyvalue_table, $header, $metadata) {
  520. if (isset($metadata['hide-empty-fields'])) {
  521. $header = drush_hide_empty_fields($rows_of_keyvalue_table, $header);
  522. }
  523. if (empty($header)) {
  524. $first = (array)reset($rows_of_keyvalue_table);
  525. $keys = array_keys($first);
  526. $header = array_combine($keys, $keys);
  527. }
  528. $table = array(array_values($header));
  529. if (isset($rows_of_keyvalue_table) && is_array($rows_of_keyvalue_table) && !empty($rows_of_keyvalue_table)) {
  530. foreach ($rows_of_keyvalue_table as $row_index => $row_data) {
  531. $row_data = (array)$row_data;
  532. $row = array();
  533. foreach ($header as $column_key => $column_label) {
  534. $data = drush_lookup_field_by_path($row_data, $column_key, $metadata['field-mappings']);
  535. if (array_key_exists('transform-columns', $metadata)) {
  536. foreach ($metadata['transform-columns'] as $dest_col => $transformations) {
  537. if ($dest_col == $column_key) {
  538. $data = str_replace(array_keys($transformations), array_values($transformations), $data);
  539. }
  540. }
  541. }
  542. if (array_key_exists('concatenate-columns', $metadata)) {
  543. foreach ($metadata['concatenate-columns'] as $dest_col => $src_cols) {
  544. if ($dest_col == $column_key) {
  545. $data = '';
  546. if (!is_array($src_cols)) {
  547. $src_cols = array($src_cols);
  548. }
  549. foreach($src_cols as $src) {
  550. if (array_key_exists($src, $row_data) && !empty($row_data[$src])) {
  551. if (!empty($data)) {
  552. $data .= "\n";
  553. }
  554. $data .= $row_data[$src];
  555. }
  556. }
  557. }
  558. }
  559. }
  560. if (array_key_exists('format-cell', $metadata) && is_array($data)) {
  561. $data = drush_format($data, array(), $metadata['format-cell']);
  562. }
  563. if (array_key_exists('process-cell', $metadata) && is_array($data)) {
  564. $data = $metadata['process-cell']($data, $metadata);
  565. }
  566. if (array_key_exists('strip-tags', $metadata)) {
  567. $data = strip_tags($data);
  568. }
  569. $row[] = $data;
  570. }
  571. $table[] = $row;
  572. }
  573. }
  574. return $table;
  575. }
  576. /**
  577. * Determine the best fit for column widths.
  578. *
  579. * @param $rows
  580. * The rows to use for calculations.
  581. * @param $widths
  582. * Manually specified widths of each column (in characters) - these will be
  583. * left as is.
  584. */
  585. function drush_table_column_autowidth($rows, $widths) {
  586. $auto_widths = $widths;
  587. // First we determine the distribution of row lengths in each column.
  588. // This is an array of descending character length keys (i.e. starting at
  589. // the rightmost character column), with the value indicating the number
  590. // of rows where that character column is present.
  591. $col_dist = array();
  592. foreach ($rows as $rowkey => $row) {
  593. foreach ($row as $col_id => $cell) {
  594. if (empty($widths[$col_id])) {
  595. $length = strlen($cell);
  596. if ($length == 0) {
  597. $col_dist[$col_id][0] = 0;
  598. }
  599. while ($length > 0) {
  600. if (!isset($col_dist[$col_id][$length])) {
  601. $col_dist[$col_id][$length] = 0;
  602. }
  603. $col_dist[$col_id][$length]++;
  604. $length--;
  605. }
  606. }
  607. }
  608. }
  609. foreach ($col_dist as $col_id => $count) {
  610. // Sort the distribution in decending key order.
  611. krsort($col_dist[$col_id]);
  612. // Initially we set all columns to their "ideal" longest width
  613. // - i.e. the width of their longest column.
  614. $auto_widths[$col_id] = max(array_keys($col_dist[$col_id]));
  615. }
  616. // We determine what width we have available to use, and what width the
  617. // above "ideal" columns take up.
  618. $available_width = drush_get_context('DRUSH_COLUMNS', 80) - (count($auto_widths) * 2);
  619. $auto_width_current = array_sum($auto_widths);
  620. // If we need to reduce a column so that we can fit the space we use this
  621. // loop to figure out which column will cause the "least wrapping",
  622. // (relative to the other columns) and reduce the width of that column.
  623. while ($auto_width_current > $available_width) {
  624. $count = 0;
  625. $width = 0;
  626. foreach ($col_dist as $col_id => $counts) {
  627. // If we are just starting out, select the first column.
  628. if ($count == 0 ||
  629. // OR: if this column would cause less wrapping than the currently
  630. // selected column, then select it.
  631. (current($counts) < $count) ||
  632. // OR: if this column would cause the same amount of wrapping, but is
  633. // longer, then we choose to wrap the longer column (proportionally
  634. // less wrapping, and helps avoid triple line wraps).
  635. (current($counts) == $count && key($counts) > $width)) {
  636. // Select the column number, and record the count and current width
  637. // for later comparisons.
  638. $column = $col_id;
  639. $count = current($counts);
  640. $width = key($counts);
  641. }
  642. }
  643. if ($width <= 1) {
  644. // If we have reached a width of 1 then give up, so wordwrap can still progress.
  645. break;
  646. }
  647. // Reduce the width of the selected column.
  648. $auto_widths[$column]--;
  649. // Reduce our overall table width counter.
  650. $auto_width_current--;
  651. // Remove the corresponding data from the disctribution, so next time
  652. // around we use the data for the row to the left.
  653. unset($col_dist[$column][$width]);
  654. }
  655. return $auto_widths;
  656. }
  657. /**
  658. * Print the contents of a file.
  659. *
  660. * @param string $file
  661. * Full path to a file.
  662. */
  663. function drush_print_file($file) {
  664. // Don't even bother to print the file in --no mode
  665. if (drush_get_context('DRUSH_NEGATIVE')) {
  666. return;
  667. }
  668. if ((substr($file,-4) == ".htm") || (substr($file,-5) == ".html")) {
  669. $tmp_file = drush_tempnam(basename($file));
  670. file_put_contents($tmp_file, drush_html_to_text(file_get_contents($file)));
  671. $file = $tmp_file;
  672. }
  673. // Do not wait for user input in --yes or --pipe modes
  674. if (drush_get_context('DRUSH_PIPE')) {
  675. drush_print_pipe(file_get_contents($file));
  676. }
  677. elseif (drush_get_context('DRUSH_AFFIRMATIVE')) {
  678. drush_print(file_get_contents($file));
  679. }
  680. elseif (drush_shell_exec_interactive("less %s", $file)) {
  681. return;
  682. }
  683. elseif (drush_shell_exec_interactive("more %s", $file)) {
  684. return;
  685. }
  686. else {
  687. drush_print(file_get_contents($file));
  688. }
  689. }
  690. /**
  691. * Converts a PHP variable into its Javascript equivalent.
  692. *
  693. * We provide a copy of D7's drupal_json_encode since this function is
  694. * unavailable on earlier versions of Drupal.
  695. *
  696. * @see drupal_json_decode()
  697. * @ingroup php_wrappers
  698. */
  699. function drush_json_encode($var) {
  700. if (version_compare(phpversion(), '5.4.0', '>=')) {
  701. $json = json_encode($var, JSON_PRETTY_PRINT);
  702. }
  703. else {
  704. $json = json_encode($var);
  705. }
  706. // json_encode() does not escape <, > and &, so we do it with str_replace().
  707. return str_replace(array('<', '>', '&'), array('\u003c', '\u003e', '\u0026'), $json);
  708. }
  709. /**
  710. * Converts an HTML-safe JSON string into its PHP equivalent.
  711. *
  712. * We provide a copy of D7's drupal_json_decode since this function is
  713. * unavailable on earlier versions of Drupal.
  714. *
  715. * @see drupal_json_encode()
  716. * @ingroup php_wrappers
  717. */
  718. function drush_json_decode($var) {
  719. return json_decode($var, TRUE);
  720. }
  721. /**
  722. * Drupal-friendly var_export(). Taken from utility.inc in Drupal 8.
  723. *
  724. * @param $var
  725. * The variable to export.
  726. * @param $prefix
  727. * A prefix that will be added at the beginning of every lines of the output.
  728. *
  729. * @return
  730. * The variable exported in a way compatible to Drupal's coding standards.
  731. */
  732. function drush_var_export($var, $prefix = '') {
  733. if (is_array($var)) {
  734. if (empty($var)) {
  735. $output = 'array()';
  736. }
  737. else {
  738. $output = "array(\n";
  739. // Don't export keys if the array is non associative.
  740. $export_keys = array_values($var) != $var;
  741. foreach ($var as $key => $value) {
  742. $output .= ' ' . ($export_keys ? drush_var_export($key) . ' => ' : '') . drush_var_export($value, ' ', FALSE) . ",\n";
  743. }
  744. $output .= ')';
  745. }
  746. }
  747. elseif (is_bool($var)) {
  748. $output = $var ? 'TRUE' : 'FALSE';
  749. }
  750. elseif (is_string($var)) {
  751. $line_safe_var = str_replace("\n", '\n', $var);
  752. if (strpos($var, "\n") !== FALSE || strpos($var, "'") !== FALSE) {
  753. // If the string contains a line break or a single quote, use the
  754. // double quote export mode. Encode backslash and double quotes and
  755. // transform some common control characters.
  756. $var = str_replace(array('\\', '"', "\n", "\r", "\t"), array('\\\\', '\"', '\n', '\r', '\t'), $var);
  757. $output = '"' . $var . '"';
  758. }
  759. else {
  760. $output = "'" . $var . "'";
  761. }
  762. }
  763. elseif (is_object($var) && get_class($var) === 'stdClass') {
  764. // var_export() will export stdClass objects using an undefined
  765. // magic method __set_state() leaving the export broken. This
  766. // workaround avoids this by casting the object as an array for
  767. // export and casting it back to an object when evaluated.
  768. $output = '(object) ' . drush_var_export((array) $var, $prefix);
  769. }
  770. else {
  771. $output = var_export($var, TRUE);
  772. }
  773. if ($prefix) {
  774. $output = str_replace("\n", "\n$prefix", $output);
  775. }
  776. return $output;
  777. }
  778. /**
  779. * @} End of "defgroup outputfunctions".
  780. */