diff --git a/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php b/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php --- a/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php +++ b/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php @@ -18,6 +18,7 @@ public function defineParamTypes() { return array( 'paths' => 'required list<string>', + 'snapshot' => 'string' ); } @@ -28,14 +29,17 @@ public function defineErrorTypes() { return array( 'ERR_BAD_FRAGMENT' => 'No such fragment exists', + 'ERR_BAD_SNAPSHOT' => 'No such snapshot exists', ); } protected function execute(ConduitAPIRequest $request) { $paths = $request->getValue('paths'); + $snapshot_name = $request->getValue('snapshot'); $fragments = id(new PhragmentFragmentQuery()) ->setViewer($request->getUser()) + ->needLatestVersion(true) ->withPaths($paths) ->execute(); $fragments = mpull($fragments, null, 'getPath'); @@ -47,20 +51,46 @@ $results = array(); foreach ($fragments as $path => $fragment) { - $mappings = $fragment->getFragmentMappings( + + $snapshot_cache = null; + if ($snapshot_name !== null) { + $snapshot = id(new PhragmentSnapshotQuery()) + ->setViewer($request->getUser()) + ->withPrimaryFragmentPHIDs(array($fragment->getPHID())) + ->withNames(array($snapshot_name)) + ->executeOne(); + if ($snapshot === null) { + throw new ConduitException('ERR_BAD_SNAPSHOT'); + } + + $cache = id(new PhragmentSnapshotChildQuery()) + ->setViewer($request->getUser()) + ->needFragmentVersions(true) + ->withSnapshotPHIDs(array($snapshot->getPHID())) + ->execute(); + $snapshot_cache = mpull( + $cache, + 'getFragmentVersion', + 'getFragmentPHID'); + } + + $mappings = $this->getFragmentMappings( $request->getUser(), - $fragment->getPath()); + $fragment, + $fragment->getPath(), + $snapshot_cache); - $file_phids = mpull(mpull($mappings, 'getLatestVersion'), 'getFilePHID'); $files = id(new PhabricatorFileQuery()) ->setViewer($request->getUser()) - ->withPHIDs($file_phids) + ->withPHIDs(ipull($mappings, 'filePHID')) ->execute(); $files = mpull($files, null, 'getPHID'); $result = array(); - foreach ($mappings as $cpath => $child) { - $file_phid = $child->getLatestVersion()->getFilePHID(); + foreach ($mappings as $cpath => $pair) { + $child = $pair['fragment']; + $file_phid = $pair['filePHID']; + if (!isset($files[$file_phid])) { // Skip any files we don't have permission to access. continue; @@ -70,10 +100,11 @@ $cpath = substr($child->getPath(), strlen($fragment->getPath()) + 1); $result[] = array( 'phid' => $child->getPHID(), - 'phidVersion' => $child->getLatestVersionPHID(), + 'phidVersion' => $pair['versionPHID'], 'path' => $cpath, 'hash' => $file->getContentHash(), - 'version' => $child->getLatestVersion()->getSequence(), + 'size' => $file->getByteSize(), + 'version' => $pair['version']->getSequence(), 'uri' => $file->getViewURI()); } $results[$path] = $result; @@ -81,4 +112,39 @@ return $results; } + /** + * Returns a list of mappings like array('some/path.txt' => 'file PHID'); + */ + private function getFragmentMappings( + PhabricatorUser $user, + PhragmentFragment $current, + $base_path, + $snapshot_cache) { + + $mappings = $current->getFragmentMappings( + $user, + $base_path); + + $result = array(); + foreach ($mappings as $path => $fragment) { + $version = $this->getVersion($snapshot_cache, $fragment); + if ($version !== null) { + $result[$path] = array( + 'fragment' => $fragment, + 'version' => $version, + 'versionPHID' => $version->getPHID(), + 'filePHID' => $version->getFilePHID()); + } + } + return $result; + } + + private function getVersion($snapshot_cache, $fragment) { + if ($snapshot_cache === null) { + return $fragment->getLatestVersion(); + } else { + return idx($snapshot_cache, $fragment->getPHID(), null); + } + } + }