mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-28 17:52:43 +01:00
Phragment v0
Summary: Ref T4205. This is an initial implementation of Phragment. You can create and browse fragments in the system (but you can't yet view a fragment's patches / history). Test Plan: Clicked around and created fragments. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley CC: Korvin, epriestley, aran Maniphest Tasks: T4205 Differential Revision: https://secure.phabricator.com/D7726
This commit is contained in:
parent
9d474452f9
commit
4c143ad3b2
16 changed files with 3047 additions and 0 deletions
2117
externals/diff_match_patch/diff_match_patch.php
vendored
Normal file
2117
externals/diff_match_patch/diff_match_patch.php
vendored
Normal file
File diff suppressed because it is too large
Load diff
24
resources/sql/patches/20131206.phragment.sql
Normal file
24
resources/sql/patches/20131206.phragment.sql
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_phragment.phragment_fragment (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
path VARCHAR(254) NOT NULL COLLATE utf8_bin,
|
||||||
|
depth INT UNSIGNED NOT NULL,
|
||||||
|
latestVersionPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
viewPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (phid),
|
||||||
|
UNIQUE KEY `key_path` (path)
|
||||||
|
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
CREATE TABLE {$NAMESPACE}_phragment.phragment_fragmentversion (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
sequence INT UNSIGNED NOT NULL,
|
||||||
|
fragmentPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
filePHID VARCHAR(64) NULL COLLATE utf8_bin,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_version` (fragmentPHID, sequence)
|
||||||
|
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
|
@ -1053,6 +1053,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorApplicationPhlux' => 'applications/phlux/application/PhabricatorApplicationPhlux.php',
|
'PhabricatorApplicationPhlux' => 'applications/phlux/application/PhabricatorApplicationPhlux.php',
|
||||||
'PhabricatorApplicationPholio' => 'applications/pholio/application/PhabricatorApplicationPholio.php',
|
'PhabricatorApplicationPholio' => 'applications/pholio/application/PhabricatorApplicationPholio.php',
|
||||||
'PhabricatorApplicationPhortune' => 'applications/phortune/application/PhabricatorApplicationPhortune.php',
|
'PhabricatorApplicationPhortune' => 'applications/phortune/application/PhabricatorApplicationPhortune.php',
|
||||||
|
'PhabricatorApplicationPhragment' => 'applications/phragment/application/PhabricatorApplicationPhragment.php',
|
||||||
'PhabricatorApplicationPhrequent' => 'applications/phrequent/application/PhabricatorApplicationPhrequent.php',
|
'PhabricatorApplicationPhrequent' => 'applications/phrequent/application/PhabricatorApplicationPhrequent.php',
|
||||||
'PhabricatorApplicationPhriction' => 'applications/phriction/application/PhabricatorApplicationPhriction.php',
|
'PhabricatorApplicationPhriction' => 'applications/phriction/application/PhabricatorApplicationPhriction.php',
|
||||||
'PhabricatorApplicationPolicy' => 'applications/policy/application/PhabricatorApplicationPolicy.php',
|
'PhabricatorApplicationPolicy' => 'applications/policy/application/PhabricatorApplicationPolicy.php',
|
||||||
|
@ -2173,6 +2174,17 @@ phutil_register_library_map(array(
|
||||||
'PhortuneTestExtraPaymentProvider' => 'applications/phortune/provider/__tests__/PhortuneTestExtraPaymentProvider.php',
|
'PhortuneTestExtraPaymentProvider' => 'applications/phortune/provider/__tests__/PhortuneTestExtraPaymentProvider.php',
|
||||||
'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php',
|
'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php',
|
||||||
'PhortuneWePayPaymentProvider' => 'applications/phortune/provider/PhortuneWePayPaymentProvider.php',
|
'PhortuneWePayPaymentProvider' => 'applications/phortune/provider/PhortuneWePayPaymentProvider.php',
|
||||||
|
'PhragmentBrowseController' => 'applications/phragment/controller/PhragmentBrowseController.php',
|
||||||
|
'PhragmentController' => 'applications/phragment/controller/PhragmentController.php',
|
||||||
|
'PhragmentCreateController' => 'applications/phragment/controller/PhragmentCreateController.php',
|
||||||
|
'PhragmentDAO' => 'applications/phragment/storage/PhragmentDAO.php',
|
||||||
|
'PhragmentFragment' => 'applications/phragment/storage/PhragmentFragment.php',
|
||||||
|
'PhragmentFragmentQuery' => 'applications/phragment/query/PhragmentFragmentQuery.php',
|
||||||
|
'PhragmentFragmentVersion' => 'applications/phragment/storage/PhragmentFragmentVersion.php',
|
||||||
|
'PhragmentFragmentVersionQuery' => 'applications/phragment/query/PhragmentFragmentVersionQuery.php',
|
||||||
|
'PhragmentPHIDTypeFragment' => 'applications/phragment/phid/PhragmentPHIDTypeFragment.php',
|
||||||
|
'PhragmentPHIDTypeFragmentVersion' => 'applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php',
|
||||||
|
'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php',
|
||||||
'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php',
|
'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php',
|
||||||
'PhrequentDAO' => 'applications/phrequent/storage/PhrequentDAO.php',
|
'PhrequentDAO' => 'applications/phrequent/storage/PhrequentDAO.php',
|
||||||
'PhrequentListController' => 'applications/phrequent/controller/PhrequentListController.php',
|
'PhrequentListController' => 'applications/phrequent/controller/PhrequentListController.php',
|
||||||
|
@ -3488,6 +3500,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorApplicationPhlux' => 'PhabricatorApplication',
|
'PhabricatorApplicationPhlux' => 'PhabricatorApplication',
|
||||||
'PhabricatorApplicationPholio' => 'PhabricatorApplication',
|
'PhabricatorApplicationPholio' => 'PhabricatorApplication',
|
||||||
'PhabricatorApplicationPhortune' => 'PhabricatorApplication',
|
'PhabricatorApplicationPhortune' => 'PhabricatorApplication',
|
||||||
|
'PhabricatorApplicationPhragment' => 'PhabricatorApplication',
|
||||||
'PhabricatorApplicationPhrequent' => 'PhabricatorApplication',
|
'PhabricatorApplicationPhrequent' => 'PhabricatorApplication',
|
||||||
'PhabricatorApplicationPhriction' => 'PhabricatorApplication',
|
'PhabricatorApplicationPhriction' => 'PhabricatorApplication',
|
||||||
'PhabricatorApplicationPolicy' => 'PhabricatorApplication',
|
'PhabricatorApplicationPolicy' => 'PhabricatorApplication',
|
||||||
|
@ -4749,6 +4762,25 @@ phutil_register_library_map(array(
|
||||||
'PhortuneTestExtraPaymentProvider' => 'PhortunePaymentProvider',
|
'PhortuneTestExtraPaymentProvider' => 'PhortunePaymentProvider',
|
||||||
'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider',
|
'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider',
|
||||||
'PhortuneWePayPaymentProvider' => 'PhortunePaymentProvider',
|
'PhortuneWePayPaymentProvider' => 'PhortunePaymentProvider',
|
||||||
|
'PhragmentBrowseController' => 'PhragmentController',
|
||||||
|
'PhragmentController' => 'PhabricatorController',
|
||||||
|
'PhragmentCreateController' => 'PhragmentController',
|
||||||
|
'PhragmentDAO' => 'PhabricatorLiskDAO',
|
||||||
|
'PhragmentFragment' =>
|
||||||
|
array(
|
||||||
|
0 => 'PhragmentDAO',
|
||||||
|
1 => 'PhabricatorPolicyInterface',
|
||||||
|
),
|
||||||
|
'PhragmentFragmentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhragmentFragmentVersion' =>
|
||||||
|
array(
|
||||||
|
0 => 'PhragmentDAO',
|
||||||
|
1 => 'PhabricatorPolicyInterface',
|
||||||
|
),
|
||||||
|
'PhragmentFragmentVersionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhragmentPHIDTypeFragment' => 'PhabricatorPHIDType',
|
||||||
|
'PhragmentPHIDTypeFragmentVersion' => 'PhabricatorPHIDType',
|
||||||
|
'PhragmentPatchUtil' => 'Phobject',
|
||||||
'PhrequentController' => 'PhabricatorController',
|
'PhrequentController' => 'PhabricatorController',
|
||||||
'PhrequentDAO' => 'PhabricatorLiskDAO',
|
'PhrequentDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhrequentListController' =>
|
'PhrequentListController' =>
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorApplicationPhragment extends PhabricatorApplication {
|
||||||
|
|
||||||
|
public function getBaseURI() {
|
||||||
|
return '/phragment/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getShortDescription() {
|
||||||
|
return pht('Versioned Artifact Storage');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIconName() {
|
||||||
|
return 'phragment';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitleGlyph() {
|
||||||
|
return "\xE2\x26\xB6";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isBeta() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canUninstall() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoutes() {
|
||||||
|
return array(
|
||||||
|
'/phragment/' => array(
|
||||||
|
'' => 'PhragmentBrowseController',
|
||||||
|
'browse/(?P<dblob>.*)' => 'PhragmentBrowseController',
|
||||||
|
'create/(?P<dblob>.*)' => 'PhragmentCreateController',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhragmentBrowseController extends PhragmentController {
|
||||||
|
|
||||||
|
private $dblob;
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
$this->dblob = idx($data, "dblob", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
$parents = $this->loadParentFragments($this->dblob);
|
||||||
|
if ($parents === null) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
$current = nonempty(last($parents), null);
|
||||||
|
|
||||||
|
$path = '';
|
||||||
|
if ($current !== null) {
|
||||||
|
$path = $current->getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbsWithPath($parents);
|
||||||
|
$crumbs->addAction(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setName(pht('Create Fragment'))
|
||||||
|
->setHref($this->getApplicationURI('/create/'.$path))
|
||||||
|
->setIcon('create'));
|
||||||
|
|
||||||
|
$current_box = $this->createCurrentFragmentView($current);
|
||||||
|
|
||||||
|
$list = id(new PHUIObjectItemListView())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
$fragments = null;
|
||||||
|
if ($current === null) {
|
||||||
|
// Find all root fragments.
|
||||||
|
$fragments = id(new PhragmentFragmentQuery())
|
||||||
|
->setViewer($this->getRequest()->getUser())
|
||||||
|
->needLatestVersion(true)
|
||||||
|
->withDepths(array(1))
|
||||||
|
->execute();
|
||||||
|
} else {
|
||||||
|
// Find all child fragments.
|
||||||
|
$fragments = id(new PhragmentFragmentQuery())
|
||||||
|
->setViewer($this->getRequest()->getUser())
|
||||||
|
->needLatestVersion(true)
|
||||||
|
->withLeadingPath($current->getPath().'/')
|
||||||
|
->withDepths(array($current->getDepth() + 1))
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($fragments as $fragment) {
|
||||||
|
$item = id(new PHUIObjectItemView());
|
||||||
|
$item->setHeader($fragment->getName());
|
||||||
|
$item->setHref($this->getApplicationURI('/browse/'.$fragment->getPath()));
|
||||||
|
$item->addAttribute(pht(
|
||||||
|
'Last Updated %s',
|
||||||
|
phabricator_datetime(
|
||||||
|
$fragment->getLatestVersion()->getDateCreated(),
|
||||||
|
$viewer)));
|
||||||
|
$item->addAttribute(pht(
|
||||||
|
'Latest Version %s',
|
||||||
|
$fragment->getLatestVersion()->getSequence()));
|
||||||
|
$list->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->buildApplicationPage(
|
||||||
|
array(
|
||||||
|
$crumbs,
|
||||||
|
$current_box,
|
||||||
|
$list),
|
||||||
|
array(
|
||||||
|
'title' => pht('Browse Phragments'),
|
||||||
|
'device' => true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createCurrentFragmentView($fragment) {
|
||||||
|
if ($fragment === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($fragment->getName())
|
||||||
|
->setPolicyObject($fragment)
|
||||||
|
->setUser($viewer);
|
||||||
|
$properties = new PHUIPropertyListView();
|
||||||
|
|
||||||
|
$phids = array();
|
||||||
|
$phids[] = $fragment->getLatestVersionPHID();
|
||||||
|
|
||||||
|
$this->loadHandles($phids);
|
||||||
|
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Latest Version'),
|
||||||
|
$this->renderHandlesForPHIDs(array($fragment->getLatestVersionPHID())));
|
||||||
|
|
||||||
|
return id(new PHUIObjectBoxView())
|
||||||
|
->setHeader($header)
|
||||||
|
->addPropertyList($properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhragmentController extends PhabricatorController {
|
||||||
|
|
||||||
|
protected function loadParentFragments($path) {
|
||||||
|
$components = explode('/', $path);
|
||||||
|
|
||||||
|
$combinations = array();
|
||||||
|
$current = '';
|
||||||
|
foreach ($components as $component) {
|
||||||
|
$current .= '/'.$component;
|
||||||
|
$current = trim($current, '/');
|
||||||
|
if (trim($current) === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$combinations[] = $current;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fragments = array();
|
||||||
|
$results = id(new PhragmentFragmentQuery())
|
||||||
|
->setViewer($this->getRequest()->getUser())
|
||||||
|
->withPaths($combinations)
|
||||||
|
->execute();
|
||||||
|
foreach ($combinations as $combination) {
|
||||||
|
$found = false;
|
||||||
|
foreach ($results as $fragment) {
|
||||||
|
if ($fragment->getPath() === $combination) {
|
||||||
|
$fragments[] = $fragment;
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$found) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $fragments;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildApplicationCrumbsWithPath(array $fragments) {
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName('/')
|
||||||
|
->setHref('/phragment/'));
|
||||||
|
foreach ($fragments as $parent) {
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName($parent->getName())
|
||||||
|
->setHref('/phragment/browse/'.$parent->getPath()));
|
||||||
|
}
|
||||||
|
return $crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhragmentCreateController extends PhragmentController {
|
||||||
|
|
||||||
|
private $dblob;
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
$this->dblob = idx($data, "dblob", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
$parent = null;
|
||||||
|
$parents = $this->loadParentFragments($this->dblob);
|
||||||
|
if ($parents === null) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
if (count($parents) !== 0) {
|
||||||
|
$parent = idx($parents, count($parents) - 1, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent_path = '';
|
||||||
|
if ($parent !== null) {
|
||||||
|
$parent_path = $parent->getPath();
|
||||||
|
}
|
||||||
|
$parent_path = trim($parent_path, '/');
|
||||||
|
|
||||||
|
$fragment = id(new PhragmentFragment());
|
||||||
|
|
||||||
|
$error_view = null;
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
$v_name = $request->getStr('name');
|
||||||
|
$v_fileid = $request->getInt('fileID');
|
||||||
|
$v_viewpolicy = $request->getStr('viewPolicy');
|
||||||
|
$v_editpolicy = $request->getStr('editPolicy');
|
||||||
|
|
||||||
|
if (strpos($v_name, '/') !== false) {
|
||||||
|
$errors[] = pht('The fragment name can not contain \'/\'.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = id(new PhabricatorFile())->load($v_fileid);
|
||||||
|
if ($file === null) {
|
||||||
|
$errors[] = pht('The specified file doesn\'t exist.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!count($errors)) {
|
||||||
|
$depth = 1;
|
||||||
|
if ($parent !== null) {
|
||||||
|
$depth = $parent->getDepth() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$version = id(new PhragmentFragmentVersion());
|
||||||
|
$version->setSequence(0);
|
||||||
|
$version->setFragmentPHID(''); // Can't set this yet...
|
||||||
|
$version->setFilePHID($file->getPHID());
|
||||||
|
$version->save();
|
||||||
|
|
||||||
|
$fragment->setPath(trim($parent_path.'/'.$v_name, '/'));
|
||||||
|
$fragment->setDepth($depth);
|
||||||
|
$fragment->setLatestVersionPHID($version->getPHID());
|
||||||
|
$fragment->setViewPolicy($v_viewpolicy);
|
||||||
|
$fragment->setEditPolicy($v_editpolicy);
|
||||||
|
$fragment->save();
|
||||||
|
|
||||||
|
$version->setFragmentPHID($fragment->getPHID());
|
||||||
|
$version->save();
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI('/phragment/browse/'.trim($parent_path.'/'.$v_name, '/'));
|
||||||
|
} else {
|
||||||
|
$error_view = id(new AphrontErrorView())
|
||||||
|
->setErrors($errors)
|
||||||
|
->setTitle(pht('Errors while creating fragment'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$policies = id(new PhabricatorPolicyQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setObject($fragment)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('Parent Path'))
|
||||||
|
->setDisabled(true)
|
||||||
|
->setValue('/'.trim($parent_path.'/', '/')))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('Name'))
|
||||||
|
->setName('name'))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('File ID'))
|
||||||
|
->setName('fileID'))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormPolicyControl())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setName('viewPolicy')
|
||||||
|
->setPolicyObject($fragment)
|
||||||
|
->setPolicies($policies)
|
||||||
|
->setCapability(PhabricatorPolicyCapability::CAN_VIEW))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormPolicyControl())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setName('editPolicy')
|
||||||
|
->setPolicyObject($fragment)
|
||||||
|
->setPolicies($policies)
|
||||||
|
->setCapability(PhabricatorPolicyCapability::CAN_EDIT))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSubmitControl())
|
||||||
|
->setValue(pht('Create Fragment'))
|
||||||
|
->addCancelButton(
|
||||||
|
$this->getApplicationURI('browse/'.$parent_path)));
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbsWithPath($parents);
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName(pht('Create Fragment')));
|
||||||
|
|
||||||
|
$box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText('Create Fragment')
|
||||||
|
->setValidationException(null)
|
||||||
|
->setForm($form);
|
||||||
|
|
||||||
|
return $this->buildApplicationPage(
|
||||||
|
array(
|
||||||
|
$crumbs,
|
||||||
|
$box),
|
||||||
|
array(
|
||||||
|
'title' => pht('Create Phragment'),
|
||||||
|
'device' => true));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhragmentPHIDTypeFragment
|
||||||
|
extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'PHRF';
|
||||||
|
|
||||||
|
public function getTypeConstant() {
|
||||||
|
return self::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Fragment');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new PhragmentFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new PhragmentFragmentQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
$viewer = $query->getViewer();
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$fragment = $objects[$phid];
|
||||||
|
|
||||||
|
$handle->setName($fragment->getID());
|
||||||
|
$handle->setURI($fragment->getURI());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadNamedObject($name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhragmentPHIDTypeFragmentVersion
|
||||||
|
extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'PHRV';
|
||||||
|
|
||||||
|
public function getTypeConstant() {
|
||||||
|
return self::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Fragment Version');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new PhragmentFragmentVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new PhragmentFragmentVersionQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
$viewer = $query->getViewer();
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$version = $objects[$phid];
|
||||||
|
|
||||||
|
$handle->setName($version->getSequence());
|
||||||
|
$handle->setURI($version->getURI());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadNamedObject($name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
131
src/applications/phragment/query/PhragmentFragmentQuery.php
Normal file
131
src/applications/phragment/query/PhragmentFragmentQuery.php
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhragmentFragmentQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $phids;
|
||||||
|
private $paths;
|
||||||
|
private $leadingPath;
|
||||||
|
private $depths;
|
||||||
|
private $needsLatestVersion;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPaths(array $paths) {
|
||||||
|
$this->paths = $paths;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withLeadingPath($path) {
|
||||||
|
$this->leadingPath = $path;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withDepths($depths) {
|
||||||
|
$this->depths = $depths;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function needLatestVersion($need_latest_version) {
|
||||||
|
$this->needsLatestVersion = $need_latest_version;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadPage() {
|
||||||
|
$table = new PhragmentFragment();
|
||||||
|
$conn_r = $table->establishConnection('r');
|
||||||
|
|
||||||
|
$data = queryfx_all(
|
||||||
|
$conn_r,
|
||||||
|
'SELECT * FROM %T %Q %Q %Q',
|
||||||
|
$table->getTableName(),
|
||||||
|
$this->buildWhereClause($conn_r),
|
||||||
|
$this->buildOrderClause($conn_r),
|
||||||
|
$this->buildLimitClause($conn_r));
|
||||||
|
|
||||||
|
return $table->loadAllFromArray($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildWhereClause($conn_r) {
|
||||||
|
$where = array();
|
||||||
|
|
||||||
|
if ($this->ids) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'id IN (%Ld)',
|
||||||
|
$this->ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->phids) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'phid IN (%Ls)',
|
||||||
|
$this->phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->paths) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'path IN (%Ls)',
|
||||||
|
$this->paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->leadingPath) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'path LIKE %>',
|
||||||
|
$this->leadingPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->depths) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'depth IN (%Ld)',
|
||||||
|
$this->depths);
|
||||||
|
}
|
||||||
|
|
||||||
|
$where[] = $this->buildPagingClause($conn_r);
|
||||||
|
|
||||||
|
return $this->formatWhereClause($where);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function didFilterPage(array $page) {
|
||||||
|
if ($this->needsLatestVersion) {
|
||||||
|
$versions = array();
|
||||||
|
|
||||||
|
$version_phids = array_filter(mpull($page, 'getLatestVersionPHID'));
|
||||||
|
if ($version_phids) {
|
||||||
|
$versions = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->withPHIDs($version_phids)
|
||||||
|
->setParentQuery($this)
|
||||||
|
->execute();
|
||||||
|
$versions = mpull($versions, null, 'getPHID');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($page as $key => $fragment) {
|
||||||
|
$version_phid = $fragment->getLatestVersionPHID();
|
||||||
|
if (empty($versions[$version_phid])) {
|
||||||
|
unset($page[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$fragment->attachLatestVersion($versions[$version_phid]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorApplicationPhragment';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhragmentFragmentVersionQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $phids;
|
||||||
|
private $fragmentPHIDs;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withFragmentPHIDs(array $fragment_phids) {
|
||||||
|
$this->fragmentPHIDs = $fragment_phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadPage() {
|
||||||
|
$table = new PhragmentFragmentVersion();
|
||||||
|
$conn_r = $table->establishConnection('r');
|
||||||
|
|
||||||
|
$data = queryfx_all(
|
||||||
|
$conn_r,
|
||||||
|
'SELECT * FROM %T %Q %Q %Q',
|
||||||
|
$table->getTableName(),
|
||||||
|
$this->buildWhereClause($conn_r),
|
||||||
|
$this->buildOrderClause($conn_r),
|
||||||
|
$this->buildLimitClause($conn_r));
|
||||||
|
|
||||||
|
return $table->loadAllFromArray($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildWhereClause($conn_r) {
|
||||||
|
$where = array();
|
||||||
|
|
||||||
|
if ($this->ids) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'id IN (%Ld)',
|
||||||
|
$this->ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->phids) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'phid IN (%Ls)',
|
||||||
|
$this->phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->fragmentPHIDs) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'fragmentPHID IN (%Ls)',
|
||||||
|
$this->fragmentPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
$where[] = $this->buildPagingClause($conn_r);
|
||||||
|
|
||||||
|
return $this->formatWhereClause($where);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function willFilterPage(array $page) {
|
||||||
|
$fragments = array();
|
||||||
|
|
||||||
|
$fragment_phids = array_filter(mpull($page, 'getFragmentPHID'));
|
||||||
|
if ($fragment_phids) {
|
||||||
|
$fragments = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->withPHIDs($fragment_phids)
|
||||||
|
->setParentQuery($this)
|
||||||
|
->execute();
|
||||||
|
$fragments = mpull($fragments, null, 'getPHID');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($page as $key => $version) {
|
||||||
|
$fragment_phid = $version->getFragmentPHID();
|
||||||
|
if (empty($fragments[$fragment_phid])) {
|
||||||
|
unset($page[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$version->attachFragment($fragments[$fragment_phid]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorApplicationPhragment';
|
||||||
|
}
|
||||||
|
}
|
9
src/applications/phragment/storage/PhragmentDAO.php
Normal file
9
src/applications/phragment/storage/PhragmentDAO.php
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhragmentDAO extends PhabricatorLiskDAO {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'phragment';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
73
src/applications/phragment/storage/PhragmentFragment.php
Normal file
73
src/applications/phragment/storage/PhragmentFragment.php
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhragmentFragment extends PhragmentDAO
|
||||||
|
implements PhabricatorPolicyInterface {
|
||||||
|
|
||||||
|
protected $path;
|
||||||
|
protected $depth;
|
||||||
|
protected $latestVersionPHID;
|
||||||
|
protected $viewPolicy;
|
||||||
|
protected $editPolicy;
|
||||||
|
|
||||||
|
private $latestVersion = self::ATTACHABLE;
|
||||||
|
|
||||||
|
public function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generatePHID() {
|
||||||
|
return PhabricatorPHID::generateNewPHID(
|
||||||
|
PhragmentPHIDTypeFragment::TYPECONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
return '/phragment/fragment/'.$this->getID().'/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return basename($this->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFile() {
|
||||||
|
return $this->assertAttached($this->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachFile(PhabricatorFile $file) {
|
||||||
|
return $this->file = $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLatestVersion() {
|
||||||
|
return $this->assertAttached($this->latestVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachLatestVersion(PhragmentFragmentVersion $version) {
|
||||||
|
return $this->latestVersion = $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
return $this->getViewPolicy();
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
return $this->getEditPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAutomaticCapability($capability) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhragmentFragmentVersion extends PhragmentDAO
|
||||||
|
implements PhabricatorPolicyInterface {
|
||||||
|
|
||||||
|
protected $sequence;
|
||||||
|
protected $fragmentPHID;
|
||||||
|
protected $filePHID;
|
||||||
|
|
||||||
|
private $fragment = self::ATTACHABLE;
|
||||||
|
private $file = self::ATTACHABLE;
|
||||||
|
|
||||||
|
public function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generatePHID() {
|
||||||
|
return PhabricatorPHID::generateNewPHID(
|
||||||
|
PhragmentPHIDTypeFragmentVersion::TYPECONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
return '/phragment/patch/'.$this->getID().'/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFragment() {
|
||||||
|
return $this->assertAttached($this->fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachFragment(PhragmentFragment $fragment) {
|
||||||
|
return $this->fragment = $fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFile() {
|
||||||
|
return $this->assertAttached($this->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachFile(PhabricatorFile $file) {
|
||||||
|
return $this->file = $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
return $this->getFragment()->getPolicy($capability);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return $this->getFragment()->hasAutomaticCapability($capability, $viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAutomaticCapability($capability) {
|
||||||
|
return $this->getFragment()->describeAutomaticCapability($capability);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
53
src/applications/phragment/util/PhragmentPatchUtil.php
Normal file
53
src/applications/phragment/util/PhragmentPatchUtil.php
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhragmentPatchUtil extends Phobject {
|
||||||
|
|
||||||
|
const EMPTY_HASH = "0000000000000000000000000000000000000000";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the DiffMatchPatch patch between two Phabricator files.
|
||||||
|
*
|
||||||
|
* @phutil-external-symbol class diff_match_patch
|
||||||
|
*/
|
||||||
|
public function calculatePatch(
|
||||||
|
PhabricatorFile $old = null,
|
||||||
|
PhabricatorFile $new = null) {
|
||||||
|
|
||||||
|
$root = dirname(phutil_get_library_root('phabricator'));
|
||||||
|
require_once $root.'/externals/diff_match_patch/diff_match_patch.php';
|
||||||
|
|
||||||
|
$old_hash = self::EMPTY_HASH;
|
||||||
|
$new_hash = self::EMPTY_HASH;
|
||||||
|
|
||||||
|
if ($old !== null) {
|
||||||
|
$old_hash = $old->getContentHash();
|
||||||
|
}
|
||||||
|
if ($new !== null) {
|
||||||
|
$new_hash = $new->getContentHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
$old_content = "";
|
||||||
|
$new_content = "";
|
||||||
|
|
||||||
|
if ($old_hash === $new_hash) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($old_hash !== self::EMPTY_HASH) {
|
||||||
|
$old_content = $old->loadFileData();
|
||||||
|
} else {
|
||||||
|
$old_content = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new_hash !== self::EMPTY_HASH) {
|
||||||
|
$new_content = $new->loadFileData();
|
||||||
|
} else {
|
||||||
|
$new_content = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$dmp = new diff_match_patch();
|
||||||
|
$dmp_patches = $dmp->patch_make($old_content, $new_content);
|
||||||
|
return $dmp->patch_toText($dmp_patches);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -216,6 +216,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'type' => 'db',
|
'type' => 'db',
|
||||||
'name' => 'passphrase',
|
'name' => 'passphrase',
|
||||||
),
|
),
|
||||||
|
'db.phragment' => array(
|
||||||
|
'type' => 'db',
|
||||||
|
'name' => 'phragment',
|
||||||
|
),
|
||||||
'0000.legacy.sql' => array(
|
'0000.legacy.sql' => array(
|
||||||
'type' => 'sql',
|
'type' => 'sql',
|
||||||
'name' => $this->getPatchPath('0000.legacy.sql'),
|
'name' => $this->getPatchPath('0000.legacy.sql'),
|
||||||
|
@ -1812,6 +1816,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'type' => 'php',
|
'type' => 'php',
|
||||||
'name' => $this->getPatchPath('20131205.buildstepordermig.php'),
|
'name' => $this->getPatchPath('20131205.buildstepordermig.php'),
|
||||||
),
|
),
|
||||||
|
'20131206.phragment.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('20131206.phragment.sql'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue