1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-02 02:40:58 +01:00

Survive pull/discover for hosted repositories in all VCSes

Summary:
Hosted repositories only sometimes survive the pull/discover phases right now, due to issues like:

  - Pull tries to `git clone`, but should `git init`.
  - Mercurial doesn't handle empty repositories with on branches.
  - SVN tries to connect to an invalid remote.
  - None of them set the INIT repo flag correctly, so status doesn't get updated properly in the UI.

Fix all this stuff.

Test Plan:
  - For each of Git, SVN and Mercurial:
    - Created a new repository from the web UI in a deactivated state.
    - Made it hosted.
    - Manually ran pull/discover.
    - Verified we end up with initialized, empty repositories in consistent states.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2230

Differential Revision: https://secure.phabricator.com/D7474
This commit is contained in:
epriestley 2013-11-01 17:36:30 -07:00
parent a0e820ad9a
commit 3607bd487c
3 changed files with 114 additions and 53 deletions

View file

@ -536,20 +536,22 @@ final class PhabricatorRepositoryPullLocalDaemon
private function executeGitDiscover( private function executeGitDiscover(
PhabricatorRepository $repository) { PhabricatorRepository $repository) {
list($remotes) = $repository->execxLocalCommand( if (!$repository->isHosted()) {
'remote show -n origin'); list($remotes) = $repository->execxLocalCommand(
'remote show -n origin');
$matches = null; $matches = null;
if (!preg_match('/^\s*Fetch URL:\s*(.*?)\s*$/m', $remotes, $matches)) { if (!preg_match('/^\s*Fetch URL:\s*(.*?)\s*$/m', $remotes, $matches)) {
throw new Exception( throw new Exception(
"Expected 'Fetch URL' in 'git remote show -n origin'."); "Expected 'Fetch URL' in 'git remote show -n origin'.");
}
self::executeGitVerifySameOrigin(
$matches[1],
$repository->getRemoteURI(),
$repository->getLocalPath());
} }
self::executeGitVerifySameOrigin(
$matches[1],
$repository->getRemoteURI(),
$repository->getLocalPath());
$refs = id(new DiffusionLowLevelGitRefQuery()) $refs = id(new DiffusionLowLevelGitRefQuery())
->setRepository($repository) ->setRepository($repository)
->withIsOriginBranch(true) ->withIsOriginBranch(true)
@ -744,6 +746,11 @@ final class PhabricatorRepositoryPullLocalDaemon
// NOTE: "--debug" gives us 40-character hashes. // NOTE: "--debug" gives us 40-character hashes.
list($stdout) = $repository->execxLocalCommand('--debug branches'); list($stdout) = $repository->execxLocalCommand('--debug branches');
if (!trim($stdout)) {
// No branches; likely a newly initialized repository.
return false;
}
$branches = ArcanistMercurialParser::parseMercurialBranches($stdout); $branches = ArcanistMercurialParser::parseMercurialBranches($stdout);
$got_something = false; $got_something = false;
foreach ($branches as $name => $branch) { foreach ($branches as $name => $branch) {

View file

@ -5,9 +5,13 @@
* @{class:PhabricatorRepository} objects. Used by * @{class:PhabricatorRepository} objects. Used by
* @{class:PhabricatorRepositoryPullLocalDaemon}. * @{class:PhabricatorRepositoryPullLocalDaemon}.
* *
* This class also covers initial working copy setup through `git clone`,
* `git init`, `hg clone`, `hg init`, or `svnadmin create`.
*
* @task pull Pulling Working Copies * @task pull Pulling Working Copies
* @task git Pulling Git Working Copies * @task git Pulling Git Working Copies
* @task hg Pulling Mercurial Working Copies * @task hg Pulling Mercurial Working Copies
* @task svn Pulling Subversion Working Copies
* @task internal Internals * @task internal Internals
*/ */
final class PhabricatorRepositoryPullEngine final class PhabricatorRepositoryPullEngine
@ -22,28 +26,24 @@ final class PhabricatorRepositoryPullEngine
$is_hg = false; $is_hg = false;
$is_git = false; $is_git = false;
$is_svn = true;
$vcs = $repository->getVersionControlSystem(); $vcs = $repository->getVersionControlSystem();
$callsign = $repository->getCallsign(); $callsign = $repository->getCallsign();
if ($repository->isHosted()) {
$this->skipPull(
pht(
'Repository "%s" is hosted, so Phabricator does not pull updates '.
'for it.',
$callsign));
return;
}
switch ($vcs) { switch ($vcs) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
// We never pull a local copy of Subversion repositories. // We never pull a local copy of non-hosted Subversion repositories.
$this->skipPull( if (!$repository->isHosted()) {
pht( $this->skipPull(
"Repository '%s' is a Subversion repository, which does not ". pht(
"require a local working copy to be pulled.", "Repository '%s' is a non-hosted Subversion repository, which ".
$callsign)); "does not require a local working copy to be pulled.",
return; $callsign));
return;
}
$is_svn = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$is_git = true; $is_git = true;
break; break;
@ -76,18 +76,28 @@ final class PhabricatorRepositoryPullEngine
$callsign)); $callsign));
if ($is_git) { if ($is_git) {
$this->executeGitCreate(); $this->executeGitCreate();
} else { } else if ($is_hg) {
$this->executeMercurialCreate(); $this->executeMercurialCreate();
} else {
$this->executeSubversionCreate();
} }
} else { } else {
$this->logPull( if ($repository->isHosted()) {
pht( $this->logPull(
"Updating the working copy for repository '%s'.", pht(
$callsign)); "Repository '%s' is hosted, so Phabricator does not pull ".
if ($is_git) { "updates for it.",
$this->executeGitUpdate(); $callsign));
} else { } else {
$this->executeMercurialUpdate(); $this->logPull(
pht(
"Updating the working copy for repository '%s'.",
$callsign));
if ($is_git) {
$this->executeGitUpdate();
} else {
$this->executeMercurialUpdate();
}
} }
} }
} catch (Exception $ex) { } catch (Exception $ex) {
@ -102,8 +112,8 @@ final class PhabricatorRepositoryPullEngine
} }
private function skipPull($message) { private function skipPull($message) {
$this->updateRepositoryInitStatus(null);
$this->log('%s', $message); $this->log('%s', $message);
$this->donePull();
} }
private function abortPull($message, Exception $ex = null) { private function abortPull($message, Exception $ex = null) {
@ -146,10 +156,18 @@ final class PhabricatorRepositoryPullEngine
private function executeGitCreate() { private function executeGitCreate() {
$repository = $this->getRepository(); $repository = $this->getRepository();
$repository->execxRemoteCommand( $path = rtrim($repository->getLocalPath(), '/');
'clone --bare %s %s',
$repository->getRemoteURI(), if ($repository->isHosted()) {
rtrim($repository->getLocalPath(), '/')); $repository->execxRemoteCommand(
'init --bare -- %s',
$path);
} else {
$repository->execxRemoteCommand(
'clone --bare -- %s %s',
$repository->getRemoteURI(),
$path);
}
} }
@ -270,10 +288,18 @@ final class PhabricatorRepositoryPullEngine
private function executeMercurialCreate() { private function executeMercurialCreate() {
$repository = $this->getRepository(); $repository = $this->getRepository();
$repository->execxRemoteCommand( $path = rtrim($repository->getLocalPath(), '/');
'clone %s %s',
$repository->getRemoteURI(), if ($repository->isHosted()) {
rtrim($repository->getLocalPath(), '/')); $repository->execxRemoteCommand(
'init -- %s',
$path);
} else {
$repository->execxRemoteCommand(
'clone -- %s %s',
$repository->getRemoteURI(),
$path);
}
} }
@ -318,6 +344,20 @@ final class PhabricatorRepositoryPullEngine
} }
/* -( Pulling Subversion Working Copies )---------------------------------- */
/**
* @task svn
*/
private function executeSubversionCreate() {
$repository = $this->getRepository();
$path = rtrim($repository->getLocalPath(), '/');
execx('svnadmin create -- %s', $path);
}
/* -( Internals )---------------------------------------------------------- */ /* -( Internals )---------------------------------------------------------- */

