1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace GitWrapper; |
4
|
|
|
|
5
|
|
|
use Symfony\Component\Process\ProcessUtils; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Base class extended by all Git command classes. |
9
|
|
|
*/ |
10
|
|
|
class GitCommand |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* Path to the directory containing the working copy. If this variable is |
14
|
|
|
* set, then the process will change into this directory while the Git |
15
|
|
|
* command is being run. |
16
|
|
|
* |
17
|
|
|
* @var string|null |
18
|
|
|
*/ |
19
|
|
|
protected $directory; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* The command being run, e.g. "clone", "commit", etc. |
23
|
|
|
* |
24
|
|
|
* @var string |
25
|
|
|
*/ |
26
|
|
|
protected $command = ''; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* An associative array of command line options and flags. |
30
|
|
|
* |
31
|
|
|
* @var array |
32
|
|
|
*/ |
33
|
|
|
protected $options = array(); |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Command line arguments passed to the Git command. |
37
|
|
|
* |
38
|
|
|
* @var array |
39
|
|
|
*/ |
40
|
|
|
protected $args = array(); |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Whether command execution should be bypassed. |
44
|
|
|
* |
45
|
|
|
* @var bool |
46
|
|
|
*/ |
47
|
|
|
protected $bypass = false; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Whether to execute the raw command without escaping it. This is useful |
51
|
|
|
* for executing arbitrary commands, e.g. "status -s". If this is true, |
52
|
|
|
* any options and arguments are ignored. |
53
|
|
|
* |
54
|
|
|
* @var bool |
55
|
|
|
*/ |
56
|
|
|
protected $executeRaw = false; |
57
|
260 |
|
|
58
|
|
|
/** |
59
|
260 |
|
* Constructs a GitCommand object. |
60
|
|
|
* |
61
|
|
|
* Use GitCommand::getInstance() as the factory method for this class. |
62
|
244 |
|
* |
63
|
|
|
* @param array $args |
64
|
|
|
* The arguments passed to GitCommand::getInstance(). |
65
|
244 |
|
*/ |
66
|
244 |
|
protected function __construct($args) |
67
|
212 |
|
{ |
68
|
212 |
|
if ($args) { |
|
|
|
|
69
|
212 |
|
|
70
|
|
|
// The first argument is the command. |
71
|
|
|
$this->command = array_shift($args); |
72
|
244 |
|
|
73
|
208 |
|
// If the last element is an array, set it as the options. |
74
|
244 |
|
$options = end($args); |
75
|
244 |
|
if (is_array($options)) { |
76
|
260 |
|
$this->setOptions($options); |
77
|
|
|
array_pop($args); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
// Pass all other method arguments as the Git command arguments. |
81
|
|
|
foreach ($args as $arg) { |
82
|
|
|
$this->addArgument($arg); |
83
|
|
|
} |
84
|
|
|
} |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Constructs a GitCommand object. |
89
|
|
|
* |
90
|
|
|
* Accepts a variable number of arguments to model the arguments passed to |
91
|
|
|
* the Git command line utility. If the last argument is an array, it is |
92
|
|
|
* passed as the command options. |
93
|
|
|
* |
94
|
260 |
|
* @param string $command |
|
|
|
|
95
|
|
|
* The Git command being run, e.g. "clone", "commit", etc. |
96
|
260 |
|
* @param string ... |
97
|
260 |
|
* Zero or more arguments passed to the Git command. |
98
|
|
|
* @param array $options |
|
|
|
|
99
|
|
|
* An optional array of arguments to pass to the command. |
100
|
|
|
* |
101
|
|
|
* @return \GitWrapper\GitCommand |
102
|
|
|
*/ |
103
|
|
|
public static function getInstance() |
104
|
|
|
{ |
105
|
252 |
|
$args = func_get_args(); |
106
|
|
|
return new static($args); |
107
|
252 |
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Returns Git command being run, e.g. "clone", "commit", etc. |
111
|
|
|
* |
112
|
|
|
* @return string |
113
|
|
|
*/ |
114
|
|
|
public function getCommand() |
115
|
|
|
{ |
116
|
|
|
return $this->command; |
117
|
|
|
} |
118
|
236 |
|
|
119
|
|
|
/** |
120
|
236 |
|
* Sets the path to the directory containing the working copy. |
121
|
236 |
|
* |
122
|
|
|
* @param string $directory |
123
|
|
|
* The path to the directory containing the working copy. |
124
|
|
|
* |
125
|
|
|
* @return \GitWrapper\GitCommand |
126
|
|
|
*/ |
127
|
|
|
public function setDirectory($directory) |
128
|
|
|
{ |
129
|
|
|
$this->directory = $directory; |
130
|
244 |
|
return $this; |
131
|
|
|
} |
132
|
244 |
|
|
133
|
|
|
/** |
134
|
|
|
* Gets the path to the directory containing the working copy. |
135
|
|
|
* |
136
|
|
|
* @return string|null |
137
|
|
|
* The path, null if no path is set. |
138
|
|
|
*/ |
139
|
|
|
public function getDirectory() |
140
|
|
|
{ |
141
|
|
|
return $this->directory; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
12 |
|
* A boolean flagging whether to skip running the command. |
146
|
|
|
* |
147
|
12 |
|
* @param boolean $bypass |
148
|
12 |
|
* Whether to bypass execution of the command. The parameter defaults to |
149
|
|
|
* true for code readability, however the default behavior of this class |
150
|
|
|
* is to run the command. |
151
|
|
|
* |
152
|
|
|
* @return \GitWrapper\GitCommand |
153
|
|
|
*/ |
154
|
|
|
public function bypass($bypass = true) |
155
|
|
|
{ |
156
|
|
|
$this->bypass = (bool) $bypass; |
157
|
|
|
return $this; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
240 |
|
* Set whether to execute the command as-is without escaping it. |
162
|
|
|
* |
163
|
240 |
|
* @param boolean $executeRaw |
164
|
|
|
* Whether to execute the command as-is without excaping it. |
165
|
|
|
* |
166
|
|
|
* @return \GitWrapper\GitCommand |
167
|
|
|
*/ |
168
|
|
|
public function executeRaw($executeRaw = true) |
169
|
|
|
{ |
170
|
|
|
$this->executeRaw = $executeRaw; |
171
|
252 |
|
return $this; |
172
|
|
|
} |
173
|
252 |
|
|
174
|
252 |
|
/** |
175
|
224 |
|
* Returns true if the Git command should be run. |
176
|
224 |
|
* |
177
|
224 |
|
* The return value is the boolean opposite $this->bypass. Although this |
178
|
224 |
|
* seems complex, it makes the code more readable when checking whether the |
179
|
208 |
|
* command should be run or not. |
180
|
208 |
|
* |
181
|
208 |
|
* @return boolean |
182
|
224 |
|
* If true, the command should be run. |
183
|
224 |
|
*/ |
184
|
252 |
|
public function notBypassed() |
185
|
252 |
|
{ |
186
|
|
|
return !$this->bypass; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Builds the command line options for use in the Git command. |
191
|
|
|
* |
192
|
|
|
* @return array |
193
|
|
|
*/ |
194
|
|
|
public function buildOptions(): array |
195
|
|
|
{ |
196
|
|
|
$options = array(); |
197
|
|
|
foreach ($this->options as $option => $values) { |
198
|
|
|
foreach ((array) $values as $value) { |
199
|
|
|
|
200
|
|
|
// Render the option. |
201
|
228 |
|
$prefix = (strlen($option) != 1) ? '--' : '-'; |
202
|
|
|
$options[] = $prefix . $option; |
203
|
228 |
|
|
204
|
228 |
|
// Render apend the value if the option isn't a flag. |
205
|
|
|
if ($value !== true) { |
206
|
|
|
$options[] = $value; |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
} |
210
|
|
|
return $options; |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* Sets a command line option. |
215
|
212 |
|
* |
216
|
|
|
* Option names are passed as-is to the command line, whereas the values are |
217
|
212 |
|
* escaped using \Symfony\Component\Process\ProcessUtils. |
218
|
208 |
|
* |
219
|
212 |
|
* @param string $option |
220
|
212 |
|
* The option name, e.g. "branch", "q". |
221
|
|
|
* @param string|true $value |
222
|
|
|
* The option's value, pass true if the options is a flag. |
223
|
|
|
* |
224
|
|
|
* @reutrn \GitWrapper\GitCommand |
225
|
|
|
*/ |
226
|
|
|
public function setOption($option, $value) |
227
|
|
|
{ |
228
|
|
|
$this->options[$option] = $value; |
229
|
|
|
return $this; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
12 |
|
* Sets multiple command line options. |
234
|
|
|
* |
235
|
12 |
|
* @param array $options |
236
|
|
|
* An associative array of command line options. |
237
|
|
|
* |
238
|
|
|
* @reutrn \GitWrapper\GitCommand |
239
|
|
|
*/ |
240
|
|
|
public function setOptions(array $options) |
241
|
|
|
{ |
242
|
|
|
foreach ($options as $option => $value) { |
243
|
|
|
$this->setOption($option, $value); |
244
|
|
|
} |
245
|
|
|
return $this; |
246
|
|
|
} |
247
|
|
|
|
248
|
4 |
|
/** |
249
|
|
|
* Sets a command line flag. |
250
|
4 |
|
* |
251
|
|
|
* @param string $flag |
|
|
|
|
252
|
|
|
* The flag name, e.g. "q", "a". |
253
|
|
|
* |
254
|
|
|
* @reutrn \GitWrapper\GitCommand |
255
|
|
|
* |
256
|
|
|
* @see \GitWrapper\GitCommand::setOption() |
257
|
|
|
*/ |
258
|
|
|
public function setFlag($option) |
259
|
|
|
{ |
260
|
|
|
return $this->setOption($option, true); |
|
|
|
|
261
|
4 |
|
} |
262
|
|
|
|
263
|
4 |
|
/** |
264
|
4 |
|
* Gets a command line option. |
265
|
|
|
* |
266
|
|
|
* @param string $option |
267
|
|
|
* The option name, e.g. "branch", "q". |
268
|
|
|
* @param mixed $default |
269
|
|
|
* Value that is returned if the option is not set, defaults to null. |
270
|
|
|
* |
271
|
|
|
* @return mixed |
272
|
|
|
*/ |
273
|
|
|
public function getOption($option, $default = null) |
274
|
|
|
{ |
275
|
212 |
|
return (isset($this->options[$option])) ? $this->options[$option] : $default; |
276
|
|
|
} |
277
|
212 |
|
|
278
|
212 |
|
/** |
279
|
|
|
* Unsets a command line option. |
280
|
|
|
* |
281
|
|
|
* @param string $option |
282
|
|
|
* The option name, e.g. "branch", "q". |
283
|
|
|
* |
284
|
|
|
* @return \GitWrapper\GitCommand |
285
|
|
|
*/ |
286
|
|
|
public function unsetOption($option) |
287
|
|
|
{ |
288
|
|
|
unset($this->options[$option]); |
289
|
252 |
|
return $this; |
290
|
|
|
} |
291
|
|
|
|
292
|
252 |
|
/** |
293
|
252 |
|
* Adds a command line argument passed to the Git command. |
294
|
252 |
|
* |
295
|
252 |
|
* @param string $arg |
296
|
252 |
|
* The argument, e.g. the repo URL, directory, etc. |
297
|
|
|
* |
298
|
|
|
* @return \GitWrapper\GitCommand |
299
|
|
|
*/ |
300
|
|
|
public function addArgument($arg) |
301
|
|
|
{ |
302
|
|
|
$this->args[] = $arg; |
303
|
|
|
return $this; |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* Renders the arguments and options for the Git command. |
308
|
|
|
* |
309
|
|
|
* @return string|array |
310
|
|
|
* |
311
|
|
|
* @see GitCommand::getCommand() |
312
|
|
|
* @see GitCommand::buildOptions() |
313
|
|
|
*/ |
314
|
|
|
public function getCommandLine() |
315
|
|
|
{ |
316
|
|
|
if ($this->executeRaw) { |
317
|
|
|
return $this->getCommand(); |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
$command = array_merge( |
321
|
|
|
[$this->getCommand()], |
322
|
|
|
$this->buildOptions(), |
323
|
|
|
$this->args |
324
|
|
|
); |
325
|
|
|
|
326
|
|
|
return array_filter($command); |
327
|
|
|
} |
328
|
|
|
} |
329
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.