Differential D8780 Diff 20838 src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php
Show All 23 Lines | |||||
* | * | ||||
* @task pull Pulling Repositories | * @task pull Pulling Repositories | ||||
* @task git Git Implementation | * @task git Git Implementation | ||||
* @task hg Mercurial Implementation | * @task hg Mercurial Implementation | ||||
*/ | */ | ||||
final class PhabricatorRepositoryPullLocalDaemon | final class PhabricatorRepositoryPullLocalDaemon | ||||
extends PhabricatorDaemon { | extends PhabricatorDaemon { | ||||
private $discoveryEngines = array(); | |||||
/* -( Pulling Repositories )----------------------------------------------- */ | /* -( Pulling Repositories )----------------------------------------------- */ | ||||
/** | /** | ||||
* @task pull | * @task pull | ||||
*/ | */ | ||||
public function run() { | public function run() { | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | while (true) { | ||||
continue; | continue; | ||||
} | } | ||||
$callsign = $repository->getCallsign(); | $callsign = $repository->getCallsign(); | ||||
try { | try { | ||||
$this->log("Updating repository '{$callsign}'."); | $this->log("Updating repository '{$callsign}'."); | ||||
id(new PhabricatorRepositoryPullEngine()) | $bin_dir = dirname(phutil_get_library_root('phabricator')).'/bin'; | ||||
->setRepository($repository) | $flags = array(); | ||||
->pullRepository(); | if ($no_discovery) { | ||||
$flags[] = '--no-discovery'; | |||||
if (!$no_discovery) { | } | ||||
// TODO: It would be nice to discover only if we pulled something, | |||||
// but this isn't totally trivial. It's slightly more complicated | list($stdout, $stderr) = execx( | ||||
// with hosted repositories, too. | '%s/repository update %Ls -- %s', | ||||
$bin_dir, | |||||
$lock_name = get_class($this).':'.$callsign; | $flags, | ||||
$lock = PhabricatorGlobalLock::newLock($lock_name); | $callsign); | ||||
$lock->lock(); | |||||
if (strlen($stderr)) { | |||||
try { | $stderr_msg = pht( | ||||
$repository->writeStatusMessage( | 'Unexpected output while updating the %s repository: %s', | ||||
PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE, | $callsign, | ||||
null); | $stderr); | ||||
$this->discoverRepository($repository); | phlog($stderr_msg); | ||||
btrahan: this ends up showing up in the daemon log? | |||||
epriestleyAuthorUnsubmitted Not Done Inline ActionsYeah, phlog() from daemons goes to the console (or, if it doesn't, that's a bug). I'll double-check. epriestley: Yeah, phlog() from daemons goes to the console (or, if it doesn't, that's a bug). I'll double… | |||||
$this->updateRepositoryRefs($repository); | |||||
$this->mirrorRepository($repository); | |||||
$repository->writeStatusMessage( | |||||
PhabricatorRepositoryStatusMessage::TYPE_FETCH, | |||||
PhabricatorRepositoryStatusMessage::CODE_OKAY); | |||||
} catch (Exception $ex) { | |||||
$repository->writeStatusMessage( | |||||
PhabricatorRepositoryStatusMessage::TYPE_FETCH, | |||||
PhabricatorRepositoryStatusMessage::CODE_ERROR, | |||||
array( | |||||
'message' => pht( | |||||
'Error updating working copy: %s', $ex->getMessage()), | |||||
)); | |||||
$lock->unlock(); | |||||
throw $ex; | |||||
} | |||||
$lock->unlock(); | |||||
} | } | ||||
$sleep_for = $repository->getDetail('pull-frequency', $min_sleep); | $sleep_for = $repository->getDetail('pull-frequency', $min_sleep); | ||||
$retry_after[$id] = time() + $sleep_for; | $retry_after[$id] = time() + $sleep_for; | ||||
} catch (PhutilLockException $ex) { | |||||
$retry_after[$id] = time() + $min_sleep; | |||||
$this->log("Failed to acquire lock."); | |||||
} catch (Exception $ex) { | } catch (Exception $ex) { | ||||
$retry_after[$id] = time() + $min_sleep; | $retry_after[$id] = time() + $min_sleep; | ||||
$proxy = new PhutilProxyException( | $proxy = new PhutilProxyException( | ||||
"Error while fetching changes to the '{$callsign}' repository.", | "Error while fetching changes to the '{$callsign}' repository.", | ||||
$ex); | $ex); | ||||
phlog($proxy); | phlog($proxy); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if ($names) { | ||||
"No repository exists with callsign '{$name}'!"); | "No repository exists with callsign '{$name}'!"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return $repos; | return $repos; | ||||
} | } | ||||
public function discoverRepository(PhabricatorRepository $repository) { | |||||
$refs = $this->getDiscoveryEngine($repository) | |||||
->discoverCommits(); | |||||
$this->checkIfRepositoryIsFullyImported($repository); | |||||
return (bool)count($refs); | |||||
} | |||||
private function mirrorRepository(PhabricatorRepository $repository) { | |||||
try { | |||||
id(new PhabricatorRepositoryMirrorEngine()) | |||||
->setRepository($repository) | |||||
->pushToMirrors(); | |||||
} catch (Exception $ex) { | |||||
// TODO: We should report these into the UI properly, but for | |||||
// now just complain. These errors are much less severe than | |||||
// pull errors. | |||||
$proxy = new PhutilProxyException( | |||||
pht( | |||||
'Error while pushing "%s" repository to mirrors.', | |||||
$repository->getCallsign()), | |||||
$ex); | |||||
phlog($proxy); | |||||
} | |||||
} | |||||
private function updateRepositoryRefs(PhabricatorRepository $repository) { | |||||
id(new PhabricatorRepositoryRefEngine()) | |||||
->setRepository($repository) | |||||
->updateRefs(); | |||||
} | |||||
private function getDiscoveryEngine(PhabricatorRepository $repository) { | |||||
$id = $repository->getID(); | |||||
if (empty($this->discoveryEngines[$id])) { | |||||
$engine = id(new PhabricatorRepositoryDiscoveryEngine()) | |||||
->setRepository($repository) | |||||
->setVerbose($this->getVerbose()); | |||||
$this->discoveryEngines[$id] = $engine; | |||||
} | |||||
return $this->discoveryEngines[$id]; | |||||
} | |||||
private function checkIfRepositoryIsFullyImported( | |||||
PhabricatorRepository $repository) { | |||||
// Check if the repository has the "Importing" flag set. We want to clear | |||||
// the flag if we can. | |||||
$importing = $repository->getDetail('importing'); | |||||
if (!$importing) { | |||||
// This repository isn't marked as "Importing", so we're done. | |||||
return; | |||||
} | |||||
// Look for any commit which hasn't imported. | |||||
$unparsed_commit = queryfx_one( | |||||
$repository->establishConnection('r'), | |||||
'SELECT * FROM %T WHERE repositoryID = %d AND (importStatus & %d) != %d | |||||
LIMIT 1', | |||||
id(new PhabricatorRepositoryCommit())->getTableName(), | |||||
$repository->getID(), | |||||
PhabricatorRepositoryCommit::IMPORTED_ALL, | |||||
PhabricatorRepositoryCommit::IMPORTED_ALL); | |||||
if ($unparsed_commit) { | |||||
// We found a commit which still needs to import, so we can't clear the | |||||
// flag. | |||||
return; | |||||
} | |||||
// Clear the "importing" flag. | |||||
$repository->openTransaction(); | |||||
$repository->beginReadLocking(); | |||||
$repository = $repository->reload(); | |||||
$repository->setDetail('importing', false); | |||||
$repository->save(); | |||||
$repository->endReadLocking(); | |||||
$repository->saveTransaction(); | |||||
} | |||||
} | } |
this ends up showing up in the daemon log?