Changeset View
Changeset View
Standalone View
Standalone View
src/workingcopy/ArcanistWorkingCopy.php
| <?php | <?php | ||||
| abstract class ArcanistWorkingCopy | abstract class ArcanistWorkingCopy | ||||
| extends Phobject { | extends Phobject { | ||||
| private $path; | private $path; | ||||
| private $workingDirectory; | private $workingDirectory; | ||||
| public static function newFromWorkingDirectory($path) { | public static function newFromWorkingDirectory($path) { | ||||
| $working_types = id(new PhutilClassMapQuery()) | $working_types = id(new PhutilClassMapQuery()) | ||||
| ->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) { | ||||
| $working_copy = $working_type->newWorkingCopyFromDirectories( | $working_copy = $working_type->newWorkingCopyFromDirectories( | ||||
| $path, | $path, | ||||
| $ancestor_path); | $ancestor_path); | ||||
| if (!$working_copy) { | if (!$working_copy) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| $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; | ||||
| } | } | ||||
| abstract protected function newWorkingCopyFromDirectories( | abstract protected function newWorkingCopyFromDirectories( | ||||
| $working_directory, | $working_directory, | ||||
| $ancestor_directory); | $ancestor_directory); | ||||
| final public function getPath($to_file = null) { | final public function getPath($to_file = null) { | ||||
| Show All 38 Lines | final public function getMetadataPath($to_file = null) { | ||||
| return Filesystem::concatenatePaths( | return Filesystem::concatenatePaths( | ||||
| array( | array( | ||||
| $this->getMetadataDirectory(), | $this->getMetadataDirectory(), | ||||
| $to_file, | $to_file, | ||||
| )); | )); | ||||
| } | } | ||||
| 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); | |||||
| } | |||||
| } | } | ||||