View source
<?php
namespace Drupal\hacked\Commands;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\hacked\hackedProject;
use Drush\Commands\DrushCommands;
class HackedCommands extends DrushCommands {
use DependencySerializationTrait;
use StringTranslationTrait;
protected $configFactory;
protected $moduleHandler;
protected $cacheBackend;
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, TranslationInterface $string_translation) {
$this->configFactory = $config_factory;
$this->moduleHandler = $module_handler;
$this->cacheBackend = $cache_backend;
$this->stringTranslation = $string_translation;
}
public function listProjects(array $options = [
'force-rebuild' => FALSE,
]) {
$this->moduleHandler
->loadInclude('update', 'inc', 'update.report');
$rows = [];
if ($available = update_get_available(TRUE)) {
$this->moduleHandler
->loadInclude('update', 'inc', 'update.compare');
$data = update_calculate_project_data($available);
$force_rebuild = $options['force-rebuild'];
$projects = $this
->calculateProjectData($data, $force_rebuild);
$rows = [];
foreach ($projects as $project) {
$row = [
'title' => $project['title'],
'name' => $project['name'],
'version' => $project['existing_version'],
];
switch ($project['status']) {
case HACKED_STATUS_UNHACKED:
$row['status'] = $this
->t('Unchanged');
break;
case HACKED_STATUS_HACKED:
$row['status'] = $this
->t('Changed');
break;
case HACKED_STATUS_UNCHECKED:
default:
$row['status'] = $this
->t('Unchecked');
break;
}
$row['changed'] = $project['counts']['different'];
$row['deleted'] = $project['counts']['missing'];
$rows[] = $row;
}
}
return new RowsOfFields($rows);
}
public function lockModified() {
}
public function details($machine_name, array $options = [
'include-unchanged' => FALSE,
]) {
$project = new hackedProject($machine_name);
$report = $project
->compute_details();
$this
->output()
->writeln((string) $this
->t('Details for project: @name', [
'@name' => $project
->title(),
]));
$this
->output()
->writeln((string) $this
->t('Total files: @total_files, files changed: @changed_files, deleted files: @deleted_files', [
'@total_files' => count($report['files']),
'@changed_files' => $report['counts']['different'],
'@deleted_files' => $report['counts']['missing'],
]));
$this
->output()
->writeln('');
$this
->output()
->writeln((string) $this
->t('Detailed results:'));
arsort($report['files']);
$rows = [];
$show_unchanged = $options['include-unchanged'];
foreach ($report['files'] as $file => $status) {
if (!$show_unchanged && $status == HACKED_STATUS_UNHACKED) {
continue;
}
$row = [];
switch ($status) {
case HACKED_STATUS_UNHACKED:
$row['status'] = $this
->t('Unchanged');
break;
case HACKED_STATUS_HACKED:
$row['status'] = $this
->t('Changed');
break;
case HACKED_STATUS_DELETED:
$row['status'] = $this
->t('Deleted');
break;
case HACKED_STATUS_UNCHECKED:
default:
$row['status'] = $this
->t('Unchecked');
break;
}
$row['file'] = $file;
$rows[] = $row;
}
return new RowsOfFields($rows);
}
public function validateDetailsCommand(CommandData $command_data) {
$machine_name = $command_data
->arguments()['machine_name'];
$this
->validateProjectName($machine_name);
}
protected function validateProjectName($machine_name) {
$project = new hackedProject($machine_name);
$project
->identify_project();
if (!$project->project_identified) {
throw new \Exception((string) $this
->t('Could not find project: @project', [
'@project' => $machine_name,
]));
}
}
public function diff($machine_name, array $options = [
'diff-options' => NULL,
]) {
$project = new hackedProject($machine_name);
$local_location = $project
->file_get_location('local', '');
$clean_location = $project
->file_get_location('remote', '');
$hasher = $this->configFactory
->get('hacked.settings')
->get('selected_file_hasher');
$hasher = is_null($hasher) ? HACKED_DEFAULT_FILE_HASHER : $hasher;
if ($hasher == 'hacked_ignore_line_endings') {
$default_options = '-uprb';
}
else {
$default_options = '-upr';
}
$diff_options = isset($options['diff-options']) ? $options['diff-options'] : $default_options;
drush_shell_exec("diff {$diff_options} {$clean_location} {$local_location}");
$lines = drush_shell_exec_output();
$local_location_trim = dirname($local_location . '/dummy.file') . '/';
$clean_location_trim = dirname($clean_location . '/dummy.file') . '/';
foreach ($lines as $line) {
if (strpos($line, '+++') === 0) {
$line = str_replace($local_location_trim, '', $line);
}
if (strpos($line, '---') === 0) {
$line = str_replace($clean_location_trim, '', $line);
}
if (strpos($line, 'diff -upr') === 0) {
$line = str_replace($clean_location_trim, 'a/', $line);
$line = str_replace($local_location_trim, 'b/', $line);
}
$this
->output()
->writeln($line);
}
}
public function validateDiffCommand(CommandData $command_data) {
$machine_name = $command_data
->arguments()['machine_name'];
$this
->validateProjectName($machine_name);
}
public function calculateProjectData(array $projects, $force = FALSE) {
$cache = $this->cacheBackend
->get('hacked:drush:full-report');
if (!empty($cache->data) && !$force) {
return $cache->data;
}
$op_callback = [
$this,
'buildReportBatch',
];
$finished_callback = [
$this,
'buildReportBatchFinished',
];
$title = $this
->t('Building report');
if (class_exists('\\Drupal\\Core\\Batch\\BatchBuilder')) {
$batch_builder = (new BatchBuilder())
->setTitle($title)
->setFinishCallback($finished_callback);
foreach ($projects as $project) {
$batch_builder
->addOperation($op_callback, [
$project['name'],
]);
}
$batch = $batch_builder
->toArray();
}
else {
$operations = [];
foreach ($projects as $project) {
$operations[] = [
$op_callback,
[
$project['name'],
],
];
}
$batch = [
'operations' => $operations,
'finished' => $finished_callback,
'title' => $title,
];
}
$this
->output()
->writeln((string) $this
->t('Rebuilding Hacked! report'));
batch_set($batch);
$batch =& batch_get();
$batch['progressive'] = FALSE;
drush_backend_batch_process();
$this
->output()
->writeln((string) $this
->t('Done.'));
$cache = $this->cacheBackend
->get('hacked:drush:full-report');
if (!empty($cache->data)) {
return $cache->data;
}
return [];
}
public function buildReportBatch($project_name, &$context) {
$this->moduleHandler
->loadInclude('hacked', 'inc', 'hacked.report');
hacked_build_report_batch($project_name, $context);
}
public function buildReportBatchFinished($success, array $results) {
if ($success) {
usort($results['report'], '_hacked_project_report_sort_by_status');
$this->cacheBackend
->set('hacked:drush:full-report', $results['report'], strtotime('+1 day'));
}
}
}