1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-09 16:32:39 +01:00

Allow phabricator to manage repositories

Summary:
This adds a configuration option for repositories to be marked as managed
by phabricator, which is then used by the pullLocal daemon to try to recover
from some errors it runs into.

Test Plan: Set a bogus uri for a repo, saw that the pullLocal daemon fixed it.

Reviewers: epriestley, vrana

Reviewed By: epriestley

CC: aran, Korvin

Differential Revision: https://secure.phabricator.com/D3680
This commit is contained in:
Nick Harper 2012-12-12 14:43:09 -08:00
parent 8dd77786c0
commit 0ba7d34f97
3 changed files with 73 additions and 18 deletions

View file

@ -1068,6 +1068,19 @@ return array(
// revision is even older than it is marked as old. // revision is even older than it is marked as old.
'differential.days-stale' => 3, 'differential.days-stale' => 3,
// -- Repositories ---------------------------------------------------------- //
// The default location in which to store local copies of repositories.
// Anything stored in this directory will be assumed to be under the
// control of phabricator, which means that Phabricator will try to do some
// maintenance on working copies if there are problems (such as a change
// to the remote origin url). This maintenance may include completely
// removing (and recloning) anything in this directory.
//
// When set to null, this option is ignored (i.e. Phabricator will not fully
// control any working copies).
'repository.default-local-path' => null,
// -- Maniphest ------------------------------------------------------------- // // -- Maniphest ------------------------------------------------------------- //
'maniphest.enabled' => true, 'maniphest.enabled' => true,

View file

@ -509,6 +509,12 @@ final class PhabricatorRepositoryEditController
$inset->setTitle('Repository Information'); $inset->setTitle('Repository Information');
if ($has_local) { if ($has_local) {
$default_local_path = '';
$default =
PhabricatorEnv::getEnvConfig('repository.default-local-path');
if (!$repository->getDetail('remote-uri') && $default) {
$default_local_path = $default.strtolower($repository->getCallsign());
}
$inset->appendChild( $inset->appendChild(
'<p class="aphront-form-instructions">Select a path on local disk '. '<p class="aphront-form-instructions">Select a path on local disk '.
'which the daemons should <tt>'.$clone_command.'</tt> the repository '. 'which the daemons should <tt>'.$clone_command.'</tt> the repository '.
@ -519,7 +525,7 @@ final class PhabricatorRepositoryEditController
id(new AphrontFormTextControl()) id(new AphrontFormTextControl())
->setName('path') ->setName('path')
->setLabel('Local Path') ->setLabel('Local Path')
->setValue($repository->getDetail('local-path')) ->setValue($repository->getDetail('local-path', $default_local_path))
->setError($e_path)); ->setError($e_path));
} else if ($is_svn) { } else if ($is_svn) {
$inset->appendChild( $inset->appendChild(

View file

@ -468,6 +468,12 @@ final class PhabricatorRepositoryPullLocalDaemon
/* -( Git Implementation )------------------------------------------------- */ /* -( Git Implementation )------------------------------------------------- */
private function canWrite($path) {
$default_path =
PhabricatorEnv::getEnvConfig('repository.default-local-path');
return Filesystem::isDescendant($path, $default_path);
}
/** /**
* @task git * @task git
*/ */
@ -495,6 +501,7 @@ final class PhabricatorRepositoryPullLocalDaemon
list($err, $stdout) = $repository->execLocalCommand( list($err, $stdout) = $repository->execLocalCommand(
'rev-parse --show-toplevel'); 'rev-parse --show-toplevel');
$msg = '';
if ($err) { if ($err) {
@ -505,45 +512,74 @@ final class PhabricatorRepositoryPullLocalDaemon
if (is_dir($path)) { if (is_dir($path)) {
$files = Filesystem::listDirectory($path, $include_hidden = true); $files = Filesystem::listDirectory($path, $include_hidden = true);
if (!$files) { if (!$files) {
throw new Exception( $msg =
"Expected to find a git repository at '{$path}', but there ". "Expected to find a git repository at '{$path}', but there ".
"is an empty directory there. Remove the directory: the daemon ". "is an empty directory there. Remove the directory: the daemon ".
"will run 'git clone' for you."); "will run 'git clone' for you.";
} }
} } else {
$msg =
throw new Exception(
"Expected to find a git repository at '{$path}', but there is ". "Expected to find a git repository at '{$path}', but there is ".
"a non-repository directory (with other stuff in it) there. Move or ". "a non-repository directory (with other stuff in it) there. Move or ".
"remove this directory (or reconfigure the repository to use a ". "remove this directory (or reconfigure the repository to use a ".
"different directory), and then either clone a repository yourself ". "different directory), and then either clone a repository yourself ".
"or let the daemon do it."); "or let the daemon do it.";
}
} else { } else {
$repo_path = rtrim($stdout, "\n"); $repo_path = rtrim($stdout, "\n");
if (empty($repo_path)) { if (empty($repo_path)) {
throw new Exception( $err = true;
$msg =
"Expected to find a git repository at '{$path}', but ". "Expected to find a git repository at '{$path}', but ".
"there was no result from `git rev-parse --show-toplevel`. ". "there was no result from `git rev-parse --show-toplevel`. ".
"Something is misconfigured or broken. The git repository ". "Something is misconfigured or broken. The git repository ".
"may be inside a '.git/' directory."); "may be inside a '.git/' directory.";
} } else if (!Filesystem::pathsAreEquivalent($repo_path, $path)) {
$err = true;
if (!Filesystem::pathsAreEquivalent($repo_path, $path)) { $msg =
throw new Exception(
"Expected to find repo at '{$path}', but the actual ". "Expected to find repo at '{$path}', but the actual ".
"git repository root for this directory is '{$repo_path}'. ". "git repository root for this directory is '{$repo_path}'. ".
"Something is misconfigured. The repository's 'Local Path' should ". "Something is misconfigured. The repository's 'Local Path' should ".
"be set to some place where the daemon can check out a working ". "be set to some place where the daemon can check out a working ".
"copy, and should not be inside another git repository."); "copy, and should not be inside another git repository.";
} }
} }
if ($err && $this->canWrite($path)) {
phlog("{$path} failed sanity check; recloning. ({$msg})");
Filesystem::remove($path);
$this->executeGitCreate($repository, $path);
} else if ($err) {
throw new Exception($msg);
}
// This is a local command, but needs credentials. $retry = false;
$future = $repository->getRemoteCommandFuture('fetch --all --prune'); do {
$future->setCWD($path); // This is a local command, but needs credentials.
$future->resolvex(); $future = $repository->getRemoteCommandFuture('fetch --all --prune');
$future->setCWD($path);
list($err, $stdout, $stderr) = $future->resolve();
if ($err && !$retry && $this->canWrite($path)) {
$retry = true;
// Fix remote origin url if it doesn't match our configuration
$origin_url =
$repository->execLocalCommand('config --get remote.origin.url');
$remote_uri = $repository->getDetail('remote-uri');
if ($origin_url != $remote_uri) {
$repository->execLocalCommand('remote set-url origin %s',
$remote_uri);
}
} else if ($err) {
throw new Exception(
"git fetch failed with error #{$err}:\n".
"stdout:{$stdout}\n\n".
"stderr:{$stderr}\n");
} else {
$retry = false;
}
} while ($retry);
} }