Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / modules / contrib / hacked / hacked.drush.inc
1 <?php
2
3 /**
4  * @file
5  * Hacked drush command.
6  *
7  * Enables drush support for the Hacked! module.
8  */
9
10 use Drupal\hacked\hackedProject;
11
12 /**
13  * Implements hook_drush_help().
14  */
15 function hacked_drush_help($section) {
16   switch ($section) {
17     case 'drush:hacked-list-projects':
18       return dt('List projects and their hacked/unhacked status.');
19
20     case 'drush:hacked-details':
21       return dt('Show details of the files in one project, and the hacked/unhacked status of those files.');
22
23     case 'drush:hacked-diff':
24       return dt('Output a unified diff of the specified project.');
25   }
26 }
27
28 /**
29  * Implements hook_drush_command().
30  *
31  * @See drush_parse_command() for a list of recognized keys.
32  */
33 function hacked_drush_command() {
34   $items['hacked-list-projects'] = [
35     'description'         => "List all projects that can be analysed by Hacked! ",
36     'drupal dependencies' => ['hacked'],
37     'options'             => [
38       'force-rebuild' => 'Rebuild the Hacked! report instead of getting a cached version.',
39     ],
40     'aliases'             => ['hlp'],
41   ];
42
43   $items['hacked-lock-modified'] = [
44     'description'         => "Lock all projects that Hacked! detects are modified, so that drush pm-updatecode will not touch them. (drush-4.x+ only)",
45     'drupal dependencies' => ['hacked'],
46   ];
47
48   $items['hacked-details'] = [
49     'description'         => "Show the Hacked! report about a specific project.",
50     'drupal dependencies' => ['hacked'],
51     'arguments'           => [
52       'project' => 'The machine name of the project to report on.',
53     ],
54     'options'             => [
55       'include-unchanged' => 'Show the files that are unchanged too.',
56     ],
57     'aliases'             => ['hd'],
58   ];
59
60   $items['hacked-diff'] = [
61     'description'         => "Output a unified diff of the project specified.",
62     'drupal dependencies' => ['hacked'],
63     'arguments'           => [
64       'project' => 'The machine name of the project to report on.',
65     ],
66     'options'             => [
67       'diff-options' => 'Command line options to pass through to the diff command.',
68     ],
69   ];
70
71   return $items;
72 }
73
74 /**
75  * Compute the report data for hacked.
76  *
77  * WARNING: This function can invoke a batch process and end your current page.
78  * So you'll want to be very careful if you call this!
79  *
80  * @param array $projects
81  *   An array of Drupal projects.
82  * @param bool|FALSE $force
83  *   If TRUE, force rebuild of project data.
84  */
85 function hacked_calculate_project_data_drush($projects, $force = FALSE) {
86   include_once DRUPAL_ROOT . '/core/includes/batch.inc';
87
88   // Try to get the report form cache if we can.
89   $cache = \Drupal::cache(HACKED_CACHE_TABLE)->get('hacked:drush:full-report');
90   if (!empty($cache->data) && !$force) {
91     return $cache->data;
92   }
93
94   // Enter a batch to build the report.
95   $operations = [];
96   foreach ($projects as $project) {
97     $operations[] = [
98       'hacked_build_report_batch',
99       [$project['name']],
100     ];
101   }
102
103   $batch = [
104     'operations' => $operations,
105     'finished'   => 'hacked_build_report_batch_finished_drush',
106     'file'       => drupal_get_path('module', 'hacked') . '/hacked.report.inc',
107     'title'      => t('Building report'),
108   ];
109
110   drush_print('Rebuilding Hacked! report');
111   batch_set($batch);
112   $batch =& batch_get();
113   $batch['progressive'] = FALSE;
114   drush_backend_batch_process();
115   drush_print('Done.');
116
117   // Now we can get the data from the cache.
118   $cache = \Drupal::cache(HACKED_CACHE_TABLE)->get('hacked:drush:full-report');
119   if (!empty($cache->data)) {
120     return $cache->data;
121   }
122 }
123
124 /**
125  * Completion callback for the report batch.
126  *
127  * @param bool $success
128  *   Boolean value of batch success.
129  * @param array $results
130  *   An array of batch results.
131  */
132 function hacked_build_report_batch_finished_drush($success, $results) {
133   if ($success) {
134     // Sort the results.
135     usort($results['report'], '_hacked_project_report_sort_by_status');
136     // Store them.
137     \Drupal::cache(HACKED_CACHE_TABLE)
138       ->set('hacked:drush:full-report', $results['report'], strtotime('+1 day'));
139   }
140 }
141
142 /**
143  * Drush command callback that shows the listing of changed/unchanged projects.
144  */
145 function drush_hacked_list_projects() {
146   // Go get the data:
147   module_load_include('inc', 'update', 'update.report');
148   if ($available = update_get_available(TRUE)) {
149     module_load_include('inc', 'update', 'update.compare');
150     $data = update_calculate_project_data($available);
151     $force_rebuild = drush_get_option('force-rebuild', FALSE);
152     $projects = hacked_calculate_project_data_drush($data, $force_rebuild);
153     // Now print the data using drush:
154     $rows[] = [
155       dt('Title'),
156       dt('Name'),
157       dt('Version'),
158       dt('Status'),
159       dt('Changed'),
160       dt('Deleted'),
161     ];
162     foreach ($projects as $project) {
163       $row = [
164         $project['title'],
165         $project['name'],
166         $project['existing_version'],
167       ];
168
169       // Now add the status:
170       switch ($project['status']) {
171         case HACKED_STATUS_UNHACKED:
172           $row[] = dt('Unchanged');
173           break;
174
175         case HACKED_STATUS_HACKED:
176           $row[] = t('Changed');
177           break;
178
179         case HACKED_STATUS_UNCHECKED:
180         default:
181           $row[] = t('Unchecked');
182           break;
183       }
184
185       $row[] = $project['counts']['different'];
186       $row[] = $project['counts']['missing'];
187
188       $rows[] = $row;
189     }
190     drush_print_table($rows, TRUE);
191
192     return $projects;
193   }
194 }
195
196 /**
197  * Lock all of the modified files so that pm-updatecode will not touch them.
198  */
199 function drush_hacked_lock_modified() {
200   $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
201   module_load_include('inc', 'update', 'update.report');
202   if (isset($drupal_root) && ($available = update_get_available(TRUE))) {
203     module_load_include('inc', 'update', 'update.compare');
204     $data = update_calculate_project_data($available);
205     $projects = hacked_calculate_project_data_drush($data, TRUE);
206
207     foreach ($projects as $project) {
208       $row = [
209         empty($project['title']) ? $project['name'] : $project['title'],
210         $project['name'],
211         $project['existing_version'],
212       ];
213
214       // Lock the file if it is not already locked.
215       switch ($project['status']) {
216         case HACKED_STATUS_HACKED:
217           $project_ob = NULL;
218           $project_ob = new hackedProject($project['project_name']);
219           $lockfile = $project_ob->file_get_location('local', '.drush-lock-update');
220           if (!file_exists($lockfile)) {
221             drush_op('file_put_contents', $lockfile, dt("Locked: modified."));
222             drush_print(dt("Locked: @project", ['@project' => $project['name']]));
223           }
224           else {
225             drush_print(dt("@project is modified and already locked", ['@project' => $project['name']]));
226           }
227           break;
228
229         case HACKED_STATUS_UNHACKED:
230         case HACKED_STATUS_UNCHECKED:
231         default:
232           break;
233       }
234     }
235   }
236 }
237
238 /**
239  * Add a --lock-modified flag to pm-updatecode.
240  */
241 function drush_hacked_pre_pm_updatecode() {
242   if (drush_get_option('lock-modified')) {
243     drush_print(dt('Hacked! is checking for modified projects...'));
244     drush_hacked_lock_modified();
245     drush_print(dt('Hacked! modification check complete.'));
246   }
247 }
248
249 /**
250  * Implements hook_drush_help_alter().
251  *
252  * Add --lock-modified to the pm-updatecode and pm-update help.
253  */
254 function hacked_drush_help_alter(&$command) {
255   if (($command['command'] == 'pm-updatecode') || ($command['command'] == 'pm-update')) {
256     $command['sub-options']['--lock']['--lock-modified'] = "Lock any project that Hacked! determines is modified.";
257   }
258 }
259
260 /**
261  * Validate hook for the hacked_details drush command.
262  *
263  * @param string $short_name
264  *   The project short name.
265  */
266 function drush_hacked_details_validate($short_name = '') {
267   return drush_hacked_drush_command_validate($short_name);
268 }
269
270 /**
271  * Validate hook for the hacked drush commands that need a project.
272  *
273  * @param string $short_name
274  *   The project short name.
275  */
276 function drush_hacked_drush_command_validate($short_name = '') {
277   if (empty($short_name)) {
278     return drush_set_error('HACKED_PROJECT_NOT_FOUND', dt('A valid project must be specified', ['@project' => $short_name]));
279   }
280
281   $project = new hackedProject($short_name);
282   $project->identify_project();
283   if (!$project->project_identified) {
284     return drush_set_error('HACKED_PROJECT_NOT_FOUND', dt('Could not find project: @project', ['@project' => $short_name]));
285   }
286   $project = NULL;
287 }
288
289 /**
290  * Drush callback that shows the list of changes/unchanged files in a project.
291  *
292  * You may specify the --include-unchanged option to show unchanged files too,
293  * otherwise just the changed and deleted files are shown.
294  *
295  * @param string $short_name
296  *   The project short name.
297  */
298 function drush_hacked_details($short_name) {
299   $project = new hackedProject($short_name);
300   $report = $project->compute_details();
301
302   drush_print(dt('Details for project: @name', ['@name' => $project->title()]));
303   drush_print(dt('Total files: @total_files, files changed: @changed_files, deleted files: @deleted_files', [
304     '@total_files'   => count($report['files']),
305     '@changed_files' => $report['counts']['different'],
306     '@deleted_files' => $report['counts']['missing'],
307   ]));
308   drush_print('');
309
310   drush_print(dt('Detailed results:'));
311   // Sort the results:
312   arsort($report['files']);
313
314   $rows[] = [
315     dt('Status'),
316     dt('File'),
317   ];
318   $show_unchanged = drush_get_option('include-unchanged', FALSE);
319   foreach ($report['files'] as $file => $status) {
320     if (!$show_unchanged && $status == HACKED_STATUS_UNHACKED) {
321       continue;
322     }
323     $row = [];
324
325     // Now add the status:
326     switch ($status) {
327       case HACKED_STATUS_UNHACKED:
328         $row[] = dt('Unchanged');
329         break;
330
331       case HACKED_STATUS_HACKED:
332         $row[] = t('Changed');
333         break;
334
335       case HACKED_STATUS_DELETED:
336         $row[] = t('Deleted');
337         break;
338
339       case HACKED_STATUS_UNCHECKED:
340       default:
341         $row[] = t('Unchecked');
342         break;
343     }
344
345     $row[] = $file;
346     $rows[] = $row;
347   }
348
349   drush_print_table($rows, TRUE);
350 }
351
352 /**
353  * Validate hook for the hacked_diff drush command.
354  *
355  * @param string $short_name
356  *   The project short name.
357  */
358 function drush_hacked_diff_validate($short_name = '') {
359   return drush_hacked_drush_command_validate($short_name);
360 }
361
362 /**
363  * Drush callback that shows the list of changes/unchanged files in a project.
364  *
365  * You may specify the --include-unchanged option to show unchanged files too,
366  * otherwise just the changed and deleted files are shown.
367  *
368  * @param string $short_name
369  *   The project short name.
370  */
371 function drush_hacked_diff($short_name) {
372   $project = new hackedProject($short_name);
373
374   $local_location = $project->file_get_location('local', '');
375   $clean_location = $project->file_get_location('remote', '');
376
377   // If the hasher is our ignore line endings one, then ignore line endings.
378   $hasher = \Drupal::config('hacked.settings')->get('selected_file_hasher');
379   $hasher = is_null($hasher) ? HACKED_DEFAULT_FILE_HASHER : $hasher;
380   if ($hasher == 'hacked_ignore_line_endings') {
381     $default_options = '-uprb';
382   }
383   else {
384     $default_options = '-upr';
385   }
386
387   $diff_options = drush_get_option('diff-options', $default_options);
388   drush_shell_exec("diff $diff_options $clean_location $local_location");
389
390   $lines = drush_shell_exec_output();
391   $local_location_trim = dirname($local_location . '/dummy.file') . '/';
392   $clean_location_trim = dirname($clean_location . '/dummy.file') . '/';
393   foreach ($lines as $line) {
394     if (strpos($line, '+++') === 0) {
395       $line = str_replace($local_location_trim, '', $line);
396     }
397     if (strpos($line, '---') === 0) {
398       $line = str_replace($clean_location_trim, '', $line);
399     }
400     if (strpos($line, 'diff -upr') === 0) {
401       $line = str_replace($clean_location_trim, 'a/', $line);
402       $line = str_replace($local_location_trim, 'b/', $line);
403     }
404
405     drush_print($line);
406   }
407 }