public static function createDiffDict(DifferentialDiff $diff)
 {
     $dict = array('id' => $diff->getID(), 'parent' => $diff->getParentRevisionID(), 'sourceControlBaseRevision' => $diff->getSourceControlBaseRevision(), 'sourceControlPath' => $diff->getSourceControlPath(), 'changes' => array());
     foreach ($diff->getChangesets() as $changeset) {
         $hunks = array();
         foreach ($changeset->getHunks() as $hunk) {
             $hunks[] = array('oldOffset' => $hunk->getOldOffset(), 'newOffset' => $hunk->getNewOffset(), 'oldLength' => $hunk->getOldLen(), 'newLength' => $hunk->getNewLen(), 'addLines' => null, 'delLines' => null, 'isMissingOldNewline' => null, 'isMissingNewNewline' => null, 'corpus' => $hunk->getChanges());
         }
         $change = array('metadata' => $changeset->getMetadata(), 'oldPath' => $changeset->getOldFile(), 'currentPath' => $changeset->getFileName(), 'awayPaths' => $changeset->getAwayPaths(), 'oldProperties' => $changeset->getOldProperties(), 'newProperties' => $changeset->getNewProperties(), 'type' => $changeset->getChangeType(), 'fileType' => $changeset->getFileType(), 'commitHash' => null, 'hunks' => $hunks);
         $dict['changes'][] = $change;
     }
     return $dict;
 }
 private function loadChangedByCommit(DifferentialDiff $diff)
 {
     $repository = $this->repository;
     $vs_changesets = array();
     $vs_diff = id(new DifferentialDiff())->loadOneWhere('revisionID = %d AND creationMethod != %s ORDER BY id DESC LIMIT 1', $diff->getRevisionID(), 'commit');
     foreach ($vs_diff->loadChangesets() as $changeset) {
         $path = $changeset->getAbsoluteRepositoryPath($repository, $vs_diff);
         $path = ltrim($path, '/');
         $vs_changesets[$path] = $changeset;
     }
     $changesets = array();
     foreach ($diff->getChangesets() as $changeset) {
         $path = $changeset->getAbsoluteRepositoryPath($repository, $diff);
         $path = ltrim($path, '/');
         $changesets[$path] = $changeset;
     }
     if (array_fill_keys(array_keys($changesets), true) != array_fill_keys(array_keys($vs_changesets), true)) {
         return $vs_diff;
     }
     $hunks = id(new DifferentialHunk())->loadAllWhere('changesetID IN (%Ld)', mpull($vs_changesets, 'getID'));
     $hunks = mgroup($hunks, 'getChangesetID');
     foreach ($vs_changesets as $changeset) {
         $changeset->attachHunks(idx($hunks, $changeset->getID(), array()));
     }
     $file_phids = array();
     foreach ($vs_changesets as $changeset) {
         $metadata = $changeset->getMetadata();
         $file_phid = idx($metadata, 'new:binary-phid');
         if ($file_phid) {
             $file_phids[$file_phid] = $file_phid;
         }
     }
     $files = array();
     if ($file_phids) {
         $files = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $file_phids);
         $files = mpull($files, null, 'getPHID');
     }
     foreach ($changesets as $path => $changeset) {
         $vs_changeset = $vs_changesets[$path];
         $file_phid = idx($vs_changeset->getMetadata(), 'new:binary-phid');
         if ($file_phid) {
             if (!isset($files[$file_phid])) {
                 return $vs_diff;
             }
             $drequest = DiffusionRequest::newFromDictionary(array('repository' => $this->repository, 'commit' => $this->commit->getCommitIdentifier(), 'path' => $path));
             $corpus = DiffusionFileContentQuery::newFromDiffusionRequest($drequest)->loadFileContent()->getCorpus();
             if ($files[$file_phid]->loadFileData() != $corpus) {
                 return $vs_diff;
             }
         } else {
             $context = implode("\n", $changeset->makeChangesWithContext());
             $vs_context = implode("\n", $vs_changeset->makeChangesWithContext());
             // We couldn't just compare $context and $vs_context because following
             // diffs will be considered different:
             //
             //   -(empty line)
             //   -echo 'test';
             //    (empty line)
             //
             //    (empty line)
             //   -echo "test";
             //   -(empty line)
             $hunk = id(new DifferentialHunk())->setChanges($context);
             $vs_hunk = id(new DifferentialHunk())->setChanges($vs_context);
             if ($hunk->makeOldFile() != $vs_hunk->makeOldFile() || $hunk->makeNewFile() != $vs_hunk->makeNewFile()) {
                 return $vs_diff;
             }
         }
     }
     return null;
 }
 private function renderPatchForMail(DifferentialDiff $diff)
 {
     $format = PhabricatorEnv::getEnvConfig('metamta.differential.patch-format');
     $patch = id(new DifferentialRawDiffRenderer())->setViewer($this->getActor())->setFormat($format)->setChangesets($diff->getChangesets())->buildPatch();
     $section = new PhabricatorMetaMTAMailSection();
     $section->addHTMLFragment($this->renderPatchHTMLForMail($patch));
     $section->addPlaintextFragment($patch);
     return $section;
 }
 private static function buildChangesetsFromRawChanges(DifferentialDiff $diff, array $changes)
 {
     // There may not be any changes; initialize the changesets list so that
     // we don't throw later when accessing it.
     $diff->attachChangesets(array());
     $lines = 0;
     foreach ($changes as $change) {
         if ($change->getType() == ArcanistDiffChangeType::TYPE_MESSAGE) {
             // If a user pastes a diff into Differential which includes a commit
             // message (e.g., they ran `git show` to generate it), discard that
             // change when constructing a DifferentialDiff.
             continue;
         }
         $changeset = new DifferentialChangeset();
         $add_lines = 0;
         $del_lines = 0;
         $first_line = PHP_INT_MAX;
         $hunks = $change->getHunks();
         if ($hunks) {
             foreach ($hunks as $hunk) {
                 $dhunk = new DifferentialModernHunk();
                 $dhunk->setOldOffset($hunk->getOldOffset());
                 $dhunk->setOldLen($hunk->getOldLength());
                 $dhunk->setNewOffset($hunk->getNewOffset());
                 $dhunk->setNewLen($hunk->getNewLength());
                 $dhunk->setChanges($hunk->getCorpus());
                 $changeset->addUnsavedHunk($dhunk);
                 $add_lines += $hunk->getAddLines();
                 $del_lines += $hunk->getDelLines();
                 $added_lines = $hunk->getChangedLines('new');
                 if ($added_lines) {
                     $first_line = min($first_line, head_key($added_lines));
                 }
             }
             $lines += $add_lines + $del_lines;
         } else {
             // This happens when you add empty files.
             $changeset->attachHunks(array());
         }
         $metadata = $change->getAllMetadata();
         if ($first_line != PHP_INT_MAX) {
             $metadata['line:first'] = $first_line;
         }
         $changeset->setOldFile($change->getOldPath());
         $changeset->setFilename($change->getCurrentPath());
         $changeset->setChangeType($change->getType());
         $changeset->setFileType($change->getFileType());
         $changeset->setMetadata($metadata);
         $changeset->setOldProperties($change->getOldProperties());
         $changeset->setNewProperties($change->getNewProperties());
         $changeset->setAwayPaths($change->getAwayPaths());
         $changeset->setAddLines($add_lines);
         $changeset->setDelLines($del_lines);
         $diff->addUnsavedChangeset($changeset);
     }
     $diff->setLineCount($lines);
     $parser = new DifferentialChangesetParser();
     $changesets = $parser->detectCopiedCode($diff->getChangesets(), $min_width = 30, $min_lines = 3);
     $diff->attachChangesets($changesets);
     return $diff;
 }
 private function buildPatchForMail(DifferentialDiff $diff)
 {
     $format = PhabricatorEnv::getEnvConfig('metamta.differential.patch-format');
     return id(new DifferentialRawDiffRenderer())->setViewer($this->getActor())->setFormat($format)->setChangesets($diff->getChangesets())->buildPatch();
 }
 private function loadChangedByCommit(DifferentialRevision $revision, DifferentialDiff $diff)
 {
     $repository = $this->repository;
     $vs_diff = id(new DifferentialDiffQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withRevisionIDs(array($revision->getID()))->needChangesets(true)->setLimit(1)->executeOne();
     if (!$vs_diff) {
         return null;
     }
     if ($vs_diff->getCreationMethod() == 'commit') {
         return null;
     }
     $vs_changesets = array();
     foreach ($vs_diff->getChangesets() as $changeset) {
         $path = $changeset->getAbsoluteRepositoryPath($repository, $vs_diff);
         $path = ltrim($path, '/');
         $vs_changesets[$path] = $changeset;
     }
     $changesets = array();
     foreach ($diff->getChangesets() as $changeset) {
         $path = $changeset->getAbsoluteRepositoryPath($repository, $diff);
         $path = ltrim($path, '/');
         $changesets[$path] = $changeset;
     }
     if (array_fill_keys(array_keys($changesets), true) != array_fill_keys(array_keys($vs_changesets), true)) {
         return $vs_diff;
     }
     $file_phids = array();
     foreach ($vs_changesets as $changeset) {
         $metadata = $changeset->getMetadata();
         $file_phid = idx($metadata, 'new:binary-phid');
         if ($file_phid) {
             $file_phids[$file_phid] = $file_phid;
         }
     }
     $files = array();
     if ($file_phids) {
         $files = id(new PhabricatorFileQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs($file_phids)->execute();
         $files = mpull($files, null, 'getPHID');
     }
     foreach ($changesets as $path => $changeset) {
         $vs_changeset = $vs_changesets[$path];
         $file_phid = idx($vs_changeset->getMetadata(), 'new:binary-phid');
         if ($file_phid) {
             if (!isset($files[$file_phid])) {
                 return $vs_diff;
             }
             $drequest = DiffusionRequest::newFromDictionary(array('user' => PhabricatorUser::getOmnipotentUser(), 'repository' => $this->repository, 'commit' => $this->commit->getCommitIdentifier(), 'path' => $path));
             $corpus = DiffusionFileContentQuery::newFromDiffusionRequest($drequest)->setViewer(PhabricatorUser::getOmnipotentUser())->loadFileContent()->getCorpus();
             if ($files[$file_phid]->loadFileData() != $corpus) {
                 return $vs_diff;
             }
         } else {
             $context = implode("\n", $changeset->makeChangesWithContext());
             $vs_context = implode("\n", $vs_changeset->makeChangesWithContext());
             // We couldn't just compare $context and $vs_context because following
             // diffs will be considered different:
             //
             //   -(empty line)
             //   -echo 'test';
             //    (empty line)
             //
             //    (empty line)
             //   -echo "test";
             //   -(empty line)
             $hunk = id(new DifferentialModernHunk())->setChanges($context);
             $vs_hunk = id(new DifferentialModernHunk())->setChanges($vs_context);
             if ($hunk->makeOldFile() != $vs_hunk->makeOldFile() || $hunk->makeNewFile() != $vs_hunk->makeNewFile()) {
                 return $vs_diff;
             }
         }
     }
     return null;
 }
 public function isDiffChangedBeforeCommit(PhabricatorRepositoryCommit $commit, DifferentialDiff $old, DifferentialDiff $new)
 {
     $viewer = $this->getViewer();
     $repository = $commit->getRepository();
     $identifier = $commit->getCommitIdentifier();
     $vs_changesets = array();
     foreach ($old->getChangesets() as $changeset) {
         $path = $changeset->getAbsoluteRepositoryPath($repository, $old);
         $path = ltrim($path, '/');
         $vs_changesets[$path] = $changeset;
     }
     $changesets = array();
     foreach ($new->getChangesets() as $changeset) {
         $path = $changeset->getAbsoluteRepositoryPath($repository, $new);
         $path = ltrim($path, '/');
         $changesets[$path] = $changeset;
     }
     if (array_fill_keys(array_keys($changesets), true) != array_fill_keys(array_keys($vs_changesets), true)) {
         return true;
     }
     $file_phids = array();
     foreach ($vs_changesets as $changeset) {
         $metadata = $changeset->getMetadata();
         $file_phid = idx($metadata, 'new:binary-phid');
         if ($file_phid) {
             $file_phids[$file_phid] = $file_phid;
         }
     }
     $files = array();
     if ($file_phids) {
         $files = id(new PhabricatorFileQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs($file_phids)->execute();
         $files = mpull($files, null, 'getPHID');
     }
     foreach ($changesets as $path => $changeset) {
         $vs_changeset = $vs_changesets[$path];
         $file_phid = idx($vs_changeset->getMetadata(), 'new:binary-phid');
         if ($file_phid) {
             if (!isset($files[$file_phid])) {
                 return true;
             }
             $drequest = DiffusionRequest::newFromDictionary(array('user' => $viewer, 'repository' => $repository));
             $response = DiffusionQuery::callConduitWithDiffusionRequest($viewer, $drequest, 'diffusion.filecontentquery', array('commit' => $identifier, 'path' => $path));
             $new_file_phid = $response['filePHID'];
             if (!$new_file_phid) {
                 return true;
             }
             $new_file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($new_file_phid))->executeOne();
             if (!$new_file) {
                 return true;
             }
             if ($files[$file_phid]->loadFileData() != $new_file->loadFileData()) {
                 return true;
             }
         } else {
             $context = implode("\n", $changeset->makeChangesWithContext());
             $vs_context = implode("\n", $vs_changeset->makeChangesWithContext());
             // We couldn't just compare $context and $vs_context because following
             // diffs will be considered different:
             //
             //   -(empty line)
             //   -echo 'test';
             //    (empty line)
             //
             //    (empty line)
             //   -echo "test";
             //   -(empty line)
             $hunk = id(new DifferentialModernHunk())->setChanges($context);
             $vs_hunk = id(new DifferentialModernHunk())->setChanges($vs_context);
             if ($hunk->makeOldFile() != $vs_hunk->makeOldFile() || $hunk->makeNewFile() != $vs_hunk->makeNewFile()) {
                 return true;
             }
         }
     }
     return false;
 }
 private function buildPatch()
 {
     $diff = new DifferentialDiff();
     $diff->attachChangesets($this->getChangesets());
     // TODO: We could batch this to improve performance.
     foreach ($diff->getChangesets() as $changeset) {
         $changeset->attachHunks($changeset->loadHunks());
     }
     $diff_dict = $diff->getDiffDict();
     $changes = array();
     foreach ($diff_dict['changes'] as $changedict) {
         $changes[] = ArcanistDiffChange::newFromDictionary($changedict);
     }
     $bundle = ArcanistBundle::newFromChanges($changes);
     $bundle->setLoadFileDataCallback(array($this, 'loadFileByPHID'));
     $format = PhabricatorEnv::getEnvConfig('metamta.differential.patch-format');
     switch ($format) {
         case 'git':
             return $bundle->toGitPatch();
             break;
         case 'unified':
         default:
             return $bundle->toUnifiedDiff();
             break;
     }
 }