From 3d9f66c2f86612e83a9380eee905795280659450 Mon Sep 17 00:00:00 2001
From: Colan Schwartz
Date: Thu, 25 Feb 2016 17:18:01 -0500
Subject: [PATCH] Issue #2066371 by FluxSauce, codi, colan: Added Drush support
without installation & integrated with Site Audit.
---
hacked.drush.inc | 196 ++++++++++++++++++++++++++++++++------------------
hacked.module | 12 +++-
hacked.report.inc | 11 ++-
hacked.site_audit.inc | 110 ++++++++++++++++++++++++++++
4 files changed, 255 insertions(+), 74 deletions(-)
create mode 100644 hacked.site_audit.inc
diff --git a/hacked.drush.inc b/hacked.drush.inc
index 640127b..d04e516 100644
--- a/hacked.drush.inc
+++ b/hacked.drush.inc
@@ -1,22 +1,43 @@
"List all projects that can be analysed by Hacked! ",
- 'drupal dependencies' => array('hacked'),
+ 'description' => dt('List all projects that can be analysed by Hacked!'),
'options' => array(
- 'force-rebuild' => 'Rebuild the Hacked! report instead of getting a cached version.'
+ 'force-rebuild' => dt('Rebuild the Hacked! report instead of getting a cached version.'),
),
'aliases' => array('hlp'),
);
$items['hacked-lock-modified'] = array(
- 'description' => "Lock all projects that Hacked! detects are modified, so that drush pm-updatecode will not touch them. (drush-4.x+ only)",
- 'drupal dependencies' => array('hacked'),
+ 'description' => dt('Lock all projects that Hacked! detects are modified so pm-updatecode will not change them.'),
);
$items['hacked-details'] = array(
- 'description' => "Show the Hacked! report about a specific project.",
- 'drupal dependencies' => array('hacked'),
+ 'description' => dt('Show the Hacked! report about a specific project.'),
'arguments' => array(
- 'project' => 'The machine name of the project to report on.',
+ 'project' => dt('The machine name of the project to report on.'),
),
'options' => array(
- 'include-unchanged' => 'Show the files that are unchanged too.',
+ 'include-unchanged' => dt('List unchanged files.'),
),
'aliases' => array('hd'),
);
$items['hacked-diff'] = array(
- 'description' => "Output a unified diff of the project specified.",
- 'drupal dependencies' => array('hacked'),
+ 'description' => dt('Output a unified diff of the project specified.'),
'arguments' => array(
- 'project' => 'The machine name of the project to report on.',
+ 'project' => dt('The machine name of the project to report on.'),
),
'options' => array(
- 'diff-options' => 'Command line options to pass through to the diff command.'
+ 'diff-options' => dt('Command line options to pass through to the diff command.'),
),
);
@@ -81,10 +93,10 @@ function hacked_drush_command() {
* So you'll want to be very careful if you call this!
*/
function hacked_calculate_project_data_drush($projects, $force = FALSE, $redirect = NULL) {
- include_once DRUPAL_ROOT . '/includes/batch.inc';
+ hacked_load_drush_dependencies();
// Try to get the report form cache if we can.
- $cache = cache_get('hacked:drush:full-report', HACKED_CACHE_TABLE);
+ $cache = drush_cache_get('hacked:drush:full-report', HACKED_CACHE_TABLE);
if (!empty($cache->data) && !$force) {
return $cache->data;
}
@@ -93,7 +105,7 @@ function hacked_calculate_project_data_drush($projects, $force = FALSE, $redirec
$operations = array();
foreach ($projects as $project) {
$operations[] = array(
- 'hacked_build_report_batch',
+ 'hacked_build_report_batch_drush',
array($project['name']),
);
}
@@ -102,7 +114,7 @@ function hacked_calculate_project_data_drush($projects, $force = FALSE, $redirec
'operations' => $operations,
'finished' => 'hacked_build_report_batch_finished_drush',
'file' => drupal_get_path('module', 'hacked') . '/hacked.report.inc',
- 'title' => t('Building report'),
+ 'title' => dt('Building report'),
);
drush_print('Rebuilding Hacked! report');
@@ -113,13 +125,29 @@ function hacked_calculate_project_data_drush($projects, $force = FALSE, $redirec
drush_print('Done.');
// Now we can get the data from the cache.
- $cache = cache_get('hacked:drush:full-report', HACKED_CACHE_TABLE);
+ $cache = drush_cache_get('hacked:drush:full-report', HACKED_CACHE_TABLE);
if (!empty($cache->data)) {
return $cache->data;
}
}
/**
+ * Batch callback to build the hacked report.
+ */
+function hacked_build_report_batch_drush($project_name, &$context) {
+ hacked_load_drush_dependencies();
+ if (!isset($context['results']['report'])) {
+ $context['results']['report'] = array();
+ }
+
+ $project = new hackedProject($project_name);
+ $context['results']['report'][$project_name] = $project->compute_report();
+ $context['message'] = dt('Finished processing: @name', array(
+ '@name' => $project->title(),
+ ));
+}
+
+/**
* Completion callback for the report batch.
*/
function hacked_build_report_batch_finished_drush($success, $results, $operations) {
@@ -127,22 +155,32 @@ function hacked_build_report_batch_finished_drush($success, $results, $operation
// Sort the results.
usort($results['report'], '_hacked_project_report_sort_by_status');
// Store them.
- cache_set('hacked:drush:full-report', $results['report'], HACKED_CACHE_TABLE, strtotime('+1 day'));
+ drush_cache_set('hacked:drush:full-report', $results['report'], HACKED_CACHE_TABLE, strtotime('+1 day'));
}
}
/**
- * Drush command callback that shows the listing of changed/unchanged projects.
+ * Validation callback for drush hacked_list_projects.
*/
-function drush_hacked_list_projects() {
+function drush_hacked_list_projects_validate() {
+ if (!function_exists('update_get_available')) {
+ return drush_set_error('HACKED_UPDATE_DISABLED', 'Cannot list projects without the Drupal core update module enabled.');
+ }
+}
- // Go get the data:
+/**
+ * Command callback for drush hacked_list_projects.
+ */
+function drush_hacked_list_projects() {
+ hacked_load_drush_dependencies();
+ // Get the data.
module_load_include('inc', 'update', 'update.report');
if ($available = update_get_available(TRUE)) {
module_load_include('inc', 'update', 'update.compare');
$data = update_calculate_project_data($available);
$force_rebuild = drush_get_option('force-rebuild', FALSE);
$projects = hacked_calculate_project_data_drush($data, $force_rebuild);
+
// Now print the data using drush:
$rows[] = array(
dt('Title'),
@@ -152,11 +190,12 @@ function drush_hacked_list_projects() {
dt('Changed'),
dt('Deleted'),
);
+
foreach ($projects as $project) {
$row = array(
$project['title'],
$project['name'],
- $project['existing_version']
+ $project['existing_version'],
);
// Now add the status:
@@ -164,19 +203,21 @@ function drush_hacked_list_projects() {
case HACKED_STATUS_UNHACKED:
$row[] = dt('Unchanged');
break;
+
case HACKED_STATUS_HACKED:
- $row[] = t('Changed');
+ $row[] = dt('Changed');
break;
+
case HACKED_STATUS_UNCHECKED:
default:
- $row[] = t('Unchecked');
+ $row[] = dt('Unchecked');
break;
+
}
$row[] = $project['counts']['different'];
$row[] = $project['counts']['missing'];
-
$rows[] = $row;
}
drush_print_table($rows, TRUE);
@@ -186,8 +227,7 @@ function drush_hacked_list_projects() {
}
/**
- * Lock all of the modified files so that pm-updatecode will not
- * touch them.
+ * Lock modified files so that pm-updatecode won't touch them.
*/
function drush_hacked_lock_modified() {
$drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
@@ -201,7 +241,7 @@ function drush_hacked_lock_modified() {
$row = array(
empty($project['title']) ? $project['name'] : $project['title'],
$project['name'],
- $project['existing_version']
+ $project['existing_version'],
);
// Lock the file if it is not already locked.
@@ -211,24 +251,30 @@ function drush_hacked_lock_modified() {
$project_ob = hacked_project_load($project['project_name']);
$lockfile = $project_ob->file_get_location('local', '.drush-lock-update');
if (!file_exists($lockfile)) {
- drush_op('file_put_contents', $lockfile, dt("Locked: modified."));
- drush_print(dt("Locked: @project", array('@project' => $project['name'])));
+ drush_op('file_put_contents', $lockfile, dt('Locked: modified.'));
+ drush_print(dt('Locked: @project', array(
+ '@project' => $project['name'],
+ )));
}
else {
- drush_print(dt("@project is modified and already locked", array('@project' => $project['name'])));
+ drush_print(dt('@project is modified and already locked', array(
+ '@project' => $project['name'],
+ )));
}
break;
+
case HACKED_STATUS_UNHACKED:
case HACKED_STATUS_UNCHECKED:
default:
break;
+
}
}
}
}
/**
- * Add a --lock-modified flag to pm-updatecode
+ * Add a --lock-modified flag to pm-updatecode.
*/
function drush_hacked_pre_pm_updatecode() {
if (drush_get_option('lock-modified')) {
@@ -239,11 +285,11 @@ function drush_hacked_pre_pm_updatecode() {
}
/**
- * Add --lock-modified to the pm-updatecode and pm-update help
+ * Add --lock-modified to the pm-updatecode and pm-update help.
*/
function hacked_drush_help_alter(&$command) {
if (($command['command'] == 'pm-updatecode') || ($command['command'] == 'pm-update')) {
- $command['sub-options']['--lock']['--lock-modified'] = "Lock any project that Hacked! determines is modified.";
+ $command['sub-options']['--lock']['--lock-modified'] = dt('Lock any project that Hacked! determines is modified.');
}
}
@@ -255,26 +301,31 @@ function drush_hacked_details_validate($short_name = '') {
}
/**
- * Validate hook for the hacked drush commands that need a project.
+ * Generic validator for hacked drush commands.
+ *
+ * @param string $short_name
+ * The name of the project in question.
+ *
+ * @return null|boolean
+ * Return FALSE if there's an error.
*/
function drush_hacked_drush_command_validate($short_name = '') {
+ hacked_load_drush_dependencies();
if (empty($short_name)) {
- return drush_set_error('HACKED_PROJECT_NOT_FOUND', dt('A valid project must be specified', array('@project' => $short_name)));
+ return drush_set_error('HACKED_PROJECT_NOT_FOUND', dt('You must specify the name of a project.'));
}
$project = hacked_project_load($short_name);
$project->identify_project();
if (!$project->project_identified) {
- return drush_set_error('HACKED_PROJECT_NOT_FOUND', dt('Could not find project: @project', array('@project' => $short_name)));
+ return drush_set_error('HACKED_PROJECT_NOT_FOUND', dt('Unable to find "@project".', array(
+ '@project' => $short_name,
+ )));
}
- $project = NULL;
}
/**
- * Drush command callback that shows the list of changes/unchanged files in a project.
- *
- * You may specify the --include-unchanged option to show unchanged files too,
- * otherwise just the changed and deleted files are shown.
+ * Command callback for drush hacked_details.
*/
function drush_hacked_details($short_name) {
$project = hacked_project_load($short_name);
@@ -301,48 +352,44 @@ function drush_hacked_details($short_name) {
if (!$show_unchanged && $status == HACKED_STATUS_UNHACKED) {
continue;
}
- $row = array(
- );
+ $row = array();
// Now add the status:
switch ($status) {
case HACKED_STATUS_UNHACKED:
$row[] = dt('Unchanged');
break;
+
case HACKED_STATUS_HACKED:
- $row[] = t('Changed');
+ $row[] = dt('Changed');
break;
+
case HACKED_STATUS_DELETED:
- $row[] = t('Deleted');
+ $row[] = dt('Deleted');
break;
+
case HACKED_STATUS_UNCHECKED:
default:
- $row[] = t('Unchecked');
+ $row[] = dt('Unchecked');
break;
+
}
$row[] = $file;
-
-
$rows[] = $row;
}
drush_print_table($rows, TRUE);
-
-
}
/**
- * Validate hook for the hacked_diff drush command.
+ * Validation callback for drush hacked_diff.
*/
function drush_hacked_diff_validate($short_name = '') {
return drush_hacked_drush_command_validate($short_name);
}
/**
- * Drush command callback that shows the list of changes/unchanged files in a project.
- *
- * You may specify the --include-unchanged option to show unchanged files too,
- * otherwise just the changed and deleted files are shown.
+ * Command callback for drush hacked_diff.
*/
function drush_hacked_diff($short_name) {
$project = hacked_project_load($short_name);
@@ -375,9 +422,18 @@ function drush_hacked_diff($short_name) {
$line = str_replace($clean_location_trim, 'a/', $line);
$line = str_replace($local_location_trim, 'b/', $line);
}
-
drush_print($line);
-
}
+}
+/**
+ * Implements hook_drush_command_alter().
+ */
+function hacked_drush_command_alter(&$command) {
+ if ($command['command'] == 'audit_security') {
+ $command['checks'][] = array(
+ 'name' => 'Hacked',
+ 'location' => __DIR__ . '/hacked.site_audit.inc',
+ );
+ }
}
diff --git a/hacked.module b/hacked.module
index d51f97f..8ccbad5 100644
--- a/hacked.module
+++ b/hacked.module
@@ -19,6 +19,10 @@ define('HACKED_STATUS_UNHACKED', 5);
define('HACKED_DEFAULT_FILE_HASHER', 'hacked_ignore_line_endings');
+if (function_exists('hacked_menu')) {
+ return;
+}
+
/**
* Implementation of hook_menu().
*/
@@ -153,7 +157,6 @@ function hacked_permission() {
* So you'll want to be very careful if you call this!
*/
function hacked_calculate_project_data($projects, $force = FALSE, $redirect = NULL) {
-
// Try to get the report form cache if we can.
$cache = cache_get('hacked:full-report', HACKED_CACHE_TABLE);
if (!empty($cache->data) && !$force) {
@@ -339,7 +342,12 @@ function hacked_get_file_hasher($name = NULL) {
if (is_null($name)) {
$name = variable_get('hacked_selected_file_hasher', HACKED_DEFAULT_FILE_HASHER);
}
- $hashers = hacked_get_file_hashers();
+ if (!module_exists('hacked')) {
+ $hashers = hacked_hacked_file_hashers_info();
+ }
+ else {
+ $hashers = hacked_get_file_hashers();
+ }
$class_name = $hashers[$name]['class'];
return new $class_name;
}
diff --git a/hacked.report.inc b/hacked.report.inc
index 20659a8..4117617 100644
--- a/hacked.report.inc
+++ b/hacked.report.inc
@@ -1,5 +1,8 @@
compute_report();
$context['message'] = t('Finished processing: @name', array('@name' => $project->title()));
diff --git a/hacked.site_audit.inc b/hacked.site_audit.inc
new file mode 100644
index 0000000..0d934e0
--- /dev/null
+++ b/hacked.site_audit.inc
@@ -0,0 +1,110 @@
+' . $ret_val . '
';
+ $ret_val .= '';
+ $ret_val .= 'Name | Title | Version | Changed |
';
+ $ret_val .= '';
+ foreach ($this->registry['hacked'] as $row) {
+ $ret_val .= '' . implode(' | ', $row) . ' |
';
+ }
+ $ret_val .= '';
+ $ret_val .= '
';
+ }
+ else {
+ foreach ($this->registry['hacked'] as $row) {
+ $ret_val .= PHP_EOL . str_repeat(' ', 6);
+ $ret_val .= $row['project_name'] . ' v' . $row['project_version'];
+ $ret_val .= ': ' . $row['lines_different'] . ' line(s)';
+ }
+ }
+ return $ret_val;
+ }
+
+ /**
+ * Implements \SiteAudit\Check\Abstract\getAction().
+ */
+ public function getAction() {}
+
+ /**
+ * Implements \SiteAudit\Check\Abstract\calculateScore().
+ */
+ public function calculateScore() {
+ $result = drush_invoke_process('@self', 'hacked-list-projects', array(), array('--include-unchanged=0', '--strict=0'), FALSE);
+ if ($result === FALSE) {
+ return SiteAuditCheckAbstract::AUDIT_CHECK_SCORE_INFO;
+ }
+
+ $rows = array();
+ foreach ($result['object'] as $info) {
+ if ($info['counts']['different'] != 0) {
+ $rows[] = array(
+ 'project_name' => $info['project_name'],
+ 'project_title' => $info['title'],
+ 'project_version' => $info['existing_version'],
+ 'lines_different' => $info['counts']['different'],
+ );
+ }
+ }
+
+ $this->registry['hacked'] = $result;
+ if (empty($result['object'])) {
+ return SiteAuditCheckAbstract::AUDIT_CHECK_SCORE_FAIL;
+ }
+ else {
+ if (!empty($rows)) {
+ $this->registry['hacked'] = $rows;
+ return SiteAuditCheckAbstract::AUDIT_CHECK_SCORE_WARN;
+ }
+ else {
+ return SiteAuditCheckAbstract::AUDIT_CHECK_SCORE_PASS;
+ }
+ }
+ }
+}
--
2.5.0