yaml-lint.php ➔ _msg()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 0
loc 25
rs 9.52
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * yaml-lint, a compact command line utility for checking YAML file syntax.
5
 *
6
 * Uses the parsing facility of the Symfony Yaml Component.
7
 *
8
 * For full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
use J13k\YamlLint\UsageException;
13
use Symfony\Component\Yaml\Exception\ParseException;
14
use Symfony\Component\Yaml\Yaml;
15
16
define('APP_NAME', 'yaml-lint');
17
define('APP_VERSION', '1.1.4');
18
19
define('ANSI_BLD', 01);
20
define('ANSI_UDL', 04);
21
define('ANSI_RED', 31);
22
define('ANSI_GRN', 32);
23
24
define('EXIT_NORMAL', 0);
25
define('EXIT_ERROR', 1);
26
27
define('YAML_PARSE_PARAM_NAME_EXCEPTION_ON_INVALID_TYPE', 'exceptionOnInvalidType');
28
define('YAML_PARSE_PARAM_NAME_FLAGS', 'flags');
29
30
// Init app name and args
31
$appStr = APP_NAME . ' ' . APP_VERSION;
32
$argQuiet = false;
33
$argPaths = [];
34
35
try {
36
37
    // Composer bootstrap
38
    $pathToTry = null;
39
    foreach (array('/../../../', '/../vendor/') as $pathToTry) {
40
        if (is_readable(__DIR__ . $pathToTry . 'autoload.php')) {
41
            /** @noinspection PhpIncludeInspection */
42
            require __DIR__ . $pathToTry . 'autoload.php';
43
            break;
44
        }
45
    }
46
    if (!class_exists('\Composer\Autoload\ClassLoader')) {
47
        throw new \Exception(_msg('composer'));
48
    }
49
50
    // Extract YAML component metadata
51
    $componentsManifest = __DIR__ . $pathToTry . 'composer/installed.json';
52
    $components = json_decode(file_get_contents($componentsManifest), true);
53
    foreach ($components as $component) {
54
        if (isset($component['name']) && $component['name'] == 'symfony/yaml') {
55
            $appStr .= ', symfony/yaml ' . $component['version'];
56
            break;
57
        }
58
    }
59
60
    // Process and check args
61
    $argv = $_SERVER['argv'];
62
    array_shift($argv);
63
    foreach ($argv as $arg) {
64
        switch ($arg) {
65
            case '-h':
66
            case '--help':
67
                throw new UsageException();
68
            case '-V':
69
            case '--version':
70
                fwrite(STDOUT, $appStr . "\n");
71
                exit(EXIT_NORMAL);
72
            case '-q':
73
            case '--quiet':
74
                $argQuiet = true;
75
                break;
76
            default:
77
                $argPaths[] = $arg;
78
        }
79
    }
80
81
    // Currently only one input file or STDIN supported
82
    if (count($argPaths) < 1) {
83
        throw new UsageException('no input specified', EXIT_ERROR);
84
    }
85
86
	$lintPath = function($path) use ($argQuiet, $appStr) {
87
		$content = file_get_contents($path);
88
		if (strlen($content) < 1) {
89
			throw new ParseException('Input has no content');
90
		}
91
92
		// Do the thing (now accommodates changes to the Yaml::parse method introduced in v3)
93
		$yamlParseMethod = new ReflectionMethod('\Symfony\Component\Yaml\Yaml', 'parse');
94
		$yamlParseParams = $yamlParseMethod->getParameters();
95
		switch ($yamlParseParams[1]->name) {
96
			case YAML_PARSE_PARAM_NAME_EXCEPTION_ON_INVALID_TYPE:
97
				// Maintains original behaviour in ^2
98
				Yaml::parse($content, true);
99
				break;
100
			case YAML_PARSE_PARAM_NAME_FLAGS:
101
				// Implements same behaviour in ^3 and ^4
102
				Yaml::parse($content, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE);
103
				break;
104
			default:
105
				// Param name unknown, fall back to the defaults
106
				Yaml::parse($content);
107
				break;
108
		}
109
110
		// Output app string and file path if allowed
111
		if (!$argQuiet) {
112
			fwrite(STDOUT, trim($appStr . ': parsing ' . $path));
113
			fwrite(STDOUT, sprintf(" [ %s ]\n", _ansify('OK', ANSI_GRN)));
114
		}
115
	};
116
117
    if ($argPaths[0] === '-') {
118
        $path = 'php://stdin';
119
120
		$lintPath($path);
121
    } else {
122
        // Check input file(s)
123
		foreach($argPaths as $argPath) {
124
			if (!file_exists($argPath)) {
125
				throw new ParseException(sprintf('File %s does not exist', $argPath));
126
			}
127
			if (!is_readable($argPath)) {
128
				throw new ParseException(sprintf('File %s is not readable', $argPath));
129
			}
130
131
			$lintPath($argPath);
132
		}
133
    }
134
135
    exit(EXIT_NORMAL);
136
137
} catch (UsageException $e) {
138
139
    // Usage message
140
    $outputStream = $e->getCode() > EXIT_NORMAL ? STDERR : STDOUT;
141
    fwrite($outputStream, $appStr);
142
    if ($e->getMessage()) {
143
        fwrite(
144
            $outputStream,
145
            sprintf(": %s", _ansify($e->getMessage(), ANSI_RED))
146
        );
147
    }
148
    fwrite($outputStream, sprintf("\n\n%s\n\n", _msg('usage')));
149
    exit($e->getCode());
150
151
} catch (ParseException $e) {
152
153
    // Syntax exception
154
    fwrite(STDERR, trim($appStr . ': parsing ' . $argPath));
155
    fwrite(STDERR, sprintf(" [ %s ]\n", _ansify('ERROR', ANSI_RED)));
156
    fwrite(STDERR, "\n" . $e->getMessage() . "\n\n");
157
    exit(EXIT_ERROR);
158
159
} catch (\Exception $e) {
160
161
    // The rest
162
    fwrite(STDERR, $appStr);
163
    fwrite(STDERR, sprintf(": %s\n", _ansify($e->getMessage(), ANSI_RED)));
164
    exit(EXIT_ERROR);
165
166
}
167
168
/**
169
 * Helper to wrap input string in ANSI colour code
170
 *
171
 * @param string $str
172
 * @param int    $colourCode
173
 *
174
 * @return string
175
 */
176
function _ansify($str, $colourCode)
177
{
178
    $colourCode = max(0, $colourCode);
179
    $colourCode = min(255, $colourCode);
180
181
    return sprintf("\e[%dm%s\e[0m", $colourCode, $str);
182
}
183
184
/**
185
 * Wrapper for heredoc messages
186
 *
187
 * @param string $str
188
 *
189
 * @return string
190
 */
191
function _msg($str)
192
{
193
    switch ($str) {
194
        case 'composer':
195
            return <<<EOD
196
Composer dependencies cannot be loaded; install Composer to remedy:
197
https://getcomposer.org/download/
198
EOD;
199
            break;
200
        case 'usage':
201
            return <<<EOD
202
usage: yaml-lint [options] [input source]
203
204
  input source    Path to file(s), or "-" to read from standard input
205
206
  -q, --quiet     Restrict output to syntax errors
207
  -h, --help      Display this help
208
  -V, --version   Display application version
209
EOD;
210
            break;
211
        default:
212
    }
213
214
    return '';
215
}
216