1
0
Fork 0
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:
epriestley 2020-04-08 07:18:46 -07:00
parent a1ee2ab931
commit 0b3cd39230
9 changed files with 170 additions and 23 deletions

View file

@ -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',

View 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();
}
}

View file

@ -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(

View file

@ -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(

View 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;
}
}

View file

@ -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());
} }

View file

@ -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());
} }

View file

@ -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());
} }

View file

@ -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;
}
} }