commit 5e8508b4a0f1fce92c1f2b56156d92b39d112215 Author: Randy Fay Date: Fri Apr 8 15:36:48 2011 -0600 Issue #1107552 by rfay: Use git to apply patches diff --git a/client/review/vcs/git.inc b/client/review/vcs/git.inc index 5dc538d..bf7e2da 100644 --- a/client/review/vcs/git.inc +++ b/client/review/vcs/git.inc @@ -22,6 +22,11 @@ class pifr_client_vcs_git extends pifr_client_vcs { */ protected $patch_level = 0; + /** + * Array of files that should be checked after patch application. + */ + protected $files_affected_by_patch = array(); + /** * Check out a given repo URL into given directory. @@ -87,9 +92,12 @@ class pifr_client_vcs_git extends pifr_client_vcs { */ public function apply($patch) { foreach($this->patch_levels_to_try as $patch_level) { - $result = pifr_client_review::exec("patch -p$patch_level -i $patch"); + $result = pifr_client_review::exec("git apply -p$patch_level --check $patch", TRUE); if ($result) { $this->patch_level = $patch_level; + $git_output = ""; + $git_command_result = pifr_client_review::exec("git apply -v -p$patch_level $patch", TRUE, $git_output); + $this->files_affected_by_patch = $this->determine_files_affected_by_patch($git_output); return TRUE; } } @@ -97,6 +105,37 @@ class pifr_client_vcs_git extends pifr_client_vcs { } /** + * Given output from a git patch application, determine what files changed. + * + * The git apply -v output looks like this: + * Applied patch junkincludes/token.inc cleanly. + * Applied patch includes/database/prefetch.inc => junkincludes/database/prefetch.inc cleanly. + * The regular expression is used to capture the destination filename. + * Then we check for existence (as git may list files that no longer exist). + * Finally, return the list of files affected by the patch. + * + * @param $string + * The output from the git apply -v command. + * @return + * Array containing the files affected by the patch. + */ + public function determine_files_affected_by_patch($string) { + $regex = '%Applied\spatch\s* # Key start of string + (?:.*=>\s*)? # Skip optional renames that end in => + (.*?) # Now capture the filename (non-greedy) + \s*cleanly\. # Finally match the ending "cleanly." + %x'; + $num_matches = preg_match_all($regex, $string, $matches); + $files = $matches[1]; + foreach ($files as $index => $filename) { + if (!file_exists($filename)) { + unset($files[$index]); + } + } + return $files; + } + + /** * Inspect the patch to determine which files should have changed. * * $this->patch_level has already been initialized by $this->apply(), and @@ -108,23 +147,7 @@ class pifr_client_vcs_git extends pifr_client_vcs { * initialize $this->patch_level. */ public function changed_files($patch) { - $contents = file_get_contents($patch); - // This regex looks through the patch file for lines of the format - // +++ b/install.php - // and removes the '+++ b/' from them, returning the filenames that have - // had content added. - $patch_level = $this->patch_level; - $regex = '%^[\+-]{3}\s+([^/]\/){' . $patch_level . '}(.*?)\s%m'; - preg_match_all($regex, $contents, $matches, PREG_SET_ORDER); - - $files = array(); - foreach ($matches as $match) { - // $match[2] is the file. $match[1] is the prefixes. - if ($match[2] != '/dev/null') { - $files[] = $match[2]; - } - } - return array_unique($files); + return $this->files_affected_by_patch; } public function get_display($url, $branch) { diff --git a/review/client.inc b/review/client.inc index cbf9bdf..ec684bf 100644 --- a/review/client.inc +++ b/review/client.inc @@ -738,17 +738,19 @@ abstract class pifr_client_review { * stdout and collecting it on failure in the review log. * @return boolean TRUE if success, otherwise FALSE. */ - public static function exec($command, $capture_stderr = TRUE) { + public static function exec($command, $capture_stderr = TRUE, &$returned_output = NULL) { if ($capture_stderr) { $command .= ' 2>&1'; } $cwd = getcwd(); $now = time(); + exec($command, $output, $status); $duration = time() - $now; - self::$instance->output = $output; $output = trim(implode("\n", $output)); + + self::$instance->output = $returned_output = $output; if ($status != 0) { self::$instance->log("Command [$command] failed\n Duration $duration seconds\n Directory [$cwd]\n Status [$status]\n Output: " . ($output ? "[$output]" : 'no output') . '.'); return FALSE; @@ -763,10 +765,11 @@ abstract class pifr_client_review { * @param string $command Command to execute. * @param boolean $capture_stderr Capture the stderr by mapping it to the * stdout and collecting it on failure in the review log. + * @param boolean $shell_return_value TRUE if success, FALSE if failure. * @return string Command output. */ - public static function exec_output($command, $capture_stderr = TRUE) { - self::exec($command, $capture_stderr); + public static function exec_output($command, $capture_stderr = TRUE, &$shell_return_value = TRUE) { + $shell_return_value = self::exec($command, $capture_stderr); return self::$instance->output; } } diff --git a/review/simpletest/pifr_simpletest.client.inc b/review/simpletest/pifr_simpletest.client.inc index 21b08bb..d86e802 100644 --- a/review/simpletest/pifr_simpletest.client.inc +++ b/review/simpletest/pifr_simpletest.client.inc @@ -276,7 +276,7 @@ class pifr_client_review_pifr_simpletest extends pifr_client_review_pifr_drupal // Remove class name keys. $result['data'] = array_values($result['data']); - // Assign the code bassed on the test results. + // Assign the code based on the test results. $result['code'] = $this->result_codes[$result['details']['@fail'] + $result['details']['@exception'] ? 'fail' : 'pass']; } return $result; diff --git a/server/confirmation/apply.patch b/server/confirmation/apply.patch index d26596c..32cf171 100644 --- a/server/confirmation/apply.patch +++ b/server/confirmation/apply.patch @@ -1 +1,7 @@ -fail to apply +diff --git a/garbage_file.txt b/garbage_file.txt +index e69de29..3e045ff 100644 +--- a/garbage_file.txt ++++ b/garbage_file.txt +@@ -0,0 +1,2 @@ ++ ++This just contains garbage