View file

@ -161,8 +161,16 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
throw new Exception("Not a subversion repository!"); throw new Exception("Not a subversion repository!");
} }
$uri = $this->getDetail('remote-uri'); if ($this->isHosted()) {
$uri = 'file://'.$this->getLocalPath();
} else {
$uri = $this->getDetail('remote-uri');
}
$subpath = $this->getDetail('svn-subpath'); $subpath = $this->getDetail('svn-subpath');
if ($subpath) {
$subpath = '/'.ltrim($subpath, '/');
}
return $uri.$subpath; return $uri.$subpath;
} }
@ -609,6 +617,10 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
* @task uri * @task uri
*/ */
private function shouldUseSSH() { private function shouldUseSSH() {
if ($this->isHosted()) {
return false;
}
$protocol = $this->getRemoteProtocol(); $protocol = $this->getRemoteProtocol();
if ($this->isSSHProtocol($protocol)) { if ($this->isSSHProtocol($protocol)) {
return (bool)$this->getSSHKeyfile(); return (bool)$this->getSSHKeyfile();
@ -626,6 +638,10 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
* @task uri * @task uri
*/ */
private function shouldUseHTTP() { private function shouldUseHTTP() {
if ($this->isHosted()) {
return false;
}
$protocol = $this->getRemoteProtocol(); $protocol = $this->getRemoteProtocol();
if ($protocol == 'http' || $protocol == 'https') { if ($protocol == 'http' || $protocol == 'https') {
return (bool)$this->getDetail('http-login'); return (bool)$this->getDetail('http-login');
@ -643,6 +659,10 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
* @task uri * @task uri
*/ */
private function shouldUseSVNProtocol() { private function shouldUseSVNProtocol() {
if ($this->isHosted()) {
return false;
}
$protocol = $this->getRemoteProtocol(); $protocol = $this->getRemoteProtocol();
if ($protocol == 'svn') { if ($protocol == 'svn') {
return (bool)$this->getDetail('http-login'); return (bool)$this->getDetail('http-login');
@ -788,14 +808,8 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
* Raise more useful errors when there are basic filesystem problems. * Raise more useful errors when there are basic filesystem problems.
*/ */
private function assertLocalExists() { private function assertLocalExists() {
switch ($this->getVersionControlSystem()) { if (!$this->usesLocalWorkingCopy()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: return;
if (!$this->isHosted()) {
// For non-hosted SVN repositories, we don't expect a local directory
// to exist.
return;
}
break;
} }
$local = $this->getLocalPath(); $local = $this->getLocalPath();