SeleniumProcess::addBinary()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
rs 9.7
cc 4
nc 4
nop 2
1
<?php
2
namespace Peridot\WebDriverManager\Process;
3
4
use Peridot\WebDriverManager\Binary\BinaryInterface;
5
use Peridot\WebDriverManager\Binary\DriverInterface;
6
7
/**
8
 * SeleniumProcess is responsible for controlling Selenium Server processes.
9
 *
10
 * @package Peridot\WebDriverManager\Process
11
 */
12
class SeleniumProcess implements SeleniumProcessInterface
13
{
14
    /**
15
     * @var array
16
     */
17
    protected $args = [];
18
19
    /**
20
     * @var resource
21
     */
22
    protected $process = null;
23
24
    /**
25
     * @var array
26
     */
27
    protected $pipes = [];
28
29
    public function __construct()
30
    {
31
    }
32
33
    /**
34
     * {@inheritdoc}
35
     *
36
     * @param BinaryInterface $binary
37
     * @param string $directory
38
     * @return void
39
     */
40
    public function addBinary(BinaryInterface $binary, $directory)
41
    {
42
        if (! $binary->exists($directory)) {
43
            return;
44
        }
45
46
        if ($binary instanceof DriverInterface) {
47
            $this->addArg('-D' . $binary->getDriverPath($directory));
48
            return;
49
        }
50
51
        if($this->pathContains($binary->getFileName(), ".jar")){
52
            $this->addArg('-jar');
53
        }
54
55
        $this->addArg(realpath($directory . '/' . $binary->getFileName()));
56
    }
57
58
    private function pathContains($path, $match)
59
    {
60
        return strpos($path, $match) !== false;
61
    }
62
63
64
    /**
65
     * {@inheritdoc}
66
     *
67
     * @return array
68
     */
69
    public function getArgs()
70
    {
71
        return $this->args;
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     *
77
     * @param string $arg
78
     * @return void
79
     */
80
    public function addArg($arg)
81
    {
82
        $this->args[] = $arg;
83
        $rest = array_slice(func_get_args(), 1);
84
        foreach ($rest as $arg) {
85
            $this->args[] = $arg;
86
        }
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     *
92
     * @param array $args
93
     * @return void
94
     */
95
    public function addArgs(array $args)
96
    {
97
        foreach ($args as $arg) {
98
            $this->args[] = $arg;
99
        }
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     *
105
     * @return bool
106
     */
107
    public function isAvailable()
108
    {
109
        $command = 'java -version';
110
        $descriptors = $this->getDescriptorSpec();
111
        $this->process = proc_open($this->formatCommand($command), $descriptors, $this->pipes);
112
        $status = $this->getStatus(true);
113
        $available = $status['exitcode'] == 0;
114
        proc_close($this->process);
115
        return $available;
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     *
121
     * @return $this
122
     */
123
    public function start($background = false)
124
    {
125
        $command = $this->getCommand();
126
        if (! $background) {
127
            exec($command);
128
            return $this;
129
        }
130
131
        $descriptors = $this->getDescriptorSpec();
132
        $this->process = proc_open($command, $descriptors, $this->pipes);
133
        return $this;
134
    }
135
136
    /**
137
     * {@inheritdoc}
138
     *
139
     * @return string
140
     */
141
    public function getCommand()
142
    {
143
        return $this->formatCommand('java ' . implode(' ', $this->args));
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     *
149
     * @param bool $loop
150
     * @return array
151
     */
152
    public function getStatus($loop = false)
153
    {
154
        $status = proc_get_status($this->process);
155
        while ($loop && $status['running']) {
156
            usleep(20000);
157
            $status = proc_get_status($this->process);
158
        }
159
        return $status;
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     *
165
     * @return bool
166
     */
167
    public function isRunning()
168
    {
169
        $status = $this->getStatus();
170
        return $status['running'];
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     *
176
     * @return string
177
     */
178
    public function getError()
179
    {
180
        return stream_get_contents($this->pipes[2]);
181
    }
182
183
    /**
184
     * {@inheritdoc}
185
     *
186
     * @return int
187
     */
188
    public function close()
189
    {
190
        proc_terminate($this->process);
191
        return proc_close($this->process);
192
    }
193
194
    /**
195
     * Format a shell command according to the running Operating System to avoid zombie processes.
196
     *
197
     * @param string $command A shell command.
198
     * @return string
199
     */
200
    private function formatCommand($command)
201
    {
202
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
203
            return $command;
204
        }
205
        return 'exec ' . $command;
206
    }
207
208
    /**
209
     * Helper to create an array suitable as a descriptor for process streams.
210
     *
211
     * @return array
212
     */
213
    private function getDescriptorSpec()
214
    {
215
        return [
216
            0 => ['pipe', 'r'],
217
            1 => ['pipe', 'w'],
218
            2 => ['pipe', 'w']
219
        ];
220
    }
221
}
222