Differential D20422 Diff 48775 src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
Show First 20 Lines • Show All 333 Lines • ▼ Show 20 Lines | if ($err && $repository->canDestroyWorkingCopy()) { | ||||
$path, | $path, | ||||
$message)); | $message)); | ||||
Filesystem::remove($path); | Filesystem::remove($path); | ||||
$this->executeGitCreate(); | $this->executeGitCreate(); | ||||
} else if ($err) { | } else if ($err) { | ||||
throw new Exception($message); | throw new Exception($message); | ||||
} | } | ||||
$remote_refs = $this->loadGitRemoteRefs($repository); | // Load the refs we're planning to fetch from the remote repository. | ||||
$local_refs = $this->loadGitLocalRefs($repository); | $remote_refs = $this->loadGitRemoteRefs( | ||||
$repository, | |||||
$repository->getRemoteURIEnvelope()); | |||||
// Load the refs we're planning to fetch from the local repository, by | |||||
// using the local working copy path as the "remote" repository URI. | |||||
$local_refs = $this->loadGitRemoteRefs( | |||||
$repository, | |||||
new PhutilOpaqueEnvelope($path)); | |||||
if ($remote_refs === $local_refs) { | if ($remote_refs === $local_refs) { | ||||
$this->log( | $this->log( | ||||
pht( | pht( | ||||
'Skipping fetch because local and remote refs are already '. | 'Skipping fetch because local and remote refs are already '. | ||||
'identical.')); | 'identical.')); | ||||
return false; | return false; | ||||
} | } | ||||
$this->logRefDifferences($remote_refs, $local_refs); | $this->logRefDifferences($remote_refs, $local_refs); | ||||
$fetch_rules = $this->getGitFetchRules($repository); | |||||
$future = $repository->getRemoteCommandFuture( | $future = $repository->getRemoteCommandFuture( | ||||
'fetch %P %s --prune', | 'fetch --prune -- %P %Ls', | ||||
$repository->getRemoteURIEnvelope(), | $repository->getRemoteURIEnvelope(), | ||||
'+refs/*:refs/*'); | $fetch_rules); | ||||
$future | $future | ||||
->setCWD($path) | ->setCWD($path) | ||||
->resolvex(); | ->resolvex(); | ||||
} | } | ||||
private function getGitRefRules(PhabricatorRepository $repository) { | |||||
$ref_rules = $repository->getFetchRules($repository); | |||||
if (!$ref_rules) { | |||||
$ref_rules = array( | |||||
'refs/*', | |||||
); | |||||
} | |||||
return $ref_rules; | |||||
} | |||||
private function getGitFetchRules(PhabricatorRepository $repository) { | |||||
$ref_rules = $this->getGitRefRules($repository); | |||||
// Rewrite each ref rule "X" into "+X:X". | |||||
// The "X" means "fetch ref X". | |||||
// The "...:X" means "...and copy it into local ref X". | |||||
// The "+..." means "...and overwrite the local ref if it already exists". | |||||
$fetch_rules = array(); | |||||
foreach ($ref_rules as $key => $ref_rule) { | |||||
$fetch_rules[] = sprintf( | |||||
'+%s:%s', | |||||
$ref_rule, | |||||
$ref_rule); | |||||
} | |||||
return $fetch_rules; | |||||
} | |||||
/** | /** | ||||
* @task git | * @task git | ||||
*/ | */ | ||||
private function installGitHook() { | private function installGitHook() { | ||||
$repository = $this->getRepository(); | $repository = $this->getRepository(); | ||||
$root = $repository->getLocalPath(); | $root = $repository->getLocalPath(); | ||||
if ($repository->isWorkingCopyBare()) { | if ($repository->isWorkingCopyBare()) { | ||||
$path = '/hooks/pre-receive'; | $path = '/hooks/pre-receive'; | ||||
} else { | } else { | ||||
$path = '/.git/hooks/pre-receive'; | $path = '/.git/hooks/pre-receive'; | ||||
} | } | ||||
$this->installHook($root.$path); | $this->installHook($root.$path); | ||||
} | } | ||||
private function loadGitRemoteRefs(PhabricatorRepository $repository) { | private function loadGitRemoteRefs( | ||||
$remote_envelope = $repository->getRemoteURIEnvelope(); | PhabricatorRepository $repository, | ||||
PhutilOpaqueEnvelope $remote_envelope) { | |||||
$ref_rules = $this->getGitRefRules($repository); | |||||
// NOTE: "git ls-remote" does not support "--" until circa January 2016. | // NOTE: "git ls-remote" does not support "--" until circa January 2016. | ||||
// See T12416. None of the flags to "ls-remote" appear dangerous, and | // See T12416. None of the flags to "ls-remote" appear dangerous, but | ||||
// other checks make it difficult to configure a suspicious remote URI. | // refuse to list any refs beginning with "-" just in case. | ||||
foreach ($ref_rules as $ref_rule) { | |||||
if (preg_match('/^-/', $ref_rule)) { | |||||
throw new Exception( | |||||
pht( | |||||
'Refusing to list potentially dangerous ref ("%s") beginning '. | |||||
'with "-".', | |||||
$ref_rule)); | |||||
} | |||||
} | |||||
list($stdout) = $repository->execxRemoteCommand( | list($stdout) = $repository->execxRemoteCommand( | ||||
'ls-remote %P', | 'ls-remote %P %Ls', | ||||
$remote_envelope); | $remote_envelope, | ||||
$ref_rules); | |||||
// Empty repositories don't have any refs. | // Empty repositories don't have any refs. | ||||
if (!strlen(rtrim($stdout))) { | if (!strlen(rtrim($stdout))) { | ||||
return array(); | return array(); | ||||
} | } | ||||
$map = array(); | $map = array(); | ||||
$lines = phutil_split_lines($stdout, false); | $lines = phutil_split_lines($stdout, false); | ||||
▲ Show 20 Lines • Show All 262 Lines • Show Last 20 Lines |