Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/drydock/worker/DrydockRepositoryOperationUpdateWorker.php
12256 views
1
<?php
2
3
final class DrydockRepositoryOperationUpdateWorker
4
extends DrydockWorker {
5
6
protected function doWork() {
7
$operation_phid = $this->getTaskDataValue('operationPHID');
8
9
$hash = PhabricatorHash::digestForIndex($operation_phid);
10
$lock_key = 'drydock.operation:'.$hash;
11
12
$lock = PhabricatorGlobalLock::newLock($lock_key)
13
->lock(1);
14
15
try {
16
$operation = $this->loadOperation($operation_phid);
17
$this->handleUpdate($operation);
18
} catch (Exception $ex) {
19
$lock->unlock();
20
throw $ex;
21
}
22
23
$lock->unlock();
24
}
25
26
27
private function handleUpdate(DrydockRepositoryOperation $operation) {
28
$operation_state = $operation->getOperationState();
29
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;
42
}
43
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.
52
53
try {
54
$lease = $this->loadWorkingCopyLease($operation);
55
56
$interface = $lease->getInterface(
57
DrydockCommandInterface::INTERFACE_TYPE);
58
59
// No matter what happens here, destroy the lease away once we're done.
60
$lease->setReleaseOnDestruction(true);
61
62
$operation->attachWorkingCopyLease($lease);
63
64
$operation->logEvent(DrydockOperationWorkLogType::LOGCONST);
65
66
$operation->applyOperation($interface);
67
68
} catch (PhabricatorWorkerYieldException $ex) {
69
throw $ex;
70
} catch (Exception $ex) {
71
$operation
72
->setOperationState(DrydockRepositoryOperation::STATE_FAIL)
73
->save();
74
throw $ex;
75
}
76
77
$operation
78
->setOperationState(DrydockRepositoryOperation::STATE_DONE)
79
->save();
80
81
// TODO: Once we have sequencing, we could awaken the next operation
82
// against this target after finishing or failing.
83
}
84
85
private function loadWorkingCopyLease(
86
DrydockRepositoryOperation $operation) {
87
$viewer = $this->getViewer();
88
89
// TODO: This is very similar to leasing in Harbormaster, maybe we can
90
// share some of the logic?
91
92
$working_copy = new DrydockWorkingCopyBlueprintImplementation();
93
$working_copy_type = $working_copy->getType();
94
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));
106
}
107
} else {
108
$repository = $operation->getRepository();
109
110
$allowed_phids = $repository->getAutomationBlueprintPHIDs();
111
$authorizing_phid = $repository->getPHID();
112
113
$lease = DrydockLease::initializeNewLease()
114
->setResourceType($working_copy_type)
115
->setOwnerPHID($operation->getPHID())
116
->setAuthorizingPHID($authorizing_phid)
117
->setAllowedBlueprintPHIDs($allowed_phids);
118
119
$map = $this->buildRepositoryMap($operation);
120
121
$lease->setAttribute('repositories.map', $map);
122
123
$task_id = $this->getCurrentWorkerTaskID();
124
if ($task_id) {
125
$lease->setAwakenTaskIDs(array($task_id));
126
}
127
128
$operation
129
->setWorkingCopyLeasePHID($lease->getPHID())
130
->save();
131
132
$lease->queueForActivation();
133
}
134
135
if ($lease->isActivating()) {
136
throw new PhabricatorWorkerYieldException(15);
137
}
138
139
if (!$lease->isActive()) {
140
$vcs_error = $working_copy->getCommandError($lease);
141
if ($vcs_error) {
142
$operation
143
->setCommandError($vcs_error)
144
->save();
145
}
146
147
throw new PhabricatorWorkerPermanentFailureException(
148
pht(
149
'Lease "%s" never activated.',
150
$lease->getPHID()));
151
}
152
153
return $lease;
154
}
155
156
private function buildRepositoryMap(DrydockRepositoryOperation $operation) {
157
$repository = $operation->getRepository();
158
159
$target = $operation->getRepositoryTarget();
160
list($type, $name) = explode(':', $target, 2);
161
switch ($type) {
162
case 'branch':
163
$spec = array(
164
'branch' => $name,
165
);
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));
176
}
177
178
$spec['merges'] = $operation->getWorkingCopyMerges();
179
180
$map = array();
181
$map[$repository->getCloneName()] = array(
182
'phid' => $repository->getPHID(),
183
'default' => true,
184
) + $spec;
185
186
return $map;
187
}
188
}
189
190