generate.make.inc

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

Functions for the generate makefile command.

Functions

Namesort descending Description
drush_make_generate Drush callback; generate makefile from the current build.
_drush_generate_custom_project Create a project record for an extension not downloaded from drupal.org
_drush_generate_makefile_check_path Helper function to check for a non-default installation location.
_drush_generate_track_version Helper function to determine if a given project is to have its version tracked.
_drush_generate_validate_repo_location If the user has checked in the Drupal root, or the 'sites/all/modules' folder into a git repository, then we do not want to confuse that location with a "project".
_drush_make_generate_add_patch_files Record any patches that were applied to this project per information stored in PATCHES.txt.
_drush_make_generate_get_version_options Create the $version_options array from the --include-versions and --exclude-versions command line options.
_drush_make_generate_makefile_body
_drush_make_generate_makefile_contents Generate the actual contents of the .make file.
_drush_make_generate_projects Generate the $projects makefile array for the current site.

File

commands/make/generate.make.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Functions for the generate makefile command.
  5. */
  6. include_once DRUSH_DRUPAL_CORE . '/includes/install.inc';
  7. include_once drupal_get_path('module', 'system') . '/system.install';
  8. /**
  9. * Drush callback; generate makefile from the current build.
  10. */
  11. function drush_make_generate($file = NULL) {
  12. $version_options = _drush_make_generate_get_version_options();
  13. $all_extensions = drush_get_extensions();
  14. list($projects, $libraries) = _drush_make_generate_projects($all_extensions, $version_options);
  15. $contents = _drush_make_generate_makefile_contents($projects, $libraries);
  16. if (!$file) {
  17. drush_print($contents);
  18. }
  19. elseif (file_put_contents($file, $contents)) {
  20. drush_log(dt("Wrote .make file @file", array('@file' => $file)), 'ok');
  21. }
  22. else {
  23. drush_make_error('FILE_ERROR', dt("Unable to write .make file !file", array('!file' => $file)));
  24. }
  25. }
  26. /**
  27. * Create the $version_options array from the --include-versions and
  28. * --exclude-versions command line options.
  29. */
  30. function _drush_make_generate_get_version_options() {
  31. // What projects should we pin the versions for?
  32. // Check the command-line options for details.
  33. foreach (array("include", "exclude") as $option) {
  34. $version_options[$option] = drush_get_option("$option-versions");
  35. if ($version_options[$option] !== TRUE) {
  36. $version_options[$option] = array_filter(explode(",", $version_options[$option]));
  37. }
  38. }
  39. return $version_options;
  40. }
  41. /**
  42. * Generate the $projects makefile array for the current site.
  43. */
  44. function _drush_make_generate_projects($all_extensions, $version_options) {
  45. $projects = array();
  46. $project_libraries = array();
  47. $system_requirements = system_requirements('runtime');
  48. // Update xml expects the drupal version to be expressed as "7.x" or "8.x"
  49. // We used to check $system_requirements['drupal']['value'], but this now
  50. // contains values such as "7.10-dev".
  51. $drupal_major_version = drush_drupal_major_version() . '.x';
  52. $core_project = strtolower($system_requirements['drupal']['title']);
  53. $projects[$core_project] = array('_type' => 'core');
  54. if ($core_project != 'drupal') {
  55. $projects[$core_project]['custom_download'] = TRUE;
  56. $projects[$core_project]['type'] = 'core';
  57. }
  58. else {
  59. // Drupal core - we can determine the version if required.
  60. if (_drush_generate_track_version("drupal", $version_options)) {
  61. $projects[$core_project]["version"] = drush_drupal_version();
  62. }
  63. }
  64. // Non-default profiles section.
  65. $install_profile = variable_get('install_profile', '');
  66. if (!in_array($install_profile, array('default', 'standard', 'minimal', 'testing')) && $install_profile != '') {
  67. $projects[$install_profile]['type']
  68. = $projects[$install_profile]['_type'] = 'profile';
  69. $request = array(
  70. 'name' => $install_profile,
  71. 'drupal_version' => $drupal_major_version,
  72. );
  73. if (!release_info_check_project($request, 'profile')) {
  74. $projects[$install_profile]['custom_download'] = TRUE;
  75. }
  76. }
  77. // Iterate installed projects to build $projects array.
  78. $extensions = $all_extensions;
  79. $project_info = drush_get_projects($extensions);
  80. foreach ($project_info as $name => $project) {
  81. // Discard the extensions within this project. At the end $extensions will
  82. // contain only extensions part of custom projects (not from drupal.org or
  83. // other update service).
  84. foreach ($project['extensions'] as $ext) {
  85. unset($extensions[$ext]);
  86. }
  87. if ($name == 'drupal') {
  88. continue;
  89. }
  90. $type = $project['type'];
  91. // Discard projects with all modules disabled.
  92. if (($type == 'module') && (!$project['status'])) {
  93. continue;
  94. }
  95. $projects[$name] = array('_type' => $type);
  96. // Check the project is on drupal.org or its own update service.
  97. $request = array(
  98. 'name' => $name,
  99. 'drupal_version' => $drupal_major_version,
  100. );
  101. if (isset($project['status url'])) {
  102. $request['status url'] = $project['status url'];
  103. $projects[$name]['location'] = $status_url;
  104. }
  105. if (!release_info_check_project($request, $type)) {
  106. // It is not a project on drupal.org neither an external update service.
  107. $projects[$name]['type'] = $type;
  108. $projects[$name]['custom_download'] = TRUE;
  109. }
  110. // Add 'subdir' if the project is installed in a non-default location.
  111. if (isset($project['path'])) {
  112. $projects[$name] += _drush_generate_makefile_check_path($project);
  113. }
  114. // Add version number if this project's version is to be tracked.
  115. if (_drush_generate_track_version($name, $version_options) && $project["version"]) {
  116. $projects[$name]['version'] = preg_replace("/^" . DRUPAL_CORE_COMPATIBILITY . "-/", "", $project["version"]);
  117. }
  118. foreach ($project['extensions'] as $extension_name) {
  119. _drush_make_generate_add_patch_files($projects[$name], dirname($all_extensions[$extension_name]->filename));
  120. }
  121. }
  122. // Add a project for each unknown extension.
  123. foreach ($extensions as $name => $extension) {
  124. list($project_name, $project_data) = _drush_generate_custom_project($name, $extension, $version_options);
  125. $projects[$project_name] = $project_data;
  126. }
  127. // Add libraries.
  128. if (function_exists('libraries_get_libraries')) {
  129. $libraries = libraries_get_libraries();
  130. foreach ($libraries as $library_name => $library_path) {
  131. $path = explode('/', $library_path);
  132. $project_libraries[$library_name] = array(
  133. 'directory_name' => $path[(count($path) - 1)],
  134. 'custom_download' => TRUE,
  135. 'type' => 'library',
  136. '_type' => 'librarie', // For plural.
  137. );
  138. }
  139. }
  140. return array($projects, $project_libraries);
  141. }
  142. /**
  143. * Record any patches that were applied to this project
  144. * per information stored in PATCHES.txt.
  145. */
  146. function _drush_make_generate_add_patch_files(&$project, $location) {
  147. $patchfile = DRUPAL_ROOT . '/' . $location . '/PATCHES.txt';
  148. if (is_file($patchfile)) {
  149. foreach (file($patchfile) as $line) {
  150. if (substr($line, 0, 2) == '- ') {
  151. $project['patches'][] = trim(substr($line, 2));
  152. }
  153. }
  154. }
  155. }
  156. /**
  157. * Create a project record for an extension not downloaded from drupal.org
  158. */
  159. function _drush_generate_custom_project($name, $extension, $version_options) {
  160. $project['_type'] = $extension->type;
  161. $project['type'] = $extension->type;
  162. $info_file = $extension->filename;
  163. $location = DRUPAL_ROOT . '/' . dirname($info_file);
  164. // To start off, we will presume that our custom extension is
  165. // stored in a folder named after its project, and there are
  166. // no subfolders between the .info file and the project root.
  167. $project_name = basename($location);
  168. drush_shell_cd_and_exec($location, 'git rev-parse --git-dir 2> ' . drush_bit_bucket());
  169. $output = drush_shell_exec_output();
  170. if (!empty($output)) {
  171. $git_dir = $output[0];
  172. // Find the actual base of the git repository.
  173. $repo_root = $git_dir == ".git" ? $location : dirname($git_dir);
  174. // If the repository root is at the drupal root or some parent
  175. // of the drupal root, or some other location that could not
  176. // pausibly be a project, then there is nothing we can do.
  177. // (We can't tell Drush make to download some sub-part of a repo,
  178. // can we?)
  179. if ($repo_project_name = _drush_generate_validate_repo_location($repo_root)) {
  180. $project_name = $repo_project_name;
  181. drush_shell_cd_and_exec($repo_root, 'git remote show origin');
  182. $output = drush_shell_exec_output();
  183. foreach ($output as $line) {
  184. if (strpos($line, "Fetch URL:") !== FALSE) {
  185. $url = preg_replace('/ *Fetch URL: */', '', $line);
  186. if (!empty($url)) {
  187. // We use the unconventional-looking keys
  188. // `download][type` and `download][url` so that
  189. // we can produce output that appears to be two-dimensional
  190. // arrays from a single-dimensional array.
  191. $project['download][type'] = 'git';
  192. $project['download][url'] = $url;
  193. // Fill in the branch as well.
  194. drush_shell_cd_and_exec($repo_root, 'git branch');
  195. $output = drush_shell_exec_output();
  196. foreach ($output as $line) {
  197. if ($line{0} == '*') {
  198. $branch = substr($line, 2);
  199. if ($branch != "master") {
  200. $project['download][branch'] = $branch;
  201. }
  202. }
  203. }
  204. // Put in the commit hash.
  205. drush_shell_cd_and_exec($repo_root, 'git log');
  206. $output = drush_shell_exec_output();
  207. if (substr($output[0], 0, 7) == "commit ") {
  208. $revision = substr($output[0], 7);
  209. if (_drush_generate_track_version($project_name, $version_options)) {
  210. $project['download][revision'] = $revision;
  211. }
  212. }
  213. // Add patch files, if any.
  214. _drush_make_generate_add_patch_files($project, $repo_root);
  215. }
  216. }
  217. }
  218. }
  219. }
  220. // If we could not figure out where the extension came from, then give up and
  221. // flag it as a "custom" download.
  222. if (!isset($project['download][type'])) {
  223. $project['custom_download'] = TRUE;
  224. }
  225. return array($project_name, $project);
  226. }
  227. /**
  228. * If the user has checked in the Drupal root, or the 'sites/all/modules'
  229. * folder into a git repository, then we do not want to confuse that location
  230. * with a "project".
  231. */
  232. function _drush_generate_validate_repo_location($repo_root) {
  233. $project_name = basename($repo_root);
  234. // The Drupal root, or any folder immediately inside the Drupal
  235. // root cannot be a project location.
  236. if ((strlen(DRUPAL_ROOT) >= strlen($repo_root)) || (dirname($repo_root) == DRUPAL_ROOT)) {
  237. return NULL;
  238. }
  239. // Also exclude sites/* and sites/*/{modules,themes} and profile/* and
  240. // profile/*/{modules,themes}.
  241. return $project_name;
  242. }
  243. /**
  244. * Helper function to determine if a given project is to have its version
  245. * tracked.
  246. */
  247. function _drush_generate_track_version($project, $version_options) {
  248. // A. If --exclude-versions has been specified:
  249. // A.a. if it's a boolean, check the --include-versions option.
  250. if ($version_options["exclude"] === TRUE) {
  251. // A.a.1 if --include-versions has been specified, ensure it's an array.
  252. if (is_array($version_options["include"])) {
  253. return in_array($project, $version_options["include"]);
  254. }
  255. // A.a.2 If no include array, then we're excluding versions for ALL
  256. // projects.
  257. return FALSE;
  258. }
  259. // A.b. if --exclude-versions is an array with items, check this project is in
  260. // it: if so, then return FALSE.
  261. elseif (is_array($version_options["exclude"]) && count($version_options["exclude"])) {
  262. return !in_array($project, $version_options["exclude"]);
  263. }
  264. // B. If by now no --exclude-versions, but --include-versions is an array,
  265. // examine it for this project.
  266. if (is_array($version_options["include"]) && count($version_options["include"])) {
  267. return in_array($project, $version_options["include"]);
  268. }
  269. // If none of the above conditions match, include version number by default.
  270. return TRUE;
  271. }
  272. /**
  273. * Helper function to check for a non-default installation location.
  274. */
  275. function _drush_generate_makefile_check_path($project) {
  276. $info = array();
  277. $type = $project['type'];
  278. $path = dirname($project['path']);
  279. // Check to see if the path is in a subdir sites/all/modules or
  280. // profiles/profilename/modules
  281. if (preg_match('@^sites/[a-zA-Z0-9_]*/' . $type . 's/..*@', $path) || preg_match('@^sites/[a-zA-Z0-9_]*/' . $type . 's/..*@', $path)) {
  282. $subdir = preg_replace(array('@^[a-zA-Z0-9_]*/[a-zA-Z0-9_]*/' . $type . 's/*@', "@/$name" . '$@'), '', $path);
  283. if (!empty($subdir)) {
  284. $info['subdir'] = $subdir;
  285. }
  286. }
  287. return $info;
  288. }
  289. /**
  290. * Generate the actual contents of the .make file.
  291. */
  292. function _drush_make_generate_makefile_contents($projects, $libraries = array()) {
  293. $header = array();
  294. $header[] = '; This file was auto-generated by drush make';
  295. $header['core'] = DRUPAL_CORE_COMPATIBILITY;
  296. $header[] = '';
  297. $header['api'] = MAKE_API;
  298. return _drush_make_generate_makefile_body($projects, $header) . _drush_make_generate_makefile_body($libraries);
  299. }
  300. function _drush_make_generate_makefile_body($projects, $output = array()) {
  301. $custom = FALSE;
  302. $previous_type = 'core';
  303. foreach ($projects as $name => $project) {
  304. $type = (isset($project['type']) && ($project['type'] == 'library')) ? 'libraries' : 'projects';
  305. if ($previous_type != $project['_type']) {
  306. $previous_type = $project['_type'];
  307. $output[] = '; ' . ucfirst($previous_type) . 's';
  308. }
  309. unset($project['_type']);
  310. if (!$project && is_string($name)) {
  311. $output[] = $type . '[] = "' . $name . '"';
  312. continue;
  313. }
  314. $base = $type . '[' . $name . ']';
  315. if (isset($project['custom_download'])) {
  316. $custom = TRUE;
  317. $output[] = '; Please fill the following out. Type may be one of get, git, bzr or svn,';
  318. $output[] = '; and url is the url of the download.';
  319. $output[$base . '[download][type]'] = '""';
  320. $output[$base . '[download][url]'] = '""';
  321. unset($project['custom_download']);
  322. }
  323. foreach ($project as $key => $value) {
  324. if (is_array($value)) {
  325. foreach ($value as $item) {
  326. $output[$base . '[' . $key . '][]'] = '"' . $item . '"';
  327. }
  328. }
  329. else {
  330. $output[$base . '[' . $key . ']'] = '"' . $value . '"';
  331. }
  332. }
  333. $output[] = '';
  334. }
  335. $string = '';
  336. foreach ($output as $k => $v) {
  337. if (!is_numeric($k)) {
  338. $string .= $k . ' = ' . $v;
  339. }
  340. else {
  341. $string .= $v;
  342. }
  343. $string .= "\n";
  344. }
  345. if ($custom) {
  346. drush_log(dt('Some of the properties in your makefile will have to be manually edited. Please do that now.'), 'warning');
  347. }
  348. return $string;
  349. }