|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* eduVPN - End-user friendly VPN. |
|
5
|
|
|
* |
|
6
|
|
|
* Copyright: 2016-2017, The Commons Conservancy eduVPN Programme |
|
7
|
|
|
* SPDX-License-Identifier: AGPL-3.0+ |
|
8
|
|
|
*/ |
|
9
|
|
|
|
|
10
|
|
|
namespace SURFnet\VPN\Common; |
|
11
|
|
|
|
|
12
|
|
|
use SURFnet\VPN\Common\Exception\CliException; |
|
13
|
|
|
|
|
14
|
|
|
class CliParser |
|
15
|
|
|
{ |
|
16
|
|
|
/** @var string */ |
|
17
|
|
|
private $programDescription; |
|
18
|
|
|
|
|
19
|
|
|
/** @var array */ |
|
20
|
|
|
private $optionList; |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* Create CliParser object. |
|
24
|
|
|
* |
|
25
|
|
|
* @param string $programDescription a short sentence indicating what the |
|
26
|
|
|
* program is about |
|
27
|
|
|
* @param array $optionList an array with all options, whether |
|
28
|
|
|
* they are required and whether they |
|
29
|
|
|
* take values |
|
30
|
|
|
* |
|
31
|
|
|
* Examples: |
|
32
|
|
|
* $optionList = [ |
|
33
|
|
|
* ['foo', 'Foo Description', false, false], // no value, not required |
|
34
|
|
|
* ['bar', 'Bar Description', false, true ], // no value, required |
|
35
|
|
|
* ['baz', 'Baz Description', true, false], // value, not required |
|
36
|
|
|
* ['xyz', 'Xyz Description', true, true ], // value, required |
|
37
|
|
|
* ]; |
|
38
|
|
|
* |
|
39
|
|
|
* The first field indicates the name of the parameter, the user will have |
|
40
|
|
|
* to provide --<OPT>, e.g. --foo, --bar, ... |
|
41
|
|
|
* |
|
42
|
|
|
* The second describes the parameter, that is used when the --help |
|
43
|
|
|
* parameter is used. |
|
44
|
|
|
* |
|
45
|
|
|
* The third indicates whether or not the parameter requires a value, e.g. |
|
46
|
|
|
* --baz abc where 'abc' is the value. |
|
47
|
|
|
* |
|
48
|
|
|
* The fourth indicates whether or not the parameter is required |
|
49
|
|
|
*/ |
|
50
|
|
|
public function __construct($programDescription, array $optionList) |
|
51
|
|
|
{ |
|
52
|
|
|
$this->programDescription = $programDescription; |
|
53
|
|
|
$this->optionList = $optionList; |
|
54
|
|
|
} |
|
55
|
|
|
|
|
56
|
|
|
public function help() |
|
57
|
|
|
{ |
|
58
|
|
|
$helpText = $this->programDescription.PHP_EOL; |
|
59
|
|
|
$helpText .= 'Options:'.PHP_EOL; |
|
60
|
|
|
foreach ($this->optionList as $k => $v) { |
|
61
|
|
|
if ($v[1]) { |
|
62
|
|
|
$helpText .= sprintf(" --%s %s\t\t%s", $k, $k, $v[0]); |
|
63
|
|
|
} else { |
|
64
|
|
|
$helpText .= sprintf(" --%s\t\t%s", $k, $v[0]); |
|
65
|
|
|
} |
|
66
|
|
|
if ($v[2]) { |
|
67
|
|
|
$helpText .= ' (REQUIRED)'; |
|
68
|
|
|
} |
|
69
|
|
|
$helpText .= PHP_EOL; |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
return $helpText; |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
public function parse(array $argv) |
|
76
|
|
|
{ |
|
77
|
|
|
$argc = count($argv); |
|
78
|
|
|
$optionValues = []; |
|
79
|
|
|
|
|
80
|
|
|
for ($i = 1; $i < $argc; ++$i) { |
|
81
|
|
|
if (0 === strpos($argv[$i], '--')) { |
|
82
|
|
|
// it is an option selector |
|
83
|
|
|
$p = substr($argv[$i], 2); // strip the dashes |
|
84
|
|
|
$pO = []; |
|
85
|
|
|
while ($i + 1 < $argc && false === strpos($argv[$i + 1], '--')) { |
|
86
|
|
|
$pO[] = $argv[++$i]; |
|
87
|
|
|
} |
|
88
|
|
|
if (1 === count($pO)) { |
|
89
|
|
|
$optionValues[$p] = $pO[0]; |
|
90
|
|
|
} else { |
|
91
|
|
|
$optionValues[$p] = $pO; |
|
92
|
|
|
} |
|
93
|
|
|
} |
|
94
|
|
|
} |
|
95
|
|
|
|
|
96
|
|
|
// --help is special |
|
97
|
|
|
if (array_key_exists('help', $optionValues)) { |
|
98
|
|
|
return new Config(['help' => true]); |
|
99
|
|
|
} |
|
100
|
|
|
|
|
101
|
|
|
// check if any of the required keys is missing |
|
102
|
|
|
foreach (array_keys($this->optionList) as $opt) { |
|
103
|
|
View Code Duplication |
if ($this->optionList[$opt][2]) { |
|
|
|
|
|
|
104
|
|
|
// required |
|
105
|
|
|
if (!array_key_exists($opt, $optionValues)) { |
|
106
|
|
|
throw new CliException(sprintf('missing required parameter "--%s"', $opt)); |
|
107
|
|
|
} |
|
108
|
|
|
} |
|
109
|
|
|
} |
|
110
|
|
|
|
|
111
|
|
|
// check if any of the options that require a value has no value |
|
112
|
|
|
foreach (array_keys($this->optionList) as $opt) { |
|
113
|
|
|
if ($this->optionList[$opt][1]) { |
|
114
|
|
|
// check if it is actually there |
|
115
|
|
View Code Duplication |
if (array_key_exists($opt, $optionValues)) { |
|
|
|
|
|
|
116
|
|
|
// must have value |
|
117
|
|
|
if (0 === count($optionValues[$opt])) { |
|
118
|
|
|
throw new CliException(sprintf('missing required parameter value for option "--%s"', $opt)); |
|
119
|
|
|
} |
|
120
|
|
|
} |
|
121
|
|
|
} |
|
122
|
|
|
} |
|
123
|
|
|
|
|
124
|
|
|
return new Config($optionValues); |
|
125
|
|
|
} |
|
126
|
|
|
} |
|
127
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.