mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-12-01 19:22:41 +01:00
[Wilds] Refine the working copy selection algorithm for Subversion vs Git/Mercurial
Summary: Ref T13098. I didn't fully capture all the nuances of the old algorithm, and the behavior we want is slightly more complicated. This adjust things to try to express the more complicated behavior in a relatively clear (?) way. When a bunch of working copies are nested inside one another, first pick the deepest one, then ask it to pick the best option among all working copies of the same type. For Git and Mercurial repositories, just pick the deepest one. For Subversion repositories, pick the directory with `.arcconfig` if one exists, or the shallowest directory otherwise (this could be more sophisticated, some day). The general idea here is that if `/a` is a Git repository and `/a/b/c` is a Git repository and you run inside `/a/b/c`, that should be the working copy. But we have to use a different rule for Subversion because //every directory// had a `.svn` directory in it until SVN 1.7. Test Plan: Locally, with `core/lib/arcanist/`, got `arc` to anchor to `arcanist/` instead of `core/` with the new ruleset. (This will eventually get more extensive Subversion testing.) Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13098 Differential Revision: https://secure.phabricator.com/D19707
This commit is contained in:
parent
df2c1ba912
commit
4c4fd6fd23
2 changed files with 50 additions and 9 deletions
|
@ -46,6 +46,29 @@ final class ArcanistSubversionWorkingCopy
|
||||||
return new self();
|
return new self();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function selectFromNestedWorkingCopies(array $candidates) {
|
||||||
|
// To select the best working copy in Subversion, we first walk up the
|
||||||
|
// tree looking for a working copy with an ".arcconfig" file. If we find
|
||||||
|
// one, this anchors us.
|
||||||
|
|
||||||
|
foreach (array_reverse($candidates) as $candidate) {
|
||||||
|
$arcconfig = $candidate->getPath('.arcconfig');
|
||||||
|
if (Filesystem::pathExists($arcconfig)) {
|
||||||
|
return $candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find one, we select the outermost working copy. This is
|
||||||
|
// because older versions of Subversion (prior to 1.7) put a ".svn" file
|
||||||
|
// in every directory, and all versions of Subversion allow you to check
|
||||||
|
// out any subdirectory of the project as a working copy.
|
||||||
|
|
||||||
|
// We could possibly refine this by testing if the working copy was made
|
||||||
|
// with a recent version of Subversion and picking the deepest working copy
|
||||||
|
// if it was, similar to Git and Mercurial.
|
||||||
|
|
||||||
|
return head($candidates);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,16 +11,10 @@ abstract class ArcanistWorkingCopy
|
||||||
->setAncestorClass(__CLASS__)
|
->setAncestorClass(__CLASS__)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
// Find the outermost directory which is under version control. We go from
|
|
||||||
// the top because:
|
|
||||||
//
|
|
||||||
// - This gives us a more reasonable behavior if you embed one repository
|
|
||||||
// inside another repository.
|
|
||||||
// - This handles old Subversion working copies correctly. Before
|
|
||||||
// SVN 1.7, Subversion put a ".svn/" directory in every subdirectory.
|
|
||||||
|
|
||||||
$paths = Filesystem::walkToRoot($path);
|
$paths = Filesystem::walkToRoot($path);
|
||||||
$paths = array_reverse($paths);
|
$paths = array_reverse($paths);
|
||||||
|
|
||||||
|
$candidates = array();
|
||||||
foreach ($paths as $path_key => $ancestor_path) {
|
foreach ($paths as $path_key => $ancestor_path) {
|
||||||
foreach ($working_types as $working_type) {
|
foreach ($working_types as $working_type) {
|
||||||
|
|
||||||
|
@ -34,10 +28,28 @@ abstract class ArcanistWorkingCopy
|
||||||
$working_copy->path = $ancestor_path;
|
$working_copy->path = $ancestor_path;
|
||||||
$working_copy->workingDirectory = $path;
|
$working_copy->workingDirectory = $path;
|
||||||
|
|
||||||
return $working_copy;
|
$candidates[] = $working_copy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we've found multiple candidate working copies, we need to pick one.
|
||||||
|
// We let the innermost working copy pick the best candidate from among
|
||||||
|
// candidates of the same type. The rules for Git and Mercurial differ
|
||||||
|
// slightly from the rules for Subversion.
|
||||||
|
|
||||||
|
if ($candidates) {
|
||||||
|
$deepest = last($candidates);
|
||||||
|
|
||||||
|
foreach ($candidates as $key => $candidate) {
|
||||||
|
if (get_class($candidate) != get_class($deepest)) {
|
||||||
|
unset($candidates[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$candidates = array_values($candidates);
|
||||||
|
|
||||||
|
return $deepest->selectFromNestedWorkingCopies($candidates);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,4 +104,10 @@ abstract class ArcanistWorkingCopy
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function selectFromNestedWorkingCopies(array $candidates) {
|
||||||
|
// Normally, the best working copy in a stack is the deepest working copy.
|
||||||
|
// Subversion uses slightly different rules.
|
||||||
|
return last($candidates);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue