diff --git a/src/applications/differential/engine/DifferentialChangesetEngine.php b/src/applications/differential/engine/DifferentialChangesetEngine.php --- a/src/applications/differential/engine/DifferentialChangesetEngine.php +++ b/src/applications/differential/engine/DifferentialChangesetEngine.php @@ -2,9 +2,22 @@ final class DifferentialChangesetEngine extends Phobject { + private $viewer; + + public function setViewer(PhabricatorUser $viewer) { + $this->viewer = $viewer; + return $this; + } + + public function getViewer() { + return $this->viewer; + } + public function rebuildChangesets(array $changesets) { assert_instances_of($changesets, 'DifferentialChangeset'); + $changesets = $this->loadChangesetFiles($changesets); + foreach ($changesets as $changeset) { $this->detectGeneratedCode($changeset); $this->computeHashes($changeset); @@ -13,6 +26,45 @@ $this->detectCopiedCode($changesets); } + private function loadChangesetFiles(array $changesets) { + $viewer = $this->getViewer(); + + $file_phids = array(); + foreach ($changesets as $changeset) { + $file_phid = $changeset->getNewFileObjectPHID(); + if ($file_phid !== null) { + $file_phids[] = $file_phid; + } + } + + if ($file_phids) { + $files = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withPHIDs($file_phids) + ->execute(); + $files = mpull($files, null, 'getPHID'); + } else { + $files = array(); + } + + foreach ($changesets as $changeset_key => $changeset) { + $file_phid = $changeset->getNewFileObjectPHID(); + if ($file_phid === null) { + continue; + } + + $file = idx($files, $file_phid); + if (!$file) { + unset($changesets[$changeset_key]); + continue; + } + + $changeset->attachNewFileObject($file); + } + + return $changesets; + } + /* -( Generated Code )----------------------------------------------------- */ @@ -86,6 +138,20 @@ return PhabricatorHash::digestForIndex($new_data); } + if ($changeset->getNewFileObjectPHID()) { + $file = $changeset->getNewFileObject(); + + // See T13522. For now, the "contentHash" is not really a content hash + // for files >4MB. This is okay: we will just always detect them as + // changed, which is the safer behavior. + + $hash = $file->getContentHash(); + if ($hash !== null) { + $hash = sprintf('file-hash:%s', $hash); + return PhabricatorHash::digestForIndex($hash); + } + } + return null; } diff --git a/src/applications/differential/management/PhabricatorDifferentialRebuildChangesetsWorkflow.php b/src/applications/differential/management/PhabricatorDifferentialRebuildChangesetsWorkflow.php --- a/src/applications/differential/management/PhabricatorDifferentialRebuildChangesetsWorkflow.php +++ b/src/applications/differential/management/PhabricatorDifferentialRebuildChangesetsWorkflow.php @@ -80,6 +80,7 @@ } id(new DifferentialChangesetEngine()) + ->setViewer($viewer) ->rebuildChangesets($changesets); foreach ($changesets as $changeset) { diff --git a/src/applications/differential/parser/DifferentialChangesetParser.php b/src/applications/differential/parser/DifferentialChangesetParser.php --- a/src/applications/differential/parser/DifferentialChangesetParser.php +++ b/src/applications/differential/parser/DifferentialChangesetParser.php @@ -1827,8 +1827,6 @@ if (!$vs) { $metadata = $this->changeset->getMetadata(); - $data = idx($metadata, 'attachment-data'); - $old_phid = idx($metadata, 'old:binary-phid'); $new_phid = idx($metadata, 'new:binary-phid'); } else { diff --git a/src/applications/differential/storage/DifferentialChangeset.php b/src/applications/differential/storage/DifferentialChangeset.php --- a/src/applications/differential/storage/DifferentialChangeset.php +++ b/src/applications/differential/storage/DifferentialChangeset.php @@ -25,6 +25,9 @@ private $authorityPackages; private $changesetPackages; + private $newFileObject = self::ATTACHABLE; + private $oldFileObject = self::ATTACHABLE; + const TABLE_CACHE = 'differential_changeset_parse_cache'; const METADATA_TRUSTED_ATTRIBUTES = 'attributes.trusted'; @@ -459,6 +462,34 @@ return $this->getChangesetAttribute(self::ATTRIBUTE_GENERATED); } + public function getNewFileObjectPHID() { + $metadata = $this->getMetadata(); + return idx($metadata, 'new:binary-phid'); + } + + public function getOldFileObjectPHID() { + $metadata = $this->getMetadata(); + return idx($metadata, 'old:binary-phid'); + } + + public function attachNewFileObject(PhabricatorFile $file) { + $this->newFileObject = $file; + return $this; + } + + public function getNewFileObject() { + return $this->assertAttached($this->newFileObject); + } + + public function attachOldFileObject(PhabricatorFile $file) { + $this->oldFileObject = $file; + return $this; + } + + public function getOldFileObject() { + return $this->assertAttached($this->oldFileObject); + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff --git a/src/applications/differential/storage/DifferentialDiff.php b/src/applications/differential/storage/DifferentialDiff.php --- a/src/applications/differential/storage/DifferentialDiff.php +++ b/src/applications/differential/storage/DifferentialDiff.php @@ -232,7 +232,12 @@ $changesets = $diff->getChangesets(); + // TODO: This is "safe", but it would be better to propagate a real user + // down the stack. + $viewer = PhabricatorUser::getOmnipotentUser(); + id(new DifferentialChangesetEngine()) + ->setViewer($viewer) ->rebuildChangesets($changesets); return $diff;