Page MenuHomePhabricator

D13911.id33575.diff
No OneTemporary

D13911.id33575.diff

diff --git a/src/applications/diffusion/controller/DiffusionBrowseController.php b/src/applications/diffusion/controller/DiffusionBrowseController.php
--- a/src/applications/diffusion/controller/DiffusionBrowseController.php
+++ b/src/applications/diffusion/controller/DiffusionBrowseController.php
@@ -111,25 +111,6 @@
->setIcon('fa-home')
->setDisabled(!$behind_head));
- // TODO: Ideally, this should live in Owners and be event-triggered, but
- // there's no reasonable object for it to react to right now.
-
- $owners = 'PhabricatorOwnersApplication';
- if (PhabricatorApplication::isClassInstalled($owners)) {
- $owners_uri = id(new PhutilURI('/owners/view/search/'))
- ->setQueryParams(
- array(
- 'repository' => $drequest->getCallsign(),
- 'path' => '/'.$drequest->getPath(),
- ));
-
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Find Owners'))
- ->setHref((string)$owners_uri)
- ->setIcon('fa-users'));
- }
-
return $view;
}
@@ -137,7 +118,7 @@
DiffusionRequest $drequest,
PhabricatorActionListView $actions) {
- $viewer = $this->getRequest()->getUser();
+ $viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
@@ -180,6 +161,47 @@
}
}
+ $repository = $drequest->getRepository();
+
+ $owners = 'PhabricatorOwnersApplication';
+ if (PhabricatorApplication::isClassInstalled($owners)) {
+ $package_query = id(new PhabricatorOwnersPackageQuery())
+ ->setViewer($viewer)
+ ->withControl(
+ $repository->getPHID(),
+ array(
+ $drequest->getPath(),
+ ));
+
+ $package_query->execute();
+
+ $packages = $package_query->getControllingPackagesForPath(
+ $repository->getPHID(),
+ $drequest->getPath());
+
+ if ($packages) {
+ $ownership = id(new PHUIStatusListView())
+ ->setUser($viewer);
+
+
+
+ foreach ($packages as $package) {
+ $icon = 'fa-list-alt';
+ $color = 'grey';
+
+ $item = id(new PHUIStatusItemView())
+ ->setIcon($icon, $color)
+ ->setTarget($viewer->renderHandle($package->getPHID()));
+
+ $ownership->addItem($item);
+ }
+ } else {
+ $ownership = phutil_tag('em', array(), pht('None'));
+ }
+
+ $view->addProperty(pht('Packages'), $ownership);
+ }
+
return $view;
}
diff --git a/src/applications/owners/controller/PhabricatorOwnersDetailController.php b/src/applications/owners/controller/PhabricatorOwnersDetailController.php
--- a/src/applications/owners/controller/PhabricatorOwnersDetailController.php
+++ b/src/applications/owners/controller/PhabricatorOwnersDetailController.php
@@ -13,12 +13,13 @@
$package = id(new PhabricatorOwnersPackageQuery())
->setViewer($viewer)
->withIDs(array($request->getURIData('id')))
+ ->needPaths(true)
->executeOne();
if (!$package) {
return new Aphront404Response();
}
- $paths = $package->loadPaths();
+ $paths = $package->getPaths();
$repository_phids = array();
foreach ($paths as $path) {
diff --git a/src/applications/owners/controller/PhabricatorOwnersPathsController.php b/src/applications/owners/controller/PhabricatorOwnersPathsController.php
--- a/src/applications/owners/controller/PhabricatorOwnersPathsController.php
+++ b/src/applications/owners/controller/PhabricatorOwnersPathsController.php
@@ -15,6 +15,7 @@
// TODO: Support this capability.
// PhabricatorPolicyCapability::CAN_EDIT,
))
+ ->needPaths(true)
->executeOne();
if (!$package) {
return new Aphront404Response();
@@ -66,7 +67,7 @@
return id(new AphrontRedirectResponse())
->setURI('/owners/package/'.$package->getID().'/');
} else {
- $paths = $package->loadPaths();
+ $paths = $package->getPaths();
$path_refs = mpull($paths, 'getRef');
}
diff --git a/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php b/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php
--- a/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php
+++ b/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php
@@ -43,8 +43,7 @@
case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION:
return $object->getDescription();
case PhabricatorOwnersPackageTransaction::TYPE_PATHS:
- // TODO: needPaths() this on the query
- $paths = $object->loadPaths();
+ $paths = $object->getPaths();
return mpull($paths, 'getRef');
}
}
@@ -152,8 +151,7 @@
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
- // TODO: needPaths this
- $paths = $object->loadPaths();
+ $paths = $object->getPaths();
$diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new);
list($rem, $add) = $diffs;
diff --git a/src/applications/owners/query/PhabricatorOwnersPackageQuery.php b/src/applications/owners/query/PhabricatorOwnersPackageQuery.php
--- a/src/applications/owners/query/PhabricatorOwnersPackageQuery.php
+++ b/src/applications/owners/query/PhabricatorOwnersPackageQuery.php
@@ -8,6 +8,10 @@
private $ownerPHIDs;
private $repositoryPHIDs;
private $namePrefix;
+ private $needPaths;
+
+ private $controlMap = array();
+ private $controlResults;
/**
* Owners are direct owners, and members of owning projects.
@@ -32,19 +36,64 @@
return $this;
}
+ public function withControl($repository_phid, array $paths) {
+ if (empty($this->controlMap[$repository_phid])) {
+ $this->controlMap[$repository_phid] = array();
+ }
+
+ foreach ($paths as $path) {
+ $this->controlMap[$repository_phid][$path] = $path;
+ }
+
+ // We need to load paths to execute control queries.
+ $this->needPaths = true;
+
+ return $this;
+ }
+
public function withNamePrefix($prefix) {
$this->namePrefix = $prefix;
return $this;
}
+ public function needPaths($need_paths) {
+ $this->needPaths = $need_paths;
+ return $this;
+ }
+
public function newResultObject() {
return new PhabricatorOwnersPackage();
}
+ protected function willExecute() {
+ $this->controlResults = array();
+ }
+
protected function loadPage() {
return $this->loadStandardPage(new PhabricatorOwnersPackage());
}
+ protected function didFilterPage(array $packages) {
+ if ($this->needPaths) {
+ $package_ids = mpull($packages, 'getID');
+
+ $paths = id(new PhabricatorOwnersPath())->loadAllWhere(
+ 'packageID IN (%Ld)',
+ $package_ids);
+ $paths = mgroup($paths, 'getPackageID');
+
+ foreach ($packages as $package) {
+ $package->attachPaths(idx($paths, $package->getID(), array()));
+ }
+ }
+
+ if ($this->controlMap) {
+ $this->controlResults += mpull($packages, null, 'getID');
+ }
+
+ return $packages;
+ }
+
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
$joins = parent::buildJoinClauseParts($conn);
@@ -55,7 +104,7 @@
id(new PhabricatorOwnersOwner())->getTableName());
}
- if ($this->repositoryPHIDs !== null) {
+ if ($this->shouldJoinOwnersPathTable()) {
$joins[] = qsprintf(
$conn,
'JOIN %T rpath ON rpath.packageID = p.id',
@@ -115,11 +164,30 @@
phutil_utf8_strtolower($this->namePrefix));
}
+ if ($this->controlMap) {
+ $clauses = array();
+ foreach ($this->controlMap as $repository_phid => $paths) {
+ $fragments = array();
+ foreach ($paths as $path) {
+ foreach (PhabricatorOwnersPackage::splitPath($path) as $fragment) {
+ $fragments[$fragment] = $fragment;
+ }
+ }
+
+ $clauses[] = qsprintf(
+ $conn,
+ '(rpath.repositoryPHID = %s AND rpath.path IN (%Ls))',
+ $repository_phid,
+ $fragments);
+ }
+ $where[] = implode(' OR ', $clauses);
+ }
+
return $where;
}
protected function shouldGroupQueryResultRows() {
- if ($this->repositoryPHIDs) {
+ if ($this->shouldJoinOwnersPathTable()) {
return true;
}
@@ -167,4 +235,83 @@
return 'p';
}
+ private function shouldJoinOwnersPathTable() {
+ if ($this->repositoryPHIDs !== null) {
+ return true;
+ }
+
+ if ($this->controlMap) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+/* -( Path Control )------------------------------------------------------- */
+
+
+ /**
+ * Get the package which controls a path, if one exists.
+ *
+ * @return PhabricatorOwnersPackage|null Package, if one exists.
+ */
+ public function getControllingPackageForPath($repository_phid, $path) {
+ $packages = $this->getControllingPackagesForPath($repository_phid, $path);
+
+ if (!$packages) {
+ return null;
+ }
+
+ return head($packages);
+ }
+
+
+ /**
+ * Get a list of all packages which control a path or its parent directories,
+ * ordered from weakest to strongest.
+ *
+ * The first package has the most specific claim on the path; the last
+ * package has the most general claim.
+ *
+ * @return list<PhabricatorOwnersPackage> List of controlling packages.
+ */
+ public function getControllingPackagesForPath($repository_phid, $path) {
+ if (!isset($this->controlMap[$repository_phid][$path])) {
+ throw new PhutilInvalidStateException('withControl');
+ }
+
+ if ($this->controlResults === null) {
+ throw new PhutilInvalidStateException('execute');
+ }
+
+ $packages = $this->controlResults;
+
+ $matches = array();
+ foreach ($packages as $package_id => $package) {
+ $best_match = null;
+ $include = false;
+
+ foreach ($package->getPaths() as $package_path) {
+ $strength = $package_path->getPathMatchStrength($path);
+ if ($strength > $best_match) {
+ $best_match = $strength;
+ $include = !$package_path->getExcluded();
+ }
+ }
+
+ if ($best_match && $include) {
+ $matches[$package_id] = array(
+ 'strength' => $best_match,
+ 'package' => $package,
+ );
+ }
+ }
+
+ $matches = isort($matches, 'strength');
+ $matches = array_reverse($matches);
+
+ return array_values(ipull($matches, 'package'));
+ }
+
}
diff --git a/src/applications/owners/storage/PhabricatorOwnersPackage.php b/src/applications/owners/storage/PhabricatorOwnersPackage.php
--- a/src/applications/owners/storage/PhabricatorOwnersPackage.php
+++ b/src/applications/owners/storage/PhabricatorOwnersPackage.php
@@ -13,6 +13,8 @@
protected $primaryOwnerPHID;
protected $mailKey;
+ private $paths = self::ATTACHABLE;
+
public static function initializeNewPackage(PhabricatorUser $actor) {
return id(new PhabricatorOwnersPackage())
->setAuditingEnabled(0)
@@ -225,7 +227,7 @@
return $ids;
}
- private static function splitPath($path) {
+ public static function splitPath($path) {
$result = array('/');
$trailing_slash = preg_match('@/$@', $path) ? '/' : '';
$path = trim($path, '/');
@@ -238,6 +240,16 @@
return $result;
}
+ public function attachPaths(array $paths) {
+ assert_instances_of($paths, 'PhabricatorOwnersPath');
+ $this->paths = $paths;
+ return $this;
+ }
+
+ public function getPaths() {
+ return $this->assertAttached($this->paths);
+ }
+
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
diff --git a/src/applications/owners/storage/PhabricatorOwnersPath.php b/src/applications/owners/storage/PhabricatorOwnersPath.php
--- a/src/applications/owners/storage/PhabricatorOwnersPath.php
+++ b/src/applications/owners/storage/PhabricatorOwnersPath.php
@@ -70,4 +70,36 @@
return isset($set[$ref['repositoryPHID']][$ref['path']][$ref['excluded']]);
}
+ /**
+ * Get the number of directory matches between this path specification and
+ * some real path.
+ */
+ public function getPathMatchStrength($path) {
+ $this_path = $this->getPath();
+
+ if ($this_path === '/') {
+ // The root path "/" just matches everything with strength 1.
+ return 1;
+ }
+
+ $self_fragments = PhabricatorOwnersPackage::splitPath($this_path);
+ $path_fragments = PhabricatorOwnersPackage::splitPath($path);
+
+ $self_count = count($self_fragments);
+ $path_count = count($path_fragments);
+ if ($self_count > $path_count) {
+ // If this path is longer (and therefor more specific) than the target
+ // path, we don't match it at all.
+ return 0;
+ }
+
+ for ($ii = 0; $ii < $self_count; $ii++) {
+ if ($self_fragments[$ii] != $path_fragments[$ii]) {
+ return 0;
+ }
+ }
+
+ return $self_count;
+ }
+
}

File Metadata

Mime Type
text/plain
Expires
Sat, May 18, 1:49 PM (4 w, 1 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6286420
Default Alt Text
D13911.id33575.diff (12 KB)

Event Timeline