make.utilities.inc

  1. 8.0.x commands/make/make.utilities.inc
  2. 6.x commands/make/make.utilities.inc
  3. 7.x commands/make/make.utilities.inc
  4. 5.x commands/make/make.utilities.inc
  5. master commands/make/make.utilities.inc

General utility functions for Drush Make.

Functions

Namesort descending Description
make_apply_defaults Apply any defaults.
make_clean_tmp Removes the temporary build directory. On failed builds, this is handled by drush_register_file_for_deletion().
make_error Logs an error unless the --force-complete command line option is specified.
make_get_data Get data based on the source.
make_md5 Calculate a cksum on each file in the build, and md5 the resulting hashes.
make_normalize_info Expand shorthand elements, so that we have an associative array.
make_parse_info_file Helper function to parse a makefile and prune projects.
make_prepare_install Prepare a Drupal installation, copying default.settings.php to settings.php.
make_prune_info_file Remove entries in the info file in accordance with the options passed in. Entries are either explicitly 'allowed' (with the $include_only parameter) in which case all *other* entries will be excluded.
make_safe_path Checks an attribute's path to ensure it's not maliciously crafted.
make_tar @todo drush_archive_dump() also makes a tar. Consolidate?
make_tmp Find, and possibly create, a temporary directory.
make_validate_info_file Validate the make file.
make_valid_url Verify the syntax of the given URL.
_get_working_copy_option Gather any working copy options.
_make_determine_format Given data from stdin, determine format.
_make_get_include_path Helper function to determine the proper path for an include makefile.
_make_is_override_allowed Check if makefile overrides are allowed
_make_merge_includes_recursively Helper function to merge includes recursively.
_make_parse_info_file Parse makefile recursively.

File

