Completed
Push — master ( 9f8ca5...f1c03e )
by
unknown
13s queued 11s
created

ShellBuilder::command()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPSu\ShellCommandBuilder;
6
7
use PHPSu\ShellCommandBuilder\Collection\CollectionTuple;
8
use PHPSu\ShellCommandBuilder\Collection\Pipeline;
9
use PHPSu\ShellCommandBuilder\Collection\Redirection;
10
use PHPSu\ShellCommandBuilder\Collection\ShellList;
11
use PHPSu\ShellCommandBuilder\Conditional\BasicExpression;
12
use PHPSu\ShellCommandBuilder\Definition\ControlOperator;
13
use PHPSu\ShellCommandBuilder\Definition\GroupType;
14
use PHPSu\ShellCommandBuilder\Exception\ShellBuilderException;
15
use TypeError;
16
17
final class ShellBuilder implements ShellInterface, \JsonSerializable
18
{
19
    /** @var array<ShellInterface|CollectionTuple>  */
20
    private $commandList = [];
21
    /** @var int */
22
    private $groupType;
23
    /** @var bool */
24
    private $asynchronously = false;
25
26
    /**
27
     * This is a shortcut for quicker fluid access to the shell builder
28
     * @return static
29
     */
30
    public static function new(): self
31
    {
32
        return new ShellBuilder();
33
    }
34
35
    /**
36
     * This is a shortcut for quicker fluid access to the command api
37
     * @param string $executable
38
     * @return ShellCommand
39
     */
40
    public static function command(string $executable): ShellCommand
41
    {
42
        return new ShellCommand($executable, new self());
43
    }
44
45
    public function __construct(int $groupType = GroupType::NO_GROUP)
46
    {
47
        $this->groupType = $groupType;
48
    }
49
50
    public function createCommand(string $name, bool $withNewBuilder = false): ShellCommand
51
    {
52
        return new ShellCommand($name, $withNewBuilder ? new self() : $this);
53
    }
54
55
    public function runAsynchronously(bool $isAsync = true): self
56
    {
57
        $this->asynchronously = $isAsync;
58
        return $this;
59
    }
60
61
    /**
62
     * @param string|ShellInterface $command
63
     * @return $this
64
     * @throws ShellBuilderException
65
     */
66
    public function add($command): self
67
    {
68
        $command = $this->parseCommand($command, true);
69
        if (empty($this->commandList)) {
70
            $this->commandList[] = $command;
71
            return $this;
72
        }
73
        $this->commandList[] = ShellList::add($command);
74
        return $this;
75
    }
76
77
    /**
78
     * @param string|ShellInterface $command
79
     * @return $this
80
     * @throws ShellBuilderException
81
     */
82
    public function and($command): self
83
    {
84
        $this->commandList[] = ShellList::addAnd($this->parseCommand($command));
85
        return $this;
86
    }
87
88
    /**
89
     * @param string|ShellInterface $command
90
     * @return $this
91
     * @throws ShellBuilderException
92
     */
93
    public function or($command): self
94
    {
95
        $this->commandList[] = ShellList::addOr($this->parseCommand($command));
96
        return $this;
97
    }
98
99
    /**
100
     * @param string|ShellInterface $command
101
     * @return $this
102
     * @throws ShellBuilderException
103
     */
104
    public function async($command): self
105
    {
106
        $this->commandList[] = ShellList::async($this->parseCommand($command));
107
        return $this;
108
    }
109
110
    /**
111
     * @param string|ShellInterface $command
112
     * @return $this
113
     * @throws ShellBuilderException
114
     */
115
    public function pipe($command): self
116
    {
117
        $this->commandList[] = Pipeline::pipe($this->parseCommand($command));
118
        return $this;
119
    }
120
121
    /**
122
     * @param string|ShellInterface $command
123
     * @return $this
124
     * @throws ShellBuilderException
125
     */
126
    public function pipeWithForward($command): self
127
    {
128
        $this->commandList[] = Pipeline::pipeErrorForward($this->parseCommand($command));
129
        return $this;
130
    }
131
132
    /**
133
     * @param string|ShellInterface $command
134
     * @param bool $append
135
     * @return $this
136
     * @throws ShellBuilderException
137
     */
138
    public function redirectOutput($command, bool $append = false): self
139
    {
140
        $command = $this->parseCommand($command);
141
        $this->commandList[] = Redirection::redirectOutput($command, $append);
142
        return $this;
143
    }
144
145
    /**
146
     * @param string|ShellInterface $command
147
     * @return $this
148
     * @throws ShellBuilderException
149
     */
150
    public function redirectInput($command): self
151
    {
152
        $command = $this->parseCommand($command);
153
        $this->commandList[] = Redirection::redirectInput($command);
154
        return $this;
155
    }
156
157
    /**
158
     * @param string|ShellInterface $command
159
     * @return $this
160
     * @throws ShellBuilderException
161
     */
162
    public function redirectError($command): self
163
    {
164
        $command = $this->parseCommand($command);
165
        $this->commandList[] = Redirection::redirectError($command);
166
        return $this;
167
    }
168
169
    /**
170
     * @param string|ShellInterface $command
171
     * @param bool $toLeft
172
     * @return $this
173
     * @throws ShellBuilderException
174
     */
175
    public function redirect($command, bool $toLeft = true): self
176
    {
177
        $command = $this->parseCommand($command);
178
        $this->commandList[] = Redirection::redirectBetweenFiles($command, $toLeft);
179
        return $this;
180
    }
181
182
    public function redirectErrorToOutput(): self
183
    {
184
        $this->commandList[] = Redirection::redirectErrorToOutput();
185
        return $this;
186
    }
187
188
    public function addCondition(BasicExpression $condition): self
189
    {
190
        $this->commandList[] = $condition;
191
        return $this;
192
    }
193
194
    public function createGroup(bool $inSameShell = false): self
195
    {
196
        return new self($inSameShell ? GroupType::SAMESHELL_GROUP : GroupType::SUBSHELL_GROUP);
197
    }
198
199
    /**
200
     * @param string|ShellInterface $command
201
     * @param bool $allowEmpty
202
     * @return ShellInterface
203
     * @throws ShellBuilderException
204
     */
205
    private function parseCommand($command, bool $allowEmpty = false): ShellInterface
206
    {
207
        if (is_string($command)) {
208
            $command = $this->createCommand($command);
209
        }
210
        try {
211
            $this->validateCommand($command, $allowEmpty);
212
        } catch (TypeError $typeError) {
213
            throw new ShellBuilderException('Provided the wrong type - only ShellCommand and ShellBuilder allowed');
214
        }
215
        return $command;
216
    }
217
218
    /** @noinspection PhpUnusedParameterInspection */
219
    private function validateCommand(ShellInterface $command, bool $allowEmpty): void
0 ignored issues
show
Unused Code introduced by
The parameter $command is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

219
    private function validateCommand(/** @scrutinizer ignore-unused */ ShellInterface $command, bool $allowEmpty): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
220
    {
221
        if (!$allowEmpty && empty($this->commandList)) {
222
            throw new ShellBuilderException('You have to first add a command before you can combine it');
223
        }
224
    }
225
226
    public function jsonSerialize(): array
227
    {
228
        return $this->__toArray();
229
    }
230
231
    /**
232
     * @return array<mixed>
233
     */
234
    public function __toArray(): array
235
    {
236
        $commands = [];
237
        foreach ($this->commandList as $item) {
238
            $commands[] = $item instanceof ShellInterface ? $item->__toArray() : $item;
239
        }
240
        return $commands;
241
    }
242
243
    public function __toString(): string
244
    {
245
        $result = '';
246
        if ($this->asynchronously) {
247
            $result = 'coproc ';
248
        }
249
        foreach ($this->commandList as $command) {
250
            $result .= $command;
251
        }
252
        if ($this->groupType === GroupType::SAMESHELL_GROUP) {
253
            return sprintf(
254
                '%s%s;%s',
255
                ControlOperator::CURLY_BLOCK_DEFINITON_OPEN,
256
                $result,
257
                ControlOperator::CURLY_BLOCK_DEFINITON_CLOSE
258
            );
259
        }
260
        if ($this->groupType === GroupType::SUBSHELL_GROUP) {
261
            return sprintf(
262
                '%s%s%s',
263
                ControlOperator::BLOCK_DEFINITON_OPEN,
264
                $result,
265
                ControlOperator::BLOCK_DEFINITON_CLOSE
266
            );
267
        }
268
        return $result;
269
    }
270
}
271