Correct a parameter order swap in "diffusion.historyquery" for Mercurial
[phabricator.git] / src / applications / drydock / worker / DrydockRepositoryOperationUpdateWorker.php
blobc6e6927f2258cc59c9c7ced58e87955b31eaacb2
1 <?php
3 final class DrydockRepositoryOperationUpdateWorker
4 extends DrydockWorker {
6 protected function doWork() {
7 $operation_phid = $this->getTaskDataValue('operationPHID');
9 $hash = PhabricatorHash::digestForIndex($operation_phid);
10 $lock_key = 'drydock.operation:'.$hash;
12 $lock = PhabricatorGlobalLock::newLock($lock_key)
13 ->lock(1);
15 try {
16 $operation = $this->loadOperation($operation_phid);
17 $this->handleUpdate($operation);
18 } catch (Exception $ex) {
19 $lock->unlock();
20 throw $ex;
23 $lock->unlock();
27 private function handleUpdate(DrydockRepositoryOperation $operation) {
28 $operation_state = $operation->getOperationState();
30 switch ($operation_state) {
31 case DrydockRepositoryOperation::STATE_WAIT:
32 $operation
33 ->setOperationState(DrydockRepositoryOperation::STATE_WORK)
34 ->save();
35 break;
36 case DrydockRepositoryOperation::STATE_WORK:
37 break;
38 case DrydockRepositoryOperation::STATE_DONE:
39 case DrydockRepositoryOperation::STATE_FAIL:
40 // No more processing for these requests.
41 return;
44 // TODO: We should probably check for other running operations with lower
45 // IDs and the same repository target and yield to them here? That is,
46 // enforce sequential evaluation of operations against the same target so
47 // that if you land "A" and then land "B", we always finish "A" first.
48 // For now, just let stuff happen in any order. We can't lease until
49 // we know we're good to move forward because we might deadlock if we do:
50 // we're waiting for another operation to complete, and that operation is
51 // waiting for a lease we're holding.
53 try {
54 $lease = $this->loadWorkingCopyLease($operation);
56 $interface = $lease->getInterface(
57 DrydockCommandInterface::INTERFACE_TYPE);
59 // No matter what happens here, destroy the lease away once we're done.
60 $lease->setReleaseOnDestruction(true);
62 $operation->attachWorkingCopyLease($lease);
64 $operation->logEvent(DrydockOperationWorkLogType::LOGCONST);
66 $operation->applyOperation($interface);
68 } catch (PhabricatorWorkerYieldException $ex) {
69 throw $ex;
70 } catch (Exception $ex) {
71 $operation
72 ->setOperationState(DrydockRepositoryOperation::STATE_FAIL)
73 ->save();
74 throw $ex;
77 $operation
78 ->setOperationState(DrydockRepositoryOperation::STATE_DONE)
79 ->save();
81 // TODO: Once we have sequencing, we could awaken the next operation
82 // against this target after finishing or failing.
85 private function loadWorkingCopyLease(
86 DrydockRepositoryOperation $operation) {
87 $viewer = $this->getViewer();
89 // TODO: This is very similar to leasing in Harbormaster, maybe we can
90 // share some of the logic?
92 $working_copy = new DrydockWorkingCopyBlueprintImplementation();
93 $working_copy_type = $working_copy->getType();
95 $lease_phid = $operation->getProperty('exec.leasePHID');
96 if ($lease_phid) {
97 $lease = id(new DrydockLeaseQuery())
98 ->setViewer($viewer)
99 ->withPHIDs(array($lease_phid))
100 ->executeOne();
101 if (!$lease) {
102 throw new PhabricatorWorkerPermanentFailureException(
103 pht(
104 'Lease "%s" could not be loaded.',
105 $lease_phid));
107 } else {
108 $repository = $operation->getRepository();
110 $allowed_phids = $repository->getAutomationBlueprintPHIDs();
111 $authorizing_phid = $repository->getPHID();
113 $lease = DrydockLease::initializeNewLease()
114 ->setResourceType($working_copy_type)
115 ->setOwnerPHID($operation->getPHID())
116 ->setAuthorizingPHID($authorizing_phid)
117 ->setAllowedBlueprintPHIDs($allowed_phids);
119 $map = $this->buildRepositoryMap($operation);
121 $lease->setAttribute('repositories.map', $map);
123 $task_id = $this->getCurrentWorkerTaskID();
124 if ($task_id) {
125 $lease->setAwakenTaskIDs(array($task_id));
128 $operation
129 ->setWorkingCopyLeasePHID($lease->getPHID())
130 ->save();
132 $lease->queueForActivation();
135 if ($lease->isActivating()) {
136 throw new PhabricatorWorkerYieldException(15);
139 if (!$lease->isActive()) {
140 $vcs_error = $working_copy->getCommandError($lease);
141 if ($vcs_error) {
142 $operation
143 ->setCommandError($vcs_error)
144 ->save();
147 throw new PhabricatorWorkerPermanentFailureException(
148 pht(
149 'Lease "%s" never activated.',
150 $lease->getPHID()));
153 return $lease;
156 private function buildRepositoryMap(DrydockRepositoryOperation $operation) {
157 $repository = $operation->getRepository();
159 $target = $operation->getRepositoryTarget();
160 list($type, $name) = explode(':', $target, 2);
161 switch ($type) {
162 case 'branch':
163 $spec = array(
164 'branch' => $name,
166 break;
167 case 'none':
168 $spec = array();
169 break;
170 default:
171 throw new Exception(
172 pht(
173 'Unknown repository operation target type "%s" (in target "%s").',
174 $type,
175 $target));
178 $spec['merges'] = $operation->getWorkingCopyMerges();
180 $map = array();
181 $map[$repository->getCloneName()] = array(
182 'phid' => $repository->getPHID(),
183 'default' => true,
184 ) + $spec;
186 return $map;