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 @@ -353,6 +353,9 @@ $packages = $this->controlResults; $weak_dominion = PhabricatorOwnersPackage::DOMINION_WEAK; + $path_fragments = PhabricatorOwnersPackage::splitPath($path); + $fragment_count = count($path_fragments); + $matches = array(); foreach ($packages as $package_id => $package) { $best_match = null; @@ -365,13 +368,11 @@ continue; } - foreach ($package->getPaths() as $package_path) { - if ($package_path->getRepositoryPHID() != $repository_phid) { - // If this path is for some other repository, skip it. - continue; - } - - $strength = $package_path->getPathMatchStrength($path); + $repository_paths = $package->getPathsForRepository($repository_phid); + foreach ($repository_paths as $package_path) { + $strength = $package_path->getPathMatchStrength( + $path_fragments, + $fragment_count); if ($strength > $best_match) { $best_match = $strength; $include = !$package_path->getExcluded(); 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 @@ -26,6 +26,7 @@ private $paths = self::ATTACHABLE; private $owners = self::ATTACHABLE; private $customFields = self::ATTACHABLE; + private $pathRepositoryMap = array(); const STATUS_ACTIVE = 'active'; const STATUS_ARCHIVED = 'archived'; @@ -369,6 +370,10 @@ public function attachPaths(array $paths) { assert_instances_of($paths, 'PhabricatorOwnersPath'); $this->paths = $paths; + + // Drop this cache if we're attaching new paths. + $this->pathRepositoryMap = array(); + return $this; } @@ -376,6 +381,23 @@ return $this->assertAttached($this->paths); } + public function getPathsForRepository($repository_phid) { + if (isset($this->pathRepositoryMap[$repository_phid])) { + return $this->pathRepositoryMap[$repository_phid]; + } + + $map = array(); + foreach ($this->getPaths() as $path) { + if ($path->getRepositoryPHID() == $repository_phid) { + $map[] = $path; + } + } + + $this->pathRepositoryMap[$repository_phid] = $map; + + return $this->pathRepositoryMap[$repository_phid]; + } + public function attachOwners(array $owners) { assert_instances_of($owners, 'PhabricatorOwnersOwner'); $this->owners = $owners; 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 @@ -7,6 +7,9 @@ protected $path; protected $excluded; + private $fragments; + private $fragmentCount; + protected function getConfiguration() { return array( self::CONFIG_TIMESTAMPS => false, @@ -74,19 +77,21 @@ * Get the number of directory matches between this path specification and * some real path. */ - public function getPathMatchStrength($path) { - $this_path = $this->getPath(); + public function getPathMatchStrength($path_fragments, $path_count) { + $this_path = $this->path; 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); + if ($this->fragments === null) { + $this->fragments = PhabricatorOwnersPackage::splitPath($this_path); + $this->fragmentCount = count($this->fragments); + } - $self_count = count($self_fragments); - $path_count = count($path_fragments); + $self_fragments = $this->fragments; + $self_count = $this->fragmentCount; if ($self_count > $path_count) { // If this path is longer (and therefore more specific) than the target // path, we don't match it at all.