Differential D15420 Diff 37180 src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php
<?php | <?php | ||||
final class DrydockWorkingCopyBlueprintImplementation | final class DrydockWorkingCopyBlueprintImplementation | ||||
extends DrydockBlueprintImplementation { | extends DrydockBlueprintImplementation { | ||||
const PHASE_SQUASHMERGE = 'squashmerge'; | const PHASE_SQUASHMERGE = 'squashmerge'; | ||||
const PHASE_REMOTEFETCH = 'blueprint.workingcopy.fetch.remote'; | |||||
const PHASE_MERGEFETCH = 'blueprint.workingcopy.fetch.staging'; | |||||
public function isEnabled() { | public function isEnabled() { | ||||
return true; | return true; | ||||
} | } | ||||
public function getBlueprintName() { | public function getBlueprintName() { | ||||
return pht('Working Copy'); | return pht('Working Copy'); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 220 Lines • ▼ Show 20 Lines | public function activateLease( | ||||
$command_type = DrydockCommandInterface::INTERFACE_TYPE; | $command_type = DrydockCommandInterface::INTERFACE_TYPE; | ||||
$interface = $host_lease->getInterface($command_type); | $interface = $host_lease->getInterface($command_type); | ||||
$map = $lease->getAttribute('repositories.map'); | $map = $lease->getAttribute('repositories.map'); | ||||
$root = $resource->getAttribute('workingcopy.root'); | $root = $resource->getAttribute('workingcopy.root'); | ||||
$default = null; | $default = null; | ||||
foreach ($map as $directory => $spec) { | foreach ($map as $directory => $spec) { | ||||
$interface->pushWorkingDirectory("{$root}/repo/{$directory}/"); | |||||
$cmd = array(); | $cmd = array(); | ||||
$arg = array(); | $arg = array(); | ||||
$interface->pushWorkingDirectory("{$root}/repo/{$directory}/"); | |||||
$cmd[] = 'git clean -d --force'; | $cmd[] = 'git clean -d --force'; | ||||
$cmd[] = 'git fetch'; | $cmd[] = 'git fetch'; | ||||
$commit = idx($spec, 'commit'); | $commit = idx($spec, 'commit'); | ||||
$branch = idx($spec, 'branch'); | $branch = idx($spec, 'branch'); | ||||
$ref = idx($spec, 'ref'); | $ref = idx($spec, 'ref'); | ||||
// Reset things first, in case previous builds left anything staged or | // Reset things first, in case previous builds left anything staged or | ||||
// dirty. | // dirty. | ||||
$cmd[] = 'git reset --hard HEAD'; | $cmd[] = 'git reset --hard HEAD'; | ||||
if ($commit !== null) { | if ($commit !== null) { | ||||
$cmd[] = 'git checkout %s --'; | $cmd[] = 'git checkout %s --'; | ||||
$arg[] = $commit; | $arg[] = $commit; | ||||
} else if ($branch !== null) { | } else if ($branch !== null) { | ||||
$cmd[] = 'git checkout %s --'; | $cmd[] = 'git checkout %s --'; | ||||
$arg[] = $branch; | $arg[] = $branch; | ||||
$cmd[] = 'git reset --hard origin/%s'; | $cmd[] = 'git reset --hard origin/%s'; | ||||
$arg[] = $branch; | $arg[] = $branch; | ||||
} else if ($ref) { | } | ||||
$this->execxv($interface, $cmd, $arg); | |||||
if (idx($spec, 'default')) { | |||||
$default = $directory; | |||||
} | |||||
// If we're fetching a ref from a remote, do that separately so we can | |||||
// raise a more tailored error. | |||||
if ($ref) { | |||||
$cmd = array(); | |||||
$arg = array(); | |||||
$ref_uri = $ref['uri']; | $ref_uri = $ref['uri']; | ||||
$ref_ref = $ref['ref']; | $ref_ref = $ref['ref']; | ||||
$cmd[] = 'git fetch --no-tags -- %s +%s:%s'; | $cmd[] = 'git fetch --no-tags -- %s +%s:%s'; | ||||
$arg[] = $ref_uri; | $arg[] = $ref_uri; | ||||
$arg[] = $ref_ref; | $arg[] = $ref_ref; | ||||
$arg[] = $ref_ref; | $arg[] = $ref_ref; | ||||
$cmd[] = 'git checkout %s --'; | $cmd[] = 'git checkout %s --'; | ||||
$arg[] = $ref_ref; | $arg[] = $ref_ref; | ||||
} | |||||
$cmd = implode(' && ', $cmd); | |||||
$argv = array_merge(array($cmd), $arg); | |||||
$result = call_user_func_array( | try { | ||||
array($interface, 'execx'), | $this->execxv($interface, $cmd, $arg); | ||||
$argv); | } catch (CommandException $ex) { | ||||
$display_command = csprintf( | |||||
'git fetch %R %R', | |||||
$ref_uri, | |||||
$ref_ref); | |||||
$error = DrydockCommandError::newFromCommandException($ex) | |||||
->setPhase(self::PHASE_REMOTEFETCH) | |||||
->setDisplayCommand($display_command); | |||||
$lease->setAttribute( | |||||
'workingcopy.vcs.error', | |||||
$error->toDictionary()); | |||||
if (idx($spec, 'default')) { | throw $ex; | ||||
$default = $directory; | } | ||||
} | } | ||||
$merges = idx($spec, 'merges'); | $merges = idx($spec, 'merges'); | ||||
if ($merges) { | if ($merges) { | ||||
foreach ($merges as $merge) { | foreach ($merges as $merge) { | ||||
$this->applyMerge($lease, $interface, $merge); | $this->applyMerge($lease, $interface, $merge); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | final class DrydockWorkingCopyBlueprintImplementation | ||||
private function applyMerge( | private function applyMerge( | ||||
DrydockLease $lease, | DrydockLease $lease, | ||||
DrydockCommandInterface $interface, | DrydockCommandInterface $interface, | ||||
array $merge) { | array $merge) { | ||||
$src_uri = $merge['src.uri']; | $src_uri = $merge['src.uri']; | ||||
$src_ref = $merge['src.ref']; | $src_ref = $merge['src.ref']; | ||||
try { | |||||
$interface->execx( | $interface->execx( | ||||
'git fetch --no-tags -- %s +%s:%s', | 'git fetch --no-tags -- %s +%s:%s', | ||||
$src_uri, | $src_uri, | ||||
$src_ref, | $src_ref, | ||||
$src_ref); | $src_ref); | ||||
} catch (CommandException $ex) { | |||||
$display_command = csprintf( | |||||
'git fetch %R +%R:%R', | |||||
$src_uri, | |||||
$src_ref, | |||||
$src_ref); | |||||
$error = DrydockCommandError::newFromCommandException($ex) | |||||
->setPhase(self::PHASE_MERGEFETCH) | |||||
->setDisplayCommand($display_command); | |||||
$lease->setAttribute('workingcopy.vcs.error', $error->toDictionary()); | |||||
throw $ex; | |||||
} | |||||
// NOTE: This can never actually generate a commit because we pass | // NOTE: This can never actually generate a commit because we pass | ||||
// "--squash", but git sometimes runs code to check that a username and | // "--squash", but git sometimes runs code to check that a username and | ||||
// email are configured anyway. | // email are configured anyway. | ||||
$real_command = csprintf( | $real_command = csprintf( | ||||
'git -c user.name=%s -c user.email=%s merge --no-stat --squash -- %R', | 'git -c user.name=%s -c user.email=%s merge --no-stat --squash -- %R', | ||||
'drydock', | 'drydock', | ||||
'drydock@phabricator', | 'drydock@phabricator', | ||||
$src_ref); | $src_ref); | ||||
// Show the user a simplified command if the operation fails and we need to | |||||
// report an error. | |||||
$show_command = csprintf( | |||||
'git merge --squash -- %R', | |||||
$src_ref); | |||||
try { | try { | ||||
$interface->execx('%C', $real_command); | $interface->execx('%C', $real_command); | ||||
} catch (CommandException $ex) { | } catch (CommandException $ex) { | ||||
$error = DrydockCommandError::newFromCommandException( | $display_command = csprintf( | ||||
self::PHASE_SQUASHMERGE, | 'git merge --squash %R', | ||||
$show_command, | $src_ref); | ||||
$ex); | |||||
$error = DrydockCommandError::newFromCommandException($ex) | |||||
->setPhase(self::PHASE_SQUASHMERGE) | |||||
->setDisplayCommand($display_command); | |||||
$lease->setAttribute('workingcopy.vcs.error', $error); | $lease->setAttribute('workingcopy.vcs.error', $error->toDictionary()); | ||||
throw $ex; | throw $ex; | ||||
} | } | ||||
} | } | ||||
public function getCommandError(DrydockLease $lease) { | public function getCommandError(DrydockLease $lease) { | ||||
$error = $lease->getAttribute('workingcopy.vcs.error'); | return $lease->getAttribute('workingcopy.vcs.error'); | ||||
if (!$error) { | |||||
return null; | |||||
} else { | |||||
return $error; | |||||
} | } | ||||
private function execxv( | |||||
DrydockCommandInterface $interface, | |||||
array $commands, | |||||
array $arguments) { | |||||
$commands = implode(' && ', $commands); | |||||
$argv = array_merge(array($commands), $arguments); | |||||
return call_user_func_array(array($interface, 'execx'), $argv); | |||||
} | } | ||||
} | } |