diff --git a/hacked.drush.inc b/hacked.drush.inc index 6997ca1..b227126 100644 --- a/hacked.drush.inc +++ b/hacked.drush.inc @@ -1,22 +1,36 @@ "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 +86,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 './includes/batch.inc'; + hacked_load_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 +98,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 +107,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 +118,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_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 +148,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_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 +183,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 +196,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 +220,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 +234,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 +244,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 +278,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 +294,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_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 +345,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 +415,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..0dc0c83 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 .= ''; + $ret_val .= ''; + foreach ($this->registry['hacked'] as $row) { + $ret_val .= ''; + } + $ret_val .= ''; + $ret_val .= '
NameTitleVersionChanged
' . implode('', $row) . '
'; + } + 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; + } + } + } +} diff --git a/includes/hacked_project.inc b/includes/hacked_project.inc index 11c44fe..4cc3b7a 100644 --- a/includes/hacked_project.inc +++ b/includes/hacked_project.inc @@ -1,7 +1,7 @@ @@ -51,7 +51,7 @@ class hackedProject { * Identify the project from the name we've been created with. * * We leverage the update (status) module to get the data we require about - * projects. We just pull the information in, and make descisions about this + * projects. We just pull the information in, and make decisions about this * project being from CVS or not. */ function identify_project() { @@ -330,7 +330,6 @@ class hackedProject { } - function file_is_diffable($file) { $this->hash_remote_project(); $this->hash_local_project(); @@ -348,9 +347,6 @@ class hackedProject { } return FALSE; } - - - } /**