mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-26 00:32:41 +01:00
Update the "WorkingCopy" API and create a fallback "Filesystem" working copy
Summary: Ref T11968. - Allow "WorkingCopy" objects to maintain an API object and update callers ("get...()" instead of "new...()"). - Always generate a WorkingCopy object and a RepositoryAPI object. Currently, code has to look like this: ``` $working_copy = ... if ($working_copy) { $repository_api = ... if ($repository_api [instanceof ... ]) { ``` This is clunky. There's also no reason some "arc" commands can't run outside a VCS working directory without special-casing how they interact with the filesystem. Conceptually, model the filesystem as a trivial VCS (which stores exactly one commit, always amends onto it, and discards history). Provide a trivial WorkingCopy and API for it. (This change isn't terribly interesting on its own, but chips away at landing the new Hardpoint infrastructure.) Test Plan: Ran `arc version`, `arc upgrade`. Maniphest Tasks: T11968 Differential Revision: https://secure.phabricator.com/D21070
This commit is contained in:
parent
a1ee2ab931
commit
0b3cd39230
9 changed files with 170 additions and 23 deletions
|
@ -187,7 +187,9 @@ phutil_register_library_map(array(
|
||||||
'ArcanistFileUploader' => 'upload/ArcanistFileUploader.php',
|
'ArcanistFileUploader' => 'upload/ArcanistFileUploader.php',
|
||||||
'ArcanistFilenameLinter' => 'lint/linter/ArcanistFilenameLinter.php',
|
'ArcanistFilenameLinter' => 'lint/linter/ArcanistFilenameLinter.php',
|
||||||
'ArcanistFilenameLinterTestCase' => 'lint/linter/__tests__/ArcanistFilenameLinterTestCase.php',
|
'ArcanistFilenameLinterTestCase' => 'lint/linter/__tests__/ArcanistFilenameLinterTestCase.php',
|
||||||
|
'ArcanistFilesystemAPI' => 'repository/api/ArcanistFilesystemAPI.php',
|
||||||
'ArcanistFilesystemConfigurationSource' => 'config/source/ArcanistFilesystemConfigurationSource.php',
|
'ArcanistFilesystemConfigurationSource' => 'config/source/ArcanistFilesystemConfigurationSource.php',
|
||||||
|
'ArcanistFilesystemWorkingCopy' => 'workingcopy/ArcanistFilesystemWorkingCopy.php',
|
||||||
'ArcanistFlagWorkflow' => 'workflow/ArcanistFlagWorkflow.php',
|
'ArcanistFlagWorkflow' => 'workflow/ArcanistFlagWorkflow.php',
|
||||||
'ArcanistFlake8Linter' => 'lint/linter/ArcanistFlake8Linter.php',
|
'ArcanistFlake8Linter' => 'lint/linter/ArcanistFlake8Linter.php',
|
||||||
'ArcanistFlake8LinterTestCase' => 'lint/linter/__tests__/ArcanistFlake8LinterTestCase.php',
|
'ArcanistFlake8LinterTestCase' => 'lint/linter/__tests__/ArcanistFlake8LinterTestCase.php',
|
||||||
|
@ -1130,7 +1132,9 @@ phutil_register_library_map(array(
|
||||||
'ArcanistFileUploader' => 'Phobject',
|
'ArcanistFileUploader' => 'Phobject',
|
||||||
'ArcanistFilenameLinter' => 'ArcanistLinter',
|
'ArcanistFilenameLinter' => 'ArcanistLinter',
|
||||||
'ArcanistFilenameLinterTestCase' => 'ArcanistLinterTestCase',
|
'ArcanistFilenameLinterTestCase' => 'ArcanistLinterTestCase',
|
||||||
|
'ArcanistFilesystemAPI' => 'ArcanistRepositoryAPI',
|
||||||
'ArcanistFilesystemConfigurationSource' => 'ArcanistDictionaryConfigurationSource',
|
'ArcanistFilesystemConfigurationSource' => 'ArcanistDictionaryConfigurationSource',
|
||||||
|
'ArcanistFilesystemWorkingCopy' => 'ArcanistWorkingCopy',
|
||||||
'ArcanistFlagWorkflow' => 'ArcanistWorkflow',
|
'ArcanistFlagWorkflow' => 'ArcanistWorkflow',
|
||||||
'ArcanistFlake8Linter' => 'ArcanistExternalLinter',
|
'ArcanistFlake8Linter' => 'ArcanistExternalLinter',
|
||||||
'ArcanistFlake8LinterTestCase' => 'ArcanistExternalLinterTestCase',
|
'ArcanistFlake8LinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||||
|
|
100
src/repository/api/ArcanistFilesystemAPI.php
Normal file
100
src/repository/api/ArcanistFilesystemAPI.php
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistFilesystemAPI
|
||||||
|
extends ArcanistRepositoryAPI {
|
||||||
|
|
||||||
|
public function getSourceControlSystemName() {
|
||||||
|
return 'filesystem';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildUncommittedStatus() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildCommitRangeStatus() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllFiles() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlame($path) {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRawDiffText($path) {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOriginalFileData($path) {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCurrentFileData($path) {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLocalCommitInformation() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSourceControlBaseRevision() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCanonicalRevisionName($string) {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBranchName() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSourceControlPath() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isHistoryDefaultImmutable() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsAmend() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWorkingCopyRevision() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateWorkingCopy() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataPath() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadWorkingCopyDifferentialRevisions(
|
||||||
|
ConduitClient $conduit,
|
||||||
|
array $query) {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRemoteURI() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsLocalCommits() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildLocalFuture(array $argv) {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsCommitRanges() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -48,15 +48,10 @@ EOTEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($roots as $lib => $root) {
|
foreach ($roots as $lib => $root) {
|
||||||
$is_git = false;
|
|
||||||
|
|
||||||
$working_copy = ArcanistWorkingCopy::newFromWorkingDirectory($root);
|
$working_copy = ArcanistWorkingCopy::newFromWorkingDirectory($root);
|
||||||
if ($working_copy) {
|
|
||||||
$repository_api = $working_copy->newRepositoryAPI();
|
$repository_api = $working_copy->getRepositoryAPI();
|
||||||
if ($repository_api instanceof ArcanistGitAPI) {
|
$is_git = ($repository_api instanceof ArcanistGitAPI);
|
||||||
$is_git = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$is_git) {
|
if (!$is_git) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
|
|
|
@ -43,15 +43,10 @@ EOTEXT
|
||||||
'Preparing to upgrade "%s"...',
|
'Preparing to upgrade "%s"...',
|
||||||
$library));
|
$library));
|
||||||
|
|
||||||
$is_git = false;
|
|
||||||
|
|
||||||
$working_copy = ArcanistWorkingCopy::newFromWorkingDirectory($root);
|
$working_copy = ArcanistWorkingCopy::newFromWorkingDirectory($root);
|
||||||
if ($working_copy) {
|
|
||||||
$repository_api = $working_copy->newRepositoryAPI();
|
$repository_api = $working_copy->getRepositoryAPI();
|
||||||
if ($repository_api instanceof ArcanistGitAPI) {
|
$is_git = ($repository_api instanceof ArcanistGitAPI);
|
||||||
$is_git = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$is_git) {
|
if (!$is_git) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
|
|
27
src/workingcopy/ArcanistFilesystemWorkingCopy.php
Normal file
27
src/workingcopy/ArcanistFilesystemWorkingCopy.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistFilesystemWorkingCopy
|
||||||
|
extends ArcanistWorkingCopy {
|
||||||
|
|
||||||
|
public function getMetadataDirectory() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newWorkingCopyFromDirectories(
|
||||||
|
$working_directory,
|
||||||
|
$ancestor_directory) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newRepositoryAPI() {
|
||||||
|
return new ArcanistFilesystemAPI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProjectConfigurationFilePath() {
|
||||||
|
// We don't support project-level configuration for "filesytem" working
|
||||||
|
// copies because scattering random ".arcconfig" files around the
|
||||||
|
// filesystem and having them affect program behavior is silly.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ final class ArcanistGitWorkingCopy
|
||||||
return new self();
|
return new self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newRepositoryAPI() {
|
protected function newRepositoryAPI() {
|
||||||
return new ArcanistGitAPI($this->getPath());
|
return new ArcanistGitAPI($this->getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ final class ArcanistMercurialWorkingCopy
|
||||||
return new self();
|
return new self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newRepositoryAPI() {
|
protected function newRepositoryAPI() {
|
||||||
return new ArcanistMercurialAPI($this->getPath());
|
return new ArcanistMercurialAPI($this->getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ final class ArcanistSubversionWorkingCopy
|
||||||
return head($candidates);
|
return head($candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newRepositoryAPI() {
|
protected function newRepositoryAPI() {
|
||||||
return new ArcanistSubversionAPI($this->getPath());
|
return new ArcanistSubversionAPI($this->getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ abstract class ArcanistWorkingCopy
|
||||||
|
|
||||||
private $path;
|
private $path;
|
||||||
private $workingDirectory;
|
private $workingDirectory;
|
||||||
|
private $repositoryAPI;
|
||||||
|
|
||||||
public static function newFromWorkingDirectory($path) {
|
public static function newFromWorkingDirectory($path) {
|
||||||
$working_types = id(new PhutilClassMapQuery())
|
$working_types = id(new PhutilClassMapQuery())
|
||||||
|
@ -25,8 +26,7 @@ abstract class ArcanistWorkingCopy
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$working_copy->path = $ancestor_path;
|
self::configureWorkingCopy($working_copy, $ancestor_path, $path);
|
||||||
$working_copy->workingDirectory = $path;
|
|
||||||
|
|
||||||
$candidates[] = $working_copy;
|
$candidates[] = $working_copy;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,16 @@ abstract class ArcanistWorkingCopy
|
||||||
return $deepest->selectFromNestedWorkingCopies($candidates);
|
return $deepest->selectFromNestedWorkingCopies($candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
// If we haven't found a legitimate working copy that belongs to a
|
||||||
|
// supported version control system, return a "filesystem" working copy.
|
||||||
|
// This allows some commands to work as expected even if run outside
|
||||||
|
// of a real working copy.
|
||||||
|
|
||||||
|
$working_copy = new ArcanistFilesystemWorkingCopy();
|
||||||
|
|
||||||
|
self::configureWorkingCopy($working_copy, $ancestor_path, $path);
|
||||||
|
|
||||||
|
return $working_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract protected function newWorkingCopyFromDirectories(
|
abstract protected function newWorkingCopyFromDirectories(
|
||||||
|
@ -110,6 +119,23 @@ abstract class ArcanistWorkingCopy
|
||||||
return last($candidates);
|
return last($candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract public function newRepositoryAPI();
|
final public function getRepositoryAPI() {
|
||||||
|
if (!$this->repositoryAPI) {
|
||||||
|
$this->repositoryAPI = $this->newRepositoryAPI();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->repositoryAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function newRepositoryAPI();
|
||||||
|
|
||||||
|
private static function configureWorkingCopy(
|
||||||
|
ArcanistWorkingCopy $working_copy,
|
||||||
|
$ancestor_path,
|
||||||
|
$path) {
|
||||||
|
|
||||||
|
$working_copy->path = $ancestor_path;
|
||||||
|
$working_copy->workingDirectory = $path;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue