[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Utility class which encapsulates some shared behavior between different 5 * applications which render diffs. 6 * 7 * @task config Configuring the Engine 8 * @task diff Generating Diffs 9 */ 10 final class PhabricatorDifferenceEngine { 11 12 13 private $ignoreWhitespace; 14 private $oldName; 15 private $newName; 16 17 18 /* -( Configuring the Engine )--------------------------------------------- */ 19 20 21 /** 22 * If true, ignore whitespace when computing differences. 23 * 24 * @param bool Ignore whitespace? 25 * @return this 26 * @task config 27 */ 28 public function setIgnoreWhitespace($ignore_whitespace) { 29 $this->ignoreWhitespace = $ignore_whitespace; 30 return $this; 31 } 32 33 34 /** 35 * Set the name to identify the old file with. Primarily cosmetic. 36 * 37 * @param string Old file name. 38 * @return this 39 * @task config 40 */ 41 public function setOldName($old_name) { 42 $this->oldName = $old_name; 43 return $this; 44 } 45 46 47 /** 48 * Set the name to identify the new file with. Primarily cosmetic. 49 * 50 * @param string New file name. 51 * @return this 52 * @task config 53 */ 54 public function setNewName($new_name) { 55 $this->newName = $new_name; 56 return $this; 57 } 58 59 60 /* -( Generating Diffs )--------------------------------------------------- */ 61 62 63 /** 64 * Generate a raw diff from two raw files. This is a lower-level API than 65 * @{method:generateChangesetFromFileContent}, but may be useful if you need 66 * to use a custom parser configuration, as with Diffusion. 67 * 68 * @param string Entire previous file content. 69 * @param string Entire current file content. 70 * @return string Raw diff between the two files. 71 * @task diff 72 */ 73 public function generateRawDiffFromFileContent($old, $new) { 74 75 $options = array(); 76 if ($this->ignoreWhitespace) { 77 $options[] = '-bw'; 78 } 79 80 // Generate diffs with full context. 81 $options[] = '-U65535'; 82 83 $old_name = nonempty($this->oldName, '/dev/universe').' 9999-99-99'; 84 $new_name = nonempty($this->newName, '/dev/universe').' 9999-99-99'; 85 86 $options[] = '-L'; 87 $options[] = $old_name; 88 $options[] = '-L'; 89 $options[] = $new_name; 90 91 $old_tmp = new TempFile(); 92 $new_tmp = new TempFile(); 93 94 Filesystem::writeFile($old_tmp, $old); 95 Filesystem::writeFile($new_tmp, $new); 96 list($err, $diff) = exec_manual( 97 'diff %Ls %s %s', 98 $options, 99 $old_tmp, 100 $new_tmp); 101 102 if (!$err) { 103 // This indicates that the two files are the same (or, possibly, the 104 // same modulo whitespace differences, which is why we can't do this 105 // check trivially before running `diff`). Build a synthetic, changeless 106 // diff so that we can still render the raw, unchanged file instead of 107 // being forced to just say "this file didn't change" since we don't have 108 // the content. 109 110 $entire_file = explode("\n", $old); 111 foreach ($entire_file as $k => $line) { 112 $entire_file[$k] = ' '.$line; 113 } 114 115 $len = count($entire_file); 116 $entire_file = implode("\n", $entire_file); 117 118 // TODO: If both files were identical but missing newlines, we probably 119 // get this wrong. Unclear if it ever matters. 120 121 // This is a bit hacky but the diff parser can handle it. 122 $diff = "--- {$old_name}\n". 123 "+++ {$new_name}\n". 124 "@@ -1,{$len} +1,{$len} @@\n". 125 $entire_file."\n"; 126 } else { 127 if ($this->ignoreWhitespace) { 128 129 // Under "-bw", `diff` is inconsistent about emitting "\ No newline 130 // at end of file". For instance, a long file with a change in the 131 // middle will emit a contextless "\ No newline..." at the end if a 132 // newline is removed, but not if one is added. A file with a change 133 // at the end will emit the "old" "\ No newline..." block only, even 134 // if the newline was not removed. Since we're ostensibly ignoring 135 // whitespace changes, just drop these lines if they appear anywhere 136 // in the diff. 137 138 $lines = explode("\n", $diff); 139 foreach ($lines as $key => $line) { 140 if (isset($line[0]) && $line[0] == '\\') { 141 unset($lines[$key]); 142 } 143 } 144 $diff = implode("\n", $lines); 145 } 146 } 147 148 return $diff; 149 } 150 151 152 /** 153 * Generate an @{class:DifferentialChangeset} from two raw files. This is 154 * principally useful because you can feed the output to 155 * @{class:DifferentialChangesetParser} in order to render it. 156 * 157 * @param string Entire previous file content. 158 * @param string Entire current file content. 159 * @return @{class:DifferentialChangeset} Synthetic changeset. 160 * @task diff 161 */ 162 public function generateChangesetFromFileContent($old, $new) { 163 $diff = $this->generateRawDiffFromFileContent($old, $new); 164 165 $changes = id(new ArcanistDiffParser())->parseDiff($diff); 166 $diff = DifferentialDiff::newFromRawChanges( 167 PhabricatorUser::getOmnipotentUser(), 168 $changes); 169 return head($diff->getChangesets()); 170 } 171 172 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |