1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of tenside/core. |
5
|
|
|
* |
6
|
|
|
* (c) Christian Schiffler <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
* |
11
|
|
|
* This project is provided in good faith and hope to be usable by anyone. |
12
|
|
|
* |
13
|
|
|
* @package tenside/core |
14
|
|
|
* @author Christian Schiffler <[email protected]> |
15
|
|
|
* @copyright 2015 Christian Schiffler <[email protected]> |
16
|
|
|
* @license https://github.com/tenside/core/blob/master/LICENSE MIT |
17
|
|
|
* @link https://github.com/tenside/core |
18
|
|
|
* @filesource |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
namespace Tenside\Core\Task; |
22
|
|
|
|
23
|
|
|
use Composer\IO\ConsoleIO; |
24
|
|
|
use Composer\IO\IOInterface; |
25
|
|
|
use Symfony\Component\Console\Helper\HelperSet; |
26
|
|
|
use Symfony\Component\Console\Input\ArrayInput; |
27
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
28
|
|
|
use Tenside\Core\Util\JsonArray; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Abstract base class for tasks. |
32
|
|
|
*/ |
33
|
|
|
abstract class Task |
|
|
|
|
34
|
|
|
{ |
35
|
|
|
/** |
36
|
|
|
* The type of the task. |
37
|
|
|
*/ |
38
|
|
|
const SETTING_TYPE = 'type'; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* The id of the task. |
42
|
|
|
*/ |
43
|
|
|
const SETTING_ID = 'id'; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* The ISO 8601 date when the task got created. |
47
|
|
|
*/ |
48
|
|
|
const SETTING_CREATED_AT = 'created-at'; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* This state determines that the task is still awaiting to be executed. |
52
|
|
|
*/ |
53
|
|
|
const STATE_PENDING = 'PENDING'; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* This state determines that the task is still running. |
57
|
|
|
*/ |
58
|
|
|
const STATE_RUNNING = 'RUNNING'; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* This state determines that the task has been finished. |
62
|
|
|
*/ |
63
|
|
|
const STATE_FINISHED = 'FINISHED'; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* This state determines that the task has been finished with errors. |
67
|
|
|
*/ |
68
|
|
|
const STATE_ERROR = 'ERROR'; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* The task file to write to. |
72
|
|
|
* |
73
|
|
|
* @var JsonArray |
74
|
|
|
*/ |
75
|
|
|
protected $file; |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* The log file to write to. |
79
|
|
|
* |
80
|
|
|
* @var string |
81
|
|
|
*/ |
82
|
|
|
protected $logFile; |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* The input/output handler. |
86
|
|
|
* |
87
|
|
|
* @var IOInterface |
88
|
|
|
*/ |
89
|
|
|
private $inputOutput; |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Task constructor. |
93
|
|
|
* |
94
|
|
|
* @param JsonArray $file The json file to write to. |
95
|
|
|
*/ |
96
|
|
|
public function __construct(JsonArray $file) |
97
|
|
|
{ |
98
|
|
|
$this->file = $file; |
99
|
|
|
|
100
|
|
|
if ($this->file->has('log')) { |
101
|
|
|
$this->logFile = $this->file->get('log'); |
|
|
|
|
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Retrieve the task id. |
107
|
|
|
* |
108
|
|
|
* @return string |
|
|
|
|
109
|
|
|
*/ |
110
|
|
|
public function getId() |
111
|
|
|
{ |
112
|
|
|
return $this->file->get('id'); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Retrieve the current output. |
117
|
|
|
* |
118
|
|
|
* @param null|int $offset The offset in bytes to read from. |
119
|
|
|
* |
120
|
|
|
* @return string |
121
|
|
|
*/ |
122
|
|
|
public function getOutput($offset = null) |
123
|
|
|
{ |
124
|
|
|
if (!$this->logFile) { |
125
|
|
|
return ''; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
return (string) file_get_contents($this->logFile, FILE_BINARY, null, $offset); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Retrieve the task type name. |
133
|
|
|
* |
134
|
|
|
* @return string |
135
|
|
|
*/ |
136
|
|
|
abstract public function getType(); |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Perform the task. |
140
|
|
|
* |
141
|
|
|
* @param string $logFile The log file to write to. |
142
|
|
|
* |
143
|
|
|
* @return void |
144
|
|
|
* |
145
|
|
|
* @throws \LogicException When the task has already been run. |
146
|
|
|
* |
147
|
|
|
* @throws \RuntimeException When the execution. failed. |
148
|
|
|
*/ |
149
|
|
|
public function perform($logFile) |
150
|
|
|
{ |
151
|
|
|
if (self::STATE_PENDING !== $this->getStatus()) { |
152
|
|
|
throw new \LogicException('Attempted to run task ' . $this->getId() . ' twice.'); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
try { |
156
|
|
|
if (!is_dir(dirname($logFile))) { |
157
|
|
|
mkdir(dirname($logFile), 0777, true); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
file_put_contents($logFile, '', FILE_BINARY); |
161
|
|
|
|
162
|
|
|
$this->logFile = $logFile; |
163
|
|
|
$this->file->set('log', $logFile); |
164
|
|
|
|
165
|
|
|
$this->setStatus(self::STATE_RUNNING); |
166
|
|
|
$this->addOutput('Task ' . $this->getId() . ' started.' . "\n"); |
167
|
|
|
|
168
|
|
|
$this->doPerform(); |
169
|
|
|
} catch (\Exception $exception) { |
170
|
|
|
$this->addOutput('--------------------------------------------------------' . "\n"); |
171
|
|
|
$this->addOutput('Exception occured: ' . $exception->getMessage() . "\n"); |
172
|
|
|
$this->addOutput($exception->getTraceAsString() . "\n"); |
173
|
|
|
$loopException = $exception; |
174
|
|
|
while ($loopException = $loopException->getPrevious()) { |
175
|
|
|
$this->addOutput('Chained exception: ' . $loopException->getMessage() . "\n"); |
176
|
|
|
$this->addOutput($loopException->getTraceAsString() . "\n"); |
177
|
|
|
} |
178
|
|
|
$this->addOutput('--------------------------------------------------------' . "\n"); |
179
|
|
|
|
180
|
|
|
$this->setStatus(self::STATE_ERROR); |
181
|
|
|
|
182
|
|
|
throw new \RuntimeException( |
183
|
|
|
'Task ' . $this->getId() . ' errored: ' . $exception->getMessage(), |
184
|
|
|
1, |
185
|
|
|
$exception |
186
|
|
|
); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
$this->addOutput('Finished without error.' . "\n"); |
190
|
|
|
$this->setStatus(self::STATE_FINISHED); |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Perform the task. |
195
|
|
|
* |
196
|
|
|
* @return void |
197
|
|
|
*/ |
198
|
|
|
abstract public function doPerform(); |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* Add some output. |
202
|
|
|
* |
203
|
|
|
* @param string $string The output string to append to the output. |
204
|
|
|
* |
205
|
|
|
* @return void |
206
|
|
|
* |
207
|
|
|
* @throws \LogicException When called prior to perform(). |
208
|
|
|
*/ |
209
|
|
|
public function addOutput($string) |
210
|
|
|
{ |
211
|
|
|
if (!$this->logFile) { |
212
|
|
|
throw new \LogicException('The has not started to run yet.'); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
file_put_contents($this->logFile, $string, (FILE_APPEND | FILE_BINARY)); |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Retrieve the IO interface. |
220
|
|
|
* |
221
|
|
|
* @return IOInterface |
222
|
|
|
*/ |
223
|
|
|
public function getIO() |
224
|
|
|
{ |
225
|
|
|
if (!isset($this->inputOutput)) { |
226
|
|
|
$this->inputOutput = new ConsoleIO($this->getInput(), new TaskOutput($this), new HelperSet([])); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
return $this->inputOutput; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* Retrieve the current status of a task. |
234
|
|
|
* |
235
|
|
|
* @return string |
|
|
|
|
236
|
|
|
*/ |
237
|
|
|
public function getStatus() |
238
|
|
|
{ |
239
|
|
|
return $this->file->get('status'); |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* Retrieve when this task got created as ISO 8601 date string. |
244
|
|
|
* |
245
|
|
|
* @return \DateTime |
246
|
|
|
*/ |
247
|
|
|
public function getCreatedAt() |
248
|
|
|
{ |
249
|
|
|
return \DateTime::createFromFormat(DATE_ISO8601, $this->file->get('created-at')); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Remove the attached files for this task from disk. |
254
|
|
|
* |
255
|
|
|
* @return void |
256
|
|
|
*/ |
257
|
|
|
public function removeAssets() |
258
|
|
|
{ |
259
|
|
|
// Base implementation does only know about log file. |
260
|
|
|
if ($this->logFile) { |
261
|
|
|
if (file_exists($this->logFile)) { |
262
|
|
|
unlink($this->logFile); |
263
|
|
|
} |
264
|
|
|
$this->logFile = null; |
265
|
|
|
$this->file->remove('log'); |
266
|
|
|
} |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
/** |
270
|
|
|
* Set the task state. |
271
|
|
|
* |
272
|
|
|
* @param string $status The status code. |
273
|
|
|
* |
274
|
|
|
* @return void |
275
|
|
|
*/ |
276
|
|
|
protected function setStatus($status) |
277
|
|
|
{ |
278
|
|
|
$this->file->set('status', $status); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Retrieve the Input handler. |
283
|
|
|
* |
284
|
|
|
* @return InputInterface |
|
|
|
|
285
|
|
|
*/ |
286
|
|
|
private function getInput() |
287
|
|
|
{ |
288
|
|
|
$input = new ArrayInput([]); |
289
|
|
|
|
290
|
|
|
$input->setInteractive(false); |
291
|
|
|
|
292
|
|
|
return $input; |
293
|
|
|
} |
294
|
|
|
} |
295
|
|
|
|
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.