commands/make/make.utilities.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * General utility functions for Drush Make.
  5. */
  6. use Drush\Log\LogLevel;
  7. use Drush\Make\Parser\ParserIni;
  8. use Drush\Make\Parser\ParserYaml;
  9. /**
  10. * Helper function to parse a makefile and prune projects.
  11. */
  12. function make_parse_info_file($makefile) {
  13. $info = _make_parse_info_file($makefile);
  14. // Support making just a portion of a make file.
  15. $include_only = array(
  16. 'projects' => array_filter(drush_get_option_list('projects')),
  17. 'libraries' => array_filter(drush_get_option_list('libraries')),
  18. );
  19. $info = make_prune_info_file($info, $include_only);
  20. if ($info === FALSE || ($info = make_validate_info_file($info)) === FALSE) {
  21. return FALSE;
  22. }
  23. return $info;
  24. }
  25. /**
  26. * Parse makefile recursively.
  27. */
  28. function _make_parse_info_file($makefile, $element = 'includes') {
  29. if (!($data = make_get_data($makefile))) {
  30. return drush_set_error('MAKE_INVALID_MAKE_FILE', dt('Invalid or empty make file: !makefile', array('!makefile' => $makefile)));
  31. }
  32. // $info['format'] will specify the determined format.
  33. $info = _make_determine_format($data);
  34. // Set any allowed options.
  35. if (!empty($info['options'])) {
  36. foreach ($info['options'] as $key => $value) {
  37. if (_make_is_override_allowed($key)) {
  38. // n.b. 'custom' context has lower priority than 'cli', so
  39. // options entered on the command line will "mask" makefile options.
  40. drush_set_option($key, $value, 'custom');
  41. }
  42. }
  43. }
  44. // Include any makefiles specified on the command line.
  45. if ($include_makefiles = drush_get_option_list('includes', FALSE)) {
  46. drush_unset_option('includes'); // Avoid infinite loop.
  47. $info['includes'] = is_array($info['includes']) ? $info['includes'] : array();
  48. foreach ($include_makefiles as $include_make) {
  49. if (!array_search($include_make, $info['includes'])) {
  50. $info['includes'][] = $include_make;
  51. }
  52. }
  53. }
  54. // Override elements with values from makefiles specified on the command line.
  55. if ($overrides = drush_get_option_list('overrides', FALSE)) {
  56. drush_unset_option('overrides'); // Avoid infinite loop.
  57. $info['overrides'] = is_array($info['overrides']) ? $info['overrides'] : array();
  58. foreach ($overrides as $override) {
  59. if (!array_search($override, $info['overrides'])) {
  60. $info['overrides'][] = $override;
  61. }
  62. }
  63. }
  64. $info = _make_merge_includes_recursively($info, $makefile);
  65. $info = _make_merge_includes_recursively($info, $makefile, 'overrides');
  66. return $info;
  67. }
  68. /**
  69. * Helper function to merge includes recursively.
  70. */
  71. function _make_merge_includes_recursively($info, $makefile, $element = 'includes') {
  72. if (!empty($info[$element])) {
  73. if (is_array($info[$element])) {
  74. $includes = array();
  75. foreach ($info[$element] as $key => $include) {
  76. if (!empty($include)) {
  77. if (!$include_makefile = _make_get_include_path($include, $makefile)) {
  78. return make_error('BUILD_ERROR', dt("Cannot determine include file location: !include", array('!include' => $include)));
  79. }
  80. if ($element == 'overrides') {
  81. $info = array_replace_recursive($info, _make_parse_info_file($include_makefile, $element));
  82. }
  83. else {
  84. $info = array_replace_recursive(_make_parse_info_file($include_makefile), $info);
  85. }
  86. unset($info[$element][$key]);
  87. // Move core back to the top of the list, where
  88. // make_generate_from_makefile() expects it.
  89. if (!empty($info['projects'])) {
  90. array_reverse($info['projects']);
  91. }
  92. }
  93. }
  94. }
  95. }
  96. // Ensure $info['projects'] is an associative array, so that we can merge
  97. // includes properly.
  98. make_normalize_info($info);
  99. return $info;
  100. }
  101. /**
  102. * Helper function to determine the proper path for an include makefile.
  103. */
  104. function _make_get_include_path($include, $makefile) {
  105. if (is_array($include) && $include['download']['type'] = 'git') {
  106. $tmp_dir = make_tmp();
  107. make_download_git($include['makefile'], $include['download']['type'], $include['download'], $tmp_dir);
  108. $include_makefile = $tmp_dir . '/' . $include['makefile'];
  109. }
  110. elseif (is_string($include)) {
  111. $include_path = dirname($makefile);
  112. if (make_valid_url($include, TRUE)) {
  113. $include_makefile = $include;
  114. }
  115. elseif (file_exists($include_path . '/' . $include)) {
  116. $include_makefile = $include_path . '/' . $include;
  117. }
  118. elseif (file_exists($include)) {
  119. $include_makefile = $include;
  120. }
  121. else {
  122. return make_error('BUILD_ERROR', dt("Include file missing: !include", array('!include' => $include)));
  123. }
  124. }
  125. else {
  126. return FALSE;
  127. }
  128. return $include_makefile;
  129. }
  130. /**
  131. * Expand shorthand elements, so that we have an associative array.
  132. */
  133. function make_normalize_info(&$info) {
  134. if (isset($info['projects'])) {
  135. foreach($info['projects'] as $key => $project) {
  136. if (is_numeric($key) && is_string($project)) {
  137. unset($info['projects'][$key]);
  138. $info['projects'][$project] = array(
  139. 'version' => '',
  140. );
  141. }
  142. if (is_string($key) && is_numeric($project)) {
  143. $info['projects'][$key] = array(
  144. 'version' => $project,
  145. );
  146. }
  147. }
  148. }
  149. }
  150. /**
  151. * Remove entries in the info file in accordance with the options passed in.
  152. * Entries are either explicitly 'allowed' (with the $include_only parameter) in
  153. * which case all *other* entries will be excluded.
  154. *
  155. * @param array $info
  156. * A parsed info file.
  157. *
  158. * @param array $include_only
  159. * (Optional) Array keyed by entry type (e.g. 'libraries') against an array of
  160. * allowed keys for that type. The special value '*' means 'all entries of
  161. * this type'. If this parameter is omitted, no entries will be excluded.
  162. *
  163. * @return array
  164. * The $info array, pruned if necessary.
  165. */
  166. function make_prune_info_file($info, $include_only = array()) {
  167. // We may get passed FALSE in some cases.
  168. // Also we cannot prune an empty array, so no point in this code running!
  169. if (empty($info)) {
  170. return $info;
  171. }
  172. // We will accrue an explanation of our activities here.
  173. $msg = array();
  174. $msg['scope'] = dt("Drush make restricted to the following entries:");
  175. $pruned = FALSE;
  176. if (count(array_filter($include_only))) {
  177. $pruned = TRUE;
  178. foreach ($include_only as $type => $keys) {
  179. if (!isset($info[$type])) {
  180. continue;
  181. }
  182. // For translating
  183. // dt("Projects");
  184. // dt("Libraries");
  185. $type_title = dt(ucfirst($type));
  186. // Handle the special '*' value.
  187. if (in_array('*', $keys)) {
  188. $msg[$type] = dt("!entry_type: <All>", array('!entry_type' => $type_title));
  189. }
  190. // Handle a (possibly empty) array of keys to include/exclude.
  191. else {
  192. $info[$type] = array_intersect_key($info[$type], array_fill_keys($keys, 1));
  193. unset($msg[$type]);
  194. if (!empty($info[$type])) {
  195. $msg[$type] = dt("!entry_type: !make_entries", array('!entry_type' => $type_title, '!make_entries' => implode(', ', array_keys($info[$type]))));
  196. }
  197. }
  198. }
  199. }
  200. if ($pruned) {
  201. // Make it clear to the user what's going on.
  202. drush_log(implode("\n", $msg), LogLevel::OK);
  203. // Throw an error if these restrictions reduced the make to nothing.
  204. if (empty($info['projects']) && empty($info['libraries'])) {
  205. // This error mentions the options explicitly to make it as clear as
  206. // possible to the user why this error has occurred.
  207. make_error('BUILD_ERROR', dt("All projects and libraries have been excluded. Review the 'projects' and 'libraries' options."));
  208. }
  209. }
  210. return $info;
  211. }
  212. /**
  213. * Validate the make file.
  214. */
  215. function make_validate_info_file($info) {
  216. // Assume no errors to start.
  217. $errors = FALSE;
  218. if (empty($info['core'])) {
  219. make_error('BUILD_ERROR', dt("The 'core' attribute is required"));
  220. $errors = TRUE;
  221. }
  222. // Standardize on core.
  223. elseif (preg_match('/^(\d+)(\.(x|(\d+)(-[a-z0-9]+)?))?$/', $info['core'], $matches)) {
  224. // An exact version of core has been specified, so pass that to an
  225. // internal variable for storage.
  226. if (isset($matches[4])) {
  227. $info['core_release'] = $info['core'];
  228. }
  229. // Format the core attribute consistently.
  230. $info['core'] = $matches[1] . '.x';
  231. }
  232. else {
  233. make_error('BUILD_ERROR', dt("The 'core' attribute !core has an incorrect format.", array('!core' => $info['core'])));
  234. $errors = TRUE;
  235. }
  236. if (!isset($info['api'])) {
  237. $info['api'] = MAKE_API;
  238. drush_log(dt("You need to specify an API version of two in your makefile:\napi = !api", array("!api" => MAKE_API)), LogLevel::WARNING);
  239. }
  240. elseif ($info['api'] != MAKE_API) {
  241. make_error('BUILD_ERROR', dt("The specified API attribute is incompatible with this version of Drush Make."));
  242. $errors = TRUE;
  243. }
  244. $names = array();
  245. // Process projects.
  246. if (isset($info['projects'])) {
  247. if (!is_array($info['projects'])) {
  248. make_error('BUILD_ERROR', dt("'projects' attribute must be an array."));
  249. $errors = TRUE;
  250. }
  251. else {
  252. // Filter out entries that have been forcibly removed via [foo] = FALSE.
  253. $info['projects'] = array_filter($info['projects']);
  254. foreach ($info['projects'] as $project => $project_data) {
  255. // Project has an attributes array.
  256. if (is_string($project) && is_array($project_data)) {
  257. if (in_array($project, $names)) {
  258. make_error('BUILD_ERROR', dt("Project !project defined twice (remove the first projects[] = !project).", array('!project' => $project)));
  259. $errors = TRUE;
  260. }
  261. $names[] = $project;
  262. foreach ($project_data as $attribute => $value) {
  263. // Prevent malicious attempts to access other areas of the
  264. // filesystem.
  265. if (in_array($attribute, array('subdir', 'directory_name', 'contrib_destination')) && !make_safe_path($value)) {
  266. $args = array(
  267. '!path' => $value,
  268. '!attribute' => $attribute,
  269. '!project' => $project,
  270. );
  271. make_error('BUILD_ERROR', dt("Illegal path !path for '!attribute' attribute in project !project.", $args));
  272. $errors = TRUE;
  273. }
  274. }
  275. }
  276. // Cover if there is no project info, it's just a project name.
  277. elseif (is_numeric($project) && is_string($project_data)) {
  278. if (in_array($project_data, $names)) {
  279. make_error('BUILD_ERROR', dt("Project !project defined twice (remove the first projects[] = !project).", array('!project' => $project_data)));
  280. $errors = TRUE;
  281. }
  282. $names[] = $project_data;
  283. unset($info['projects'][$project]);
  284. $info['projects'][$project_data] = array();
  285. }
  286. // Convert shorthand project version style to array format.
  287. elseif (is_string($project_data)) {
  288. if (in_array($project, $names)) {
  289. make_error('BUILD_ERROR', dt("Project !project defined twice (remove the first projects[] = !project).", array('!project' => $project)));
  290. $errors = TRUE;
  291. }
  292. $names[] = $project;
  293. $info['projects'][$project] = array('version' => $project_data);
  294. }
  295. else {
  296. make_error('BUILD_ERROR', dt('Project !project incorrectly specified.', array('!project' => $project)));
  297. $errors = TRUE;
  298. }
  299. }
  300. }
  301. }
  302. if (isset($info['libraries'])) {
  303. if (!is_array($info['libraries'])) {
  304. make_error('BUILD_ERROR', dt("'libraries' attribute must be an array."));
  305. $errors = TRUE;
  306. }
  307. else {
  308. // Filter out entries that have been forcibly removed via [foo] = FALSE.
  309. $info['libraries'] = array_filter($info['libraries']);
  310. foreach ($info['libraries'] as $library => $library_data) {
  311. if (is_array($library_data)) {
  312. foreach ($library_data as $attribute => $value) {
  313. // Unset disallowed attributes.
  314. if (in_array($attribute, array('contrib_destination'))) {
  315. unset($info['libraries'][$library][$attribute]);
  316. }
  317. // Prevent malicious attempts to access other areas of the
  318. // filesystem.
  319. elseif (in_array($attribute, array('contrib_destination', 'directory_name')) && !make_safe_path($value)) {
  320. $args = array(
  321. '!path' => $value,
  322. '!attribute' => $attribute,
  323. '!library' => $library,
  324. );
  325. make_error('BUILD_ERROR', dt("Illegal path !path for '!attribute' attribute in library !library.", $args));
  326. $errors = TRUE;
  327. }
  328. }
  329. }
  330. }
  331. }
  332. }
  333. // Convert shorthand project/library download style to array format.
  334. foreach (array('projects', 'libraries') as $type) {
  335. if (isset($info[$type]) && is_array($info[$type])) {
  336. foreach ($info[$type] as $name => $item) {
  337. if (!empty($item['download']) && is_string($item['download'])) {
  338. $info[$type][$name]['download'] = array('url' => $item['download']);
  339. }
  340. }
  341. }
  342. }
  343. // Apply defaults after projects[] array has been expanded, but prior to
  344. // external validation.
  345. make_apply_defaults($info);
  346. foreach (drush_command_implements('make_validate_info') as $module) {
  347. $function = $module . '_make_validate_info';
  348. $return = $function($info);
  349. if ($return) {
  350. $info = $return;
  351. }
  352. else {
  353. $errors = TRUE;
  354. }
  355. }
  356. if ($errors) {
  357. return FALSE;
  358. }
  359. return $info;
  360. }
  361. /**
  362. * Verify the syntax of the given URL.
  363. *
  364. * Copied verbatim from includes/common.inc
  365. *
  366. * @see valid_url
  367. */
  368. function make_valid_url($url, $absolute = FALSE) {
  369. if ($absolute) {
  370. return (bool) preg_match("
  371. /^ # Start at the beginning of the text
  372. (?:ftp|https?):\/\/ # Look for ftp, http, or https schemes
  373. (?: # Userinfo (optional) which is typically
  374. (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)* # a username or a username and password
  375. (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@ # combination
  376. )?
  377. (?:
  378. (?:[a-z0-9\-\.]|%[0-9a-f]{2})+ # A domain name or a IPv4 address
  379. |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\]) # or a well formed IPv6 address
  380. )
  381. (?::[0-9]+)? # Server port number (optional)
  382. (?:[\/|\?]
  383. (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
  384. *)?
  385. $/xi", $url);
  386. }
  387. else {
  388. return (bool) preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url);
  389. }
  390. }
  391. /**
  392. * Find, and possibly create, a temporary directory.
  393. *
  394. * @param boolean $set
  395. * Must be TRUE to create a directory.
  396. * @param string $directory
  397. * Pass in a directory to use. This is required if using any
  398. * concurrent operations.
  399. *
  400. * @todo Merge with drush_tempdir().
  401. */
  402. function make_tmp($set = TRUE, $directory = NULL) {
  403. static $tmp_dir;
  404. if (isset($directory) && !isset($tmp_dir)) {
  405. $tmp_dir = $directory;
  406. }
  407. if (!isset($tmp_dir) && $set) {
  408. $tmp_dir = drush_find_tmp();
  409. if (strrpos($tmp_dir, '/') == strlen($tmp_dir) - 1) {
  410. $tmp_dir .= 'make_tmp_' . time() . '_' . uniqid();
  411. }
  412. else {
  413. $tmp_dir .= '/make_tmp_' . time() . '_' . uniqid();
  414. }
  415. if (!drush_get_option('no-clean', FALSE)) {
  416. drush_register_file_for_deletion($tmp_dir);
  417. }
  418. if (file_exists($tmp_dir)) {
  419. return make_tmp(TRUE);
  420. }
  421. // Create the directory.
  422. drush_mkdir($tmp_dir);
  423. }
  424. return $tmp_dir;
  425. }
  426. /**
  427. * Removes the temporary build directory. On failed builds, this is handled by
  428. * drush_register_file_for_deletion().
  429. */
  430. function make_clean_tmp() {
  431. if (!($tmp_dir = make_tmp(FALSE))) {
  432. return;
  433. }
  434. if (!drush_get_option('no-clean', FALSE)) {
  435. drush_delete_dir($tmp_dir);
  436. }
  437. else {
  438. drush_log(dt('Temporary directory: !dir', array('!dir' => $tmp_dir)), LogLevel::OK);
  439. }
  440. }
  441. /**
  442. * Prepare a Drupal installation, copying default.settings.php to settings.php.
  443. */
  444. function make_prepare_install($build_path) {
  445. $default = make_tmp() . '/__build__/sites/default';
  446. drush_copy_dir($default . DIRECTORY_SEPARATOR . 'default.settings.php', $default . DIRECTORY_SEPARATOR . 'settings.php', FILE_EXISTS_OVERWRITE);
  447. drush_mkdir($default . '/files');
  448. chmod($default . DIRECTORY_SEPARATOR . 'settings.php', 0666);
  449. chmod($default . DIRECTORY_SEPARATOR . 'files', 0777);
  450. }
  451. /**
  452. * Calculate a cksum on each file in the build, and md5 the resulting hashes.
  453. */
  454. function make_md5() {
  455. return drush_dir_md5(make_tmp());
  456. }
  457. /**
  458. * @todo drush_archive_dump() also makes a tar. Consolidate?
  459. */
  460. function make_tar($build_path) {
  461. $tmp_path = make_tmp();
  462. drush_mkdir(dirname($build_path));
  463. $filename = basename($build_path);
  464. $dirname = basename($build_path, '.tar.gz');
  465. // Move the build directory to a more human-friendly name, so that tar will
  466. // use it instead.
  467. drush_move_dir($tmp_path . DIRECTORY_SEPARATOR . '__build__', $tmp_path . DIRECTORY_SEPARATOR . $dirname, TRUE);
  468. // Only move the tar file to it's final location if it's been built
  469. // successfully.
  470. if (drush_shell_exec("%s -C %s -Pczf %s %s", drush_get_tar_executable(), $tmp_path, $tmp_path . '/' . $filename, $dirname)) {
  471. drush_move_dir($tmp_path . DIRECTORY_SEPARATOR . $filename, $build_path, TRUE);
  472. };
  473. // Move the build directory back to it's original location for consistency.
  474. drush_move_dir($tmp_path . DIRECTORY_SEPARATOR . $dirname, $tmp_path . DIRECTORY_SEPARATOR . '__build__');
  475. }
  476. /**
  477. * Logs an error unless the --force-complete command line option is specified.
  478. */
  479. function make_error($error_code, $message) {
  480. if (drush_get_option('force-complete')) {
  481. drush_log("$error_code: $message -- build forced", LogLevel::WARNING);
  482. }
  483. else {
  484. return drush_set_error($error_code, $message);
  485. }
  486. }
  487. /**
  488. * Checks an attribute's path to ensure it's not maliciously crafted.
  489. *
  490. * @param string $path
  491. * The path to check.
  492. */
  493. function make_safe_path($path) {
  494. return !preg_match("+^/|^\.\.|/\.\./+", $path);
  495. }
  496. /**
  497. * Get data based on the source.
  498. *
  499. * This is a helper function to abstract the retrieval of data, so that it can
  500. * come from files, STDIN, etc. Currently supports filepath and STDIN.
  501. *
  502. * @param string $data_source
  503. * The path to a file, or '-' for STDIN.
  504. *
  505. * @return string
  506. * The raw data as a string.
  507. */
  508. function make_get_data($data_source) {
  509. if ($data_source == '-') {
  510. // See http://drupal.org/node/499758 before changing this.
  511. $stdin = fopen('php://stdin', 'r');
  512. $data = '';
  513. $has_input = FALSE;
  514. while ($line = fgets($stdin)) {
  515. $has_input = TRUE;
  516. $data .= $line;
  517. }
  518. if ($has_input) {
  519. return $data;
  520. }
  521. return FALSE;
  522. }
  523. // Local file.
  524. elseif (!strpos($data_source, '://')) {
  525. $data = file_get_contents($data_source);
  526. }
  527. // Remote file.
  528. else {
  529. $file = _make_download_file($data_source);
  530. $data = file_get_contents($file);
  531. drush_op('unlink', $file);
  532. }
  533. return $data;
  534. }
  535. /**
  536. * Apply any defaults.
  537. *
  538. * @param array &$info
  539. * A parsed make array.
  540. */
  541. function make_apply_defaults(&$info) {
  542. if (isset($info['defaults'])) {
  543. $defaults = $info['defaults'];
  544. foreach ($defaults as $type => $default_data) {
  545. if (isset($info[$type])) {
  546. foreach ($info[$type] as $project => $data) {
  547. $info[$type][$project] = _drush_array_overlay_recursive($default_data, $info[$type][$project]);
  548. }
  549. }
  550. else {
  551. drush_log(dt("Unknown attribute '@type' in defaults array", array('@type' => $type)), LogLevel::WARNING);
  552. }
  553. }
  554. }
  555. }
  556. /**
  557. * Check if makefile overrides are allowed
  558. *
  559. * @param array $option
  560. * The option to check.
  561. */
  562. function _make_is_override_allowed ($option) {
  563. $allow_override = drush_get_option('allow-override', 'all');
  564. if ($allow_override == 'all') {
  565. $allow_override = array();
  566. }
  567. elseif (!is_array($allow_override)) {
  568. $allow_override = _convert_csv_to_array($allow_override);
  569. }
  570. if ((empty($allow_override)) || ((in_array($option, $allow_override)) && (!in_array('none', $allow_override)))) {
  571. return TRUE;
  572. }
  573. drush_log(dt("'!option' not allowed; use --allow-override=!option or --allow-override=all to permit", array("!option" => $option)), LogLevel::WARNING);
  574. return FALSE;
  575. }
  576. /**
  577. * Gather any working copy options.
  578. *
  579. * @param array $download
  580. * The download array.
  581. */
  582. function _get_working_copy_option($download) {
  583. $wc = '';
  584. if (_make_is_override_allowed('working-copy') && isset ($download['working-copy'])) {
  585. $wc = $download['working-copy'];
  586. }
  587. else {
  588. $wc = drush_get_option('working-copy');
  589. }
  590. return $wc;
  591. }
  592. /**
  593. * Given data from stdin, determine format.
  594. *
  595. * @return array|bool
  596. * Returns parsed data if it matches any known format.
  597. */
  598. function _make_determine_format($data) {
  599. // Most .make files will have a `core` attribute. Use this to determine
  600. // the format.
  601. if (preg_match('/^\s*core:/m', $data)) {
  602. $parsed = ParserYaml::parse($data);
  603. $parsed['format'] = 'yaml';
  604. return $parsed;
  605. }
  606. elseif (preg_match('/^\s*core\s*=/m', $data)) {
  607. $parsed = ParserIni::parse($data);
  608. $parsed['format'] = 'ini';
  609. return $parsed;
  610. }
  611. // If the .make file did not have a core attribute, it is being included
  612. // by another .make file. Test YAML first to avoid segmentation faults from
  613. // preg_match in INI parser.
  614. $yaml_parse_exception = FALSE;
  615. try {
  616. if ($parsed = ParserYaml::parse($data)) {
  617. $parsed['format'] = 'yaml';
  618. return $parsed;
  619. }
  620. }
  621. catch (\Symfony\Component\Yaml\Exception\ParseException $e) {
  622. // Note that an exception was thrown, and display after .ini parsing.
  623. $yaml_parse_exception = $e;
  624. }
  625. // Try INI format.
  626. if ($parsed = ParserIni::parse($data)) {
  627. $parsed['format'] = 'ini';
  628. return $parsed;
  629. }
  630. if ($yaml_parse_exception) {
  631. throw $e;
  632. }
  633. return drush_set_error('MAKE_STDIN_ERROR', dt('Unknown make file format'));
  634. }