Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13993650
D7734.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
D7734.diff
View Options
Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -2186,8 +2186,10 @@
'PhragmentHistoryController' => 'applications/phragment/controller/PhragmentHistoryController.php',
'PhragmentPHIDTypeFragment' => 'applications/phragment/phid/PhragmentPHIDTypeFragment.php',
'PhragmentPHIDTypeFragmentVersion' => 'applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php',
+ 'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php',
'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php',
'PhragmentUpdateController' => 'applications/phragment/controller/PhragmentUpdateController.php',
+ 'PhragmentVersionController' => 'applications/phragment/controller/PhragmentVersionController.php',
'PhragmentZIPController' => 'applications/phragment/controller/PhragmentZIPController.php',
'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php',
'PhrequentDAO' => 'applications/phrequent/storage/PhrequentDAO.php',
@@ -4786,8 +4788,10 @@
'PhragmentHistoryController' => 'PhragmentController',
'PhragmentPHIDTypeFragment' => 'PhabricatorPHIDType',
'PhragmentPHIDTypeFragmentVersion' => 'PhabricatorPHIDType',
+ 'PhragmentPatchController' => 'PhragmentController',
'PhragmentPatchUtil' => 'Phobject',
'PhragmentUpdateController' => 'PhragmentController',
+ 'PhragmentVersionController' => 'PhragmentController',
'PhragmentZIPController' => 'PhragmentController',
'PhrequentController' => 'PhabricatorController',
'PhrequentDAO' => 'PhabricatorLiskDAO',
Index: src/applications/phragment/application/PhabricatorApplicationPhragment.php
===================================================================
--- src/applications/phragment/application/PhabricatorApplicationPhragment.php
+++ src/applications/phragment/application/PhabricatorApplicationPhragment.php
@@ -39,6 +39,8 @@
'update/(?P<dblob>.*)' => 'PhragmentUpdateController',
'history/(?P<dblob>.*)' => 'PhragmentHistoryController',
'zip/(?P<dblob>.*)' => 'PhragmentZIPController',
+ 'version/(?P<id>[0-9]*)/' => 'PhragmentVersionController',
+ 'patch/(?P<aid>[0-9x]*)/(?P<bid>[0-9]*)/' => 'PhragmentPatchController',
),
);
}
Index: src/applications/phragment/controller/PhragmentHistoryController.php
===================================================================
--- src/applications/phragment/controller/PhragmentHistoryController.php
+++ src/applications/phragment/controller/PhragmentHistoryController.php
@@ -47,6 +47,7 @@
foreach ($versions as $version) {
$item = id(new PHUIObjectItemView());
$item->setHeader('Version '.$version->getSequence());
+ $item->setHref($version->getURI());
$item->addAttribute(phabricator_datetime(
$version->getDateCreated(),
$viewer));
Index: src/applications/phragment/controller/PhragmentPatchController.php
===================================================================
--- /dev/null
+++ src/applications/phragment/controller/PhragmentPatchController.php
@@ -0,0 +1,88 @@
+<?php
+
+final class PhragmentPatchController extends PhragmentController {
+
+ private $aid;
+ private $bid;
+
+ public function willProcessRequest(array $data) {
+ $this->aid = idx($data, "aid", 0);
+ $this->bid = idx($data, "bid", 0);
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ // If "aid" is "x", then it means the user wants to generate
+ // a patch of an empty file to the version specified by "bid".
+
+ $ids = array($this->aid, $this->bid);
+ if ($this->aid === "x") {
+ $ids = array($this->bid);
+ }
+
+ $versions = id(new PhragmentFragmentVersionQuery())
+ ->setViewer($viewer)
+ ->withIDs($ids)
+ ->execute();
+
+ $version_a = null;
+ if ($this->aid !== "x") {
+ $version_a = idx($versions, $this->aid, null);
+ if ($version_a === null) {
+ return new Aphront404Response();
+ }
+ }
+
+ $version_b = idx($versions, $this->bid, null);
+ if ($version_b === null) {
+ return new Aphront404Response();
+ }
+
+ $file_phids = array();
+ if ($version_a !== null) {
+ $file_phids[] = $version_a->getFilePHID();
+ }
+ $file_phids[] = $version_b->getFilePHID();
+
+ $files = id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($file_phids)
+ ->execute();
+ $files = mpull($files, null, 'getPHID');
+
+ $file_a = null;
+ if ($version_a != null) {
+ $file_a = idx($files, $version_a->getFilePHID(), null);
+ }
+ $file_b = idx($files, $version_b->getFilePHID(), null);
+
+ $patch = PhragmentPatchUtil::calculatePatch($file_a, $file_b);
+
+ if ($patch === null) {
+ throw new Exception("Unable to compute patch!");
+ }
+
+ $a_sequence = 'x';
+ if ($version_a !== null) {
+ $a_sequence = $version_a->getSequence();
+ }
+
+ $name =
+ $version_b->getFragment()->getName().'.'.
+ $a_sequence.'.'.
+ $version_b->getSequence().'.patch';
+
+ $result = PhabricatorFile::buildFromFileDataOrHash(
+ $patch,
+ array(
+ 'name' => $name,
+ 'mime-type' => 'text/plain',
+ 'ttl' => time() + 60 * 60 * 24,
+ ));
+ return id(new AphrontRedirectResponse())
+ ->setURI($result->getBestURI());
+ }
+
+}
Index: src/applications/phragment/controller/PhragmentVersionController.php
===================================================================
--- /dev/null
+++ src/applications/phragment/controller/PhragmentVersionController.php
@@ -0,0 +1,179 @@
+<?php
+
+final class PhragmentVersionController extends PhragmentController {
+
+ private $id;
+
+ public function willProcessRequest(array $data) {
+ $this->id = idx($data, "id", 0);
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $version = id(new PhragmentFragmentVersionQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($this->id))
+ ->executeOne();
+ if ($version === null) {
+ return new Aphront404Response();
+ }
+
+ $parents = $this->loadParentFragments($version->getFragment()->getPath());
+ if ($parents === null) {
+ return new Aphront404Response();
+ }
+ $current = idx($parents, count($parents) - 1, null);
+
+ $crumbs = $this->buildApplicationCrumbsWithPath($parents);
+ $crumbs->addCrumb(
+ id(new PhabricatorCrumbView())
+ ->setName(pht('View Version %d', $version->getSequence())));
+
+ $phids = array();
+ $phids[] = $version->getFilePHID();
+
+ $this->loadHandles($phids);
+
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($version->getFilePHID()))
+ ->executeOne();
+ if ($file !== null) {
+ $file_uri = $file->getBestURI();
+ }
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht(
+ "%s at version %d",
+ $version->getFragment()->getName(),
+ $version->getSequence()))
+ ->setPolicyObject($version)
+ ->setUser($viewer);
+
+ $actions = id(new PhabricatorActionListView())
+ ->setUser($viewer)
+ ->setObject($version)
+ ->setObjectURI($version->getURI());
+ $actions->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Download Version'))
+ ->setHref($file_uri)
+ ->setDisabled($file === null)
+ ->setIcon('download'));
+
+ $properties = id(new PHUIPropertyListView())
+ ->setUser($viewer)
+ ->setObject($version)
+ ->setActionList($actions);
+ $properties->addProperty(
+ pht('File'),
+ $this->renderHandlesForPHIDs(array($version->getFilePHID())));
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->addPropertyList($properties);
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $box,
+ $this->renderPatchFromPreviousVersion($version, $file),
+ $this->renderPreviousVersionList($version)),
+ array(
+ 'title' => pht('View Version'),
+ 'device' => true));
+ }
+
+ private function renderPatchFromPreviousVersion(
+ PhragmentFragmentVersion $version,
+ PhabricatorFile $file) {
+
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $previous_file = null;
+ $previous = id(new PhragmentFragmentVersionQuery())
+ ->setViewer($viewer)
+ ->withFragmentPHIDs(array($version->getFragmentPHID()))
+ ->withSequences(array($version->getSequence() - 1))
+ ->executeOne();
+ if ($previous !== null) {
+ $previous_file = id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($previous->getFilePHID()))
+ ->executeOne();
+ }
+
+ $patch = PhragmentPatchUtil::calculatePatch($previous_file, $file);
+
+ if ($patch === null) {
+ return id(new AphrontErrorView())
+ ->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
+ ->setTitle(pht("Identical Version"))
+ ->appendChild(phutil_tag(
+ 'p',
+ array(),
+ pht("This version is identical to the previous version.")));
+ }
+
+ if (strlen($patch) > 20480) {
+ // Patch is longer than 20480 characters. Trim it and let the user know.
+ $patch = substr($patch, 0, 20480)."\n...\n";
+ $patch .= pht(
+ "This patch is longer than 20480 characters. Use the link ".
+ "in the action list to download the full patch.");
+ }
+
+ return id(new PHUIObjectBoxView())
+ ->setHeader(id(new PHUIHeaderView())
+ ->setHeader(pht('Differences since previous version')))
+ ->appendChild(id(new PhabricatorSourceCodeView())
+ ->setLines(phutil_split_lines($patch)));
+ }
+
+ private function renderPreviousVersionList(
+ PhragmentFragmentVersion $version) {
+
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $previous_versions = id(new PhragmentFragmentVersionQuery())
+ ->setViewer($viewer)
+ ->withFragmentPHIDs(array($version->getFragmentPHID()))
+ ->withSequenceBefore($version->getSequence())
+ ->execute();
+
+ $list = id(new PHUIObjectItemListView())
+ ->setUser($viewer);
+
+ foreach ($previous_versions as $previous_version) {
+ $item = id(new PHUIObjectItemView());
+ $item->setHeader('Version '.$previous_version->getSequence());
+ $item->setHref($previous_version->getURI());
+ $item->addAttribute(phabricator_datetime(
+ $previous_version->getDateCreated(),
+ $viewer));
+ $item->addAction(id(new PHUIListItemView())
+ ->setIcon('patch')
+ ->setName(pht("Get Patch"))
+ ->setHref($this->getApplicationURI(
+ 'patch/'.$previous_version->getID().'/'.$version->getID())));
+ $list->addItem($item);
+ }
+
+ $item = id(new PHUIObjectItemView());
+ $item->setHeader('Prior to Version 0');
+ $item->addAttribute('Prior to any content (empty file)');
+ $item->addAction(id(new PHUIListItemView())
+ ->setIcon('patch')
+ ->setName(pht("Get Patch"))
+ ->setHref($this->getApplicationURI(
+ 'patch/x/'.$version->getID())));
+ $list->addItem($item);
+
+ return $list;
+ }
+
+}
Index: src/applications/phragment/query/PhragmentFragmentVersionQuery.php
===================================================================
--- src/applications/phragment/query/PhragmentFragmentVersionQuery.php
+++ src/applications/phragment/query/PhragmentFragmentVersionQuery.php
@@ -6,6 +6,8 @@
private $ids;
private $phids;
private $fragmentPHIDs;
+ private $sequences;
+ private $sequenceBefore;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -22,6 +24,16 @@
return $this;
}
+ public function withSequences(array $sequences) {
+ $this->sequences = $sequences;
+ return $this;
+ }
+
+ public function withSequenceBefore($current) {
+ $this->sequenceBefore = $current;
+ return $this;
+ }
+
public function loadPage() {
$table = new PhragmentFragmentVersion();
$conn_r = $table->establishConnection('r');
@@ -61,6 +73,20 @@
$this->fragmentPHIDs);
}
+ if ($this->sequences) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'sequence IN (%Ld)',
+ $this->sequences);
+ }
+
+ if ($this->sequenceBefore !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'sequence < %d',
+ $this->sequenceBefore);
+ }
+
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
Index: src/applications/phragment/storage/PhragmentFragmentVersion.php
===================================================================
--- src/applications/phragment/storage/PhragmentFragmentVersion.php
+++ src/applications/phragment/storage/PhragmentFragmentVersion.php
@@ -22,7 +22,7 @@
}
public function getURI() {
- return '/phragment/patch/'.$this->getID().'/';
+ return '/phragment/version/'.$this->getID().'/';
}
public function getFragment() {
Index: src/applications/phragment/util/PhragmentPatchUtil.php
===================================================================
--- src/applications/phragment/util/PhragmentPatchUtil.php
+++ src/applications/phragment/util/PhragmentPatchUtil.php
@@ -9,7 +9,7 @@
*
* @phutil-external-symbol class diff_match_patch
*/
- public function calculatePatch(
+ public static function calculatePatch(
PhabricatorFile $old = null,
PhabricatorFile $new = null) {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Oct 24, 12:26 AM (3 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6745509
Default Alt Text
D7734.diff (13 KB)
Attached To
Mode
D7734: Implement viewing versions and downloading patches in Phragment
Attached
Detach File
Event Timeline
Log In to Comment