1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of Bldr.io |
5
|
|
|
* |
6
|
|
|
* (c) Aaron Scherer <[email protected]> |
7
|
|
|
* |
8
|
|
|
* This source file is subject to the MIT license that is bundled |
9
|
|
|
* with this source code in the file LICENSE |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Bldr\Block\Execute\Task; |
13
|
|
|
|
14
|
|
|
use Bldr\Block\Execute\Service\BackgroundService; |
15
|
|
|
use Bldr\Block\Core\Task\AbstractTask; |
16
|
|
|
use Bldr\Exception\TaskRuntimeException; |
17
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
18
|
|
|
use Symfony\Component\Console\Output\StreamOutput; |
19
|
|
|
use Symfony\Component\Process\ProcessBuilder; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @author Aaron Scherer <[email protected]> |
23
|
|
|
*/ |
24
|
|
|
class BackgroundTask extends AbstractTask |
25
|
|
|
{ |
26
|
|
|
/** |
27
|
|
|
* @var BackgroundService $background |
28
|
|
|
*/ |
29
|
|
|
private $background; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @param BackgroundService $background |
33
|
|
|
*/ |
34
|
|
|
public function __construct(BackgroundService $background) |
35
|
|
|
{ |
36
|
|
|
$this->background = $background; |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Configures the Task |
41
|
|
|
*/ |
42
|
|
|
public function configure() |
43
|
|
|
{ |
44
|
|
|
$this->setName('background') |
45
|
|
|
->setDescription('Executes the given options using the executable in the background') |
46
|
|
|
->addParameter('executable', true, 'Executable to run') |
47
|
|
|
->addParameter('arguments', false, 'Arguments to run on the executable', []) |
48
|
|
|
->addParameter('cwd', false, 'Sets the working directory for the executable') |
49
|
|
|
->addParameter('output', false, 'Sets the location to output to') |
50
|
|
|
->addParameter('append', false, 'If output is set, should it append?', false) |
51
|
|
|
->addParameter('kill', false, 'Are we killing the task?', false) |
52
|
|
|
; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* {@inheritDoc} |
57
|
|
|
*/ |
58
|
|
|
public function run(OutputInterface $output) |
59
|
|
|
{ |
60
|
|
|
if ($this->getParameter('kill') === false) { |
61
|
|
|
$this->startProcess($output); |
62
|
|
|
|
63
|
|
|
return true; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
$this->endProcess(); |
67
|
|
|
|
68
|
|
|
return true; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Creates the given process |
73
|
|
|
* |
74
|
|
|
* @throws \Exception |
75
|
|
|
*/ |
76
|
|
|
private function startProcess(OutputInterface $output) |
77
|
|
|
{ |
78
|
|
|
$arguments = $this->resolveProcessArgs(); |
79
|
|
|
$name = sha1(serialize($arguments)); |
80
|
|
|
if ($this->background->hasProcess($name)) { |
81
|
|
|
throw new \RuntimeException("Service is already running."); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
$builder = new ProcessBuilder($arguments); |
85
|
|
|
|
86
|
|
|
if ($this->hasParameter('cwd')) { |
87
|
|
|
$builder->setWorkingDirectory($this->getParameter('cwd')); |
|
|
|
|
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
$process = $builder->getProcess(); |
91
|
|
|
|
92
|
|
|
if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERBOSE) { |
93
|
|
|
$output->writeln($process->getCommandLine()); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
if ($this->hasParameter('output')) { |
97
|
|
|
$append = $this->hasParameter('append') && $this->getParameter('append') ? 'a' : 'w'; |
98
|
|
|
$stream = fopen($this->getParameter('output'), $append); |
99
|
|
|
$output = new StreamOutput($stream, StreamOutput::VERBOSITY_NORMAL, true); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
$process->start( |
103
|
|
|
function ($type, $buffer) use ($output) { |
104
|
|
|
$output->write($buffer); |
105
|
|
|
} |
106
|
|
|
); |
107
|
|
|
|
108
|
|
|
$this->background->addProcess($name, $process); |
109
|
|
|
|
110
|
|
|
if (!in_array($process->getExitCode(), $this->getParameter('successCodes'))) { |
111
|
|
|
throw new TaskRuntimeException($this->getName(), $process->getErrorOutput()); |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Kills the given process |
117
|
|
|
*/ |
118
|
|
|
private function endProcess() |
119
|
|
|
{ |
120
|
|
|
$arguments = $this->resolveProcessArgs(); |
121
|
|
|
$name = sha1(serialize($arguments)); |
122
|
|
|
if ($this->background->hasProcess($name)) { |
123
|
|
|
$this->background->getProcess($name)->stop(); |
124
|
|
|
$this->background->removeProcess($name); |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Resolves the Executable and Arguments and returns a merged array |
130
|
|
|
* |
131
|
|
|
* @return array |
132
|
|
|
*/ |
133
|
|
|
protected function resolveProcessArgs() |
134
|
|
|
{ |
135
|
|
|
return array_merge( |
136
|
|
|
[$this->getParameter('executable')], |
137
|
|
|
$this->getParameter('arguments') |
138
|
|
|
); |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
|
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.