Yaffs site version 1.1
[yaffs-website] / vendor / drush / drush / commands / make / generate.contents.make.inc
1 <?php
2 /**
3  * @file
4  * Functions for the generate makefile command.
5  */
6
7 use Drush\Log\LogLevel;
8
9 /**
10  * Generate the actual contents of the .make file.
11  */
12 function _drush_make_generate_makefile_contents($projects, $libraries = array(), $core_version = NULL, $defaults = array()) {
13   if (is_null($core_version)) {
14     $core_version = drush_get_drupal_core_compatibility();
15   }
16
17   $header = array();
18   $header[] = '; This file was auto-generated by drush make';
19   $header['core'] = $core_version;
20   $header['api'] = MAKE_API;
21   $header[] = '';
22   if (!empty($defaults)) {
23     _drush_make_generate_defaults($defaults, $header);
24     $header[] = '';
25   }
26   $header[] = '; Core';
27
28   return _drush_make_generate_makefile_body($projects, $header) . _drush_make_generate_makefile_body($libraries);
29 }
30
31 function _drush_make_generate_makefile_body($projects, $output = array()) {
32   $custom = FALSE;
33   $previous_type = 'core';
34   if (isset($projects)) {
35     foreach ($projects as $name => $project) {
36       $type = (isset($project['type']) && ($project['type'] == 'library')) ? 'libraries' : 'projects';
37       if ($previous_type != $project['_type']) {
38         $previous_type = $project['_type'];
39         $output[] = '; ' . ucfirst($previous_type) . 's';
40       }
41       unset($project['_type']);
42       if (!$project && is_string($name)) {
43         $output[] = $type . '[] = "' . $name . '"';
44         continue;
45       }
46       $base = $type . '[' . $name . ']';
47       if (isset($project['custom_download'])) {
48         $custom = TRUE;
49         $output[] = '; Please fill the following out. Type may be one of get, git, bzr or svn,';
50         $output[] = '; and url is the url of the download.';
51         $output[$base . '[download][type]'] = '""';
52         $output[$base . '[download][url]'] = '""';
53         unset($project['custom_download']);
54       }
55
56       $output = array_merge($output, _drush_make_generate_lines($base, $project));
57       $output[] = '';
58     }
59   }
60   $string = '';
61   foreach ($output as $k => $v) {
62     if (!is_numeric($k)) {
63       $string .= $k . ' = ' . $v;
64     }
65     else {
66       $string .= $v;
67     }
68     $string .= "\n";
69   }
70   if ($custom) {
71     drush_log(dt('Some of the properties in your makefile will have to be manually edited. Please do that now.'), LogLevel::WARNING);
72   }
73   return $string;
74 }
75
76 /**
77  * Write a makefile based on data parsed from a previous makefile.
78  *
79  * @param $file
80  *   The path to the file to write our generated makefile to, or TRUE to
81  *   print to the terminal.
82  * @param $makefile
83  *   A makefile on which to base our generated one.
84  */
85 function make_generate_from_makefile($file, $makefile) {
86   if (!$info = make_parse_info_file($makefile)) {
87     return drush_set_error('MAKE_GENERATE_FAILED_PARSE', dt('Failed to parse makefile :makefile.', array(':makefile' => $makefile)));
88   }
89   $projects = drush_get_option('DRUSH_MAKE_PROJECTS', FALSE);
90   if ($projects === FALSE) {
91     $projects = make_prepare_projects(FALSE, $info);
92     if (isset($projects['contrib'])) {
93       $projects = array_merge($projects['core'], $projects['contrib']);
94     }
95   }
96
97   $defaults = isset($info['defaults']) ? $info['defaults'] : array();
98   $core = current($projects);
99   $core = $core['core'];
100   foreach ($projects as $name => $project) {
101     // If a specific revision was requested, do not set the version.
102     if (!isset($project['revision'])) {
103       $projects[$name]['version'] = isset($project['download']['full_version']) ? $project['download']['full_version'] : '';
104       if ($project['type'] != 'core' && strpos($projects[$name]['version'], $project['core']) === 0) {
105         $projects[$name]['version'] = substr($projects[$name]['version'], strlen($project['core'] . '-'));
106       }
107     }
108     else {
109       unset($projects[$name]['version']);
110     }
111     $projects[$name]['_type'] = $project['type'];
112
113     if ($project['download']['type'] == 'git') {
114       drush_make_resolve_git_refs($projects[$name]);
115     }
116
117     // Don't clutter the makefile with defaults
118     if (is_array($defaults)) {
119       foreach ($defaults as $type => $defs) {
120         if ($type == 'projects') {
121           foreach ($defs as $key => $value) {
122             if (isset($project[$key]) && $project[$key] == $value) {
123               unset($projects[$name][$key]);
124             }
125           }
126         }
127       }
128     }
129     if ($project['name'] == $name) {
130       unset($projects[$name]['name']);
131     }
132     if ($project['type'] == 'module' && !isset($info[$name]['type'])) {
133       unset($projects[$name]['type']);  // Module is the default
134     }
135     if (!(isset($project['download']['type'])) || ($project['download']['type'] == 'pm')) {
136       unset($projects[$name]['download']); // PM is the default
137     }
138     $ignore = array('build_path', 'contrib_destination', 'core', 'make_directory', 'l10n_url', 'download_type');
139     foreach ($ignore as $key) {
140       unset($projects[$name][$key]);
141     }
142
143     // Remove the location if it's the default.
144     if ($projects[$name]['location'] == 'https://updates.drupal.org/release-history') {
145       unset($projects[$name]['location']);
146     }
147
148     // Remove empty entries (e.g. 'directory_name')
149     $projects[$name] = _make_generate_array_filter($projects[$name]);
150   }
151
152   $libraries = drush_get_option('DRUSH_MAKE_LIBRARIES', FALSE);
153   if ($libraries === FALSE) {
154     $libraries = isset($info['libraries']) ? $info['libraries'] : array();
155   }
156   if (is_array($libraries)) {
157     foreach ($libraries as $name => $library) {
158       $libraries[$name]['type'] = 'library';
159       $libraries[$name]['_type'] = 'librarie';
160
161       if ($library['download']['type'] == 'git') {
162         drush_make_resolve_git_refs($libraries[$name]);
163       }
164     }
165   }
166
167   $contents = make_generate_makefile_contents($projects, $libraries, $core, $defaults);
168
169   // Write or print our makefile.
170   $file = $file !== TRUE ? $file : NULL;
171   make_generate_print($contents, $file);
172 }
173
174 /**
175  * Resolve branches and revisions for git-based projects.
176  */
177 function drush_make_resolve_git_refs(&$project) {
178   if (!isset($project['download']['branch'])) {
179     $project['download']['branch'] = drush_make_resolve_git_branch($project);
180   }
181   if (!isset($project['download']['revision'])) {
182     $project['download']['revision'] = drush_make_resolve_git_revision($project);
183   }
184 }
185
186 /**
187  * Resolve branch for a git-based project.
188  */
189 function drush_make_resolve_git_branch($project) {
190   drush_log(dt('Resolving default branch for repo at: :repo', array(':repo' => $project['download']['url'])));
191   if (drush_shell_exec("git ls-remote %s HEAD", $project['download']['url'])) {
192     $head_output = drush_shell_exec_output();
193     list($head_commit) = explode("\t", $head_output[0]);
194
195     drush_log(dt('Scanning branches in repo at: :repo', array(':repo' => $project['download']['url'])));
196     drush_shell_exec("git ls-remote --heads %s", $project['download']['url']);
197     $heads_output = drush_shell_exec_output();
198     $branches = array();
199     foreach ($heads_output as $key => $head) {
200       list($commit, $ref) = explode("\t", $head);
201       $branches[$commit] = explode("/", $ref)[2];
202     }
203
204     $branch = $branches[$head_commit];
205     drush_log(dt('Resolved git branch to: :branch', array(':branch' => $branch)));
206     return $branch;
207   }
208   else {
209     drush_log(dt('Could not resolve branch for `:project` using git repo at :repo', array(':project' => $project['name'], ':repo' => $project['download']['url'])), 'warning');
210   }
211 }
212
213 /**
214  * Resolve revision for a git-based project.
215  */
216 function drush_make_resolve_git_revision($project) {
217   drush_log(dt('Resolving head commit on `:branch` branch for repo at: :repo', array(':branch' => $project['download']['branch'], ':repo' => $project['download']['url'])));
218   if (drush_shell_exec("git ls-remote %s %s", $project['download']['url'], $project['download']['branch'])) {
219     $head_output = drush_shell_exec_output();
220     list($revision) = explode("\t", $head_output[0]);
221     drush_log(dt('Resolved git revision to: :revision', array(':revision' => $revision)));
222     return $revision;
223   }
224   else {
225     drush_log(dt('Could not resolve head commit for `:project` using git repo at :repo', array(':project' => $project['name'], ':repo' => $project['download']['url'])), 'warning');
226   }
227 }
228
229 /**
230  * Generate makefile contents in the appropriate format.
231  */
232 function make_generate_makefile_contents($projects,  $libraries = array(), $core = NULL, $defaults = array()) {
233   $format = drush_get_option('format', 'yaml');
234   $func = "make_generate_makefile_contents_$format";
235   if (function_exists($func)) {
236     $contents = call_user_func($func, $projects, $libraries, $core, $defaults);
237   }
238   else {
239     return drush_set_error('MAKE_UNKNOWN_OUTPUT_FORMAT', dt('Generating makefiles in the :format output format is not yet supported. Implement :func() to add such support.', array(':format' => $format, ':func' => $func)));
240   }
241   return $contents;
242 }
243
244 /**
245  * Generate makefile contents in (legacy) INI format.
246  */
247 function make_generate_makefile_contents_ini($projects, $libraries, $core, $defaults) {
248   return _drush_make_generate_makefile_contents($projects, $libraries, $core, $defaults);
249 }
250
251 /**
252  * Generate makefile contents in YAML format.
253  */
254 function make_generate_makefile_contents_yaml($projects, $libraries, $core, $defaults) {
255   $info = array(
256     'core' => $core,
257     'api' => MAKE_API,
258     'defaults' => $defaults,
259     'projects' => $projects,
260     'libraries' => $libraries,
261   );
262
263   $info = _make_generate_array_filter($info);
264   $info = _make_generate_array_filter_key('_type', $info);
265   $dumper = drush_load_engine('outputformat', 'yaml');
266   $yaml = $dumper->format($info, array());
267
268   return $yaml;
269 }
270
271 /**
272  * Helper function to recursively remove empty values from an array (but not
273  * '0'!).
274  */
275 function _make_generate_array_filter($haystack) {
276   foreach ($haystack as $key => $value) {
277     if (is_array($value)) {
278       $haystack[$key] = _make_generate_array_filter($haystack[$key]);
279     }
280     if (empty($value) && $value !== '0') {
281       unset($haystack[$key]);
282     }
283   }
284   return $haystack;
285 }
286
287 /**
288  * Helper function to recursively remove elements matching a specific key from an array.
289  */
290 function _make_generate_array_filter_key($needle, $haystack) {
291   foreach ($haystack as $key => $value) {
292     if ($key === $needle) {
293       unset($haystack[$key]);
294     }
295     elseif (is_array($value)) {
296       $haystack[$key] = _make_generate_array_filter_key($needle, $haystack[$key]);
297     }
298   }
299   return $haystack;
300 }
301
302 /**
303  * Print the generated makefile to the terminal, or write it to a file.
304  *
305  * @param $contents
306  *   The formatted contents of a makefile.
307  * @param $file
308  *   (optional) The path to write the makefile.
309  */
310 function make_generate_print($contents, $file = NULL) {
311   if (!$file) {
312     drush_print($contents);
313   }
314   elseif (file_put_contents($file, $contents)) {
315     drush_log(dt("Wrote .make file @file", array('@file' => $file)), LogLevel::OK);
316   }
317   else {
318     make_error('FILE_ERROR', dt("Unable to write .make file !file", array('!file' => $file)));
319   }
320 }
321
322 /**
323  * Utility function to generate the line or lines for a key/value pair in the
324  * make file.
325  *
326  * @param $base
327  *   The base for the configuration lines. Values will be appended to it as
328  *   [$key] = $value, or if value is an array itself it will expand into as many
329  *   lines as required.
330  * @param $values
331  *   May be a single value or an array.
332  * @return
333  *   An array of strings that represent lines for the make file.
334  */
335 function _drush_make_generate_lines($base, $values) {
336   $output = array();
337
338   if (is_array($values)) {
339     foreach ($values as $key => $value) {
340       $newbase = $base . '[' . $key . ']';
341       $output = array_merge($output, _drush_make_generate_lines($newbase, $value));
342     }
343   }
344   else {
345     $output[$base] = '"' . $values . '"';
346   }
347
348   return $output;
349 }
350
351 function _drush_make_generate_defaults($defaults, &$output = array()) {
352   $output[] = '; Defaults';
353   foreach ($defaults as $name => $project) {
354     $type = 'defaults';
355     if (!$project && is_string($name)) {
356       $output[] = $type . '[] = "' . $name . '"';
357       continue;
358     }
359     $base = $type . '[' . $name . ']';
360
361     $output = array_merge($output, _drush_make_generate_lines($base, $project));
362   }
363 }
364