[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/infrastructure/diff/ -> PhabricatorDifferenceEngine.php (source)

   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  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1