annotate vendor/squizlabs/php_codesniffer/scripts/ValidatePEAR/ValidatePEARPackageXML.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@18 1 <?php
Chris@18 2 /**
Chris@18 3 * Validate the PHP_CodeSniffer PEAR package.xml file.
Chris@18 4 *
Chris@18 5 * PHP version 5
Chris@18 6 *
Chris@18 7 * @category PHP
Chris@18 8 * @package PHP_CodeSniffer
Chris@18 9 * @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
Chris@18 10 * @copyright 2019 Juliette Reinders Folmer. All rights reserved.
Chris@18 11 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
Chris@18 12 */
Chris@18 13
Chris@18 14 /**
Chris@18 15 * Validate the PHP_CodeSniffer PEAR package.xml file.
Chris@18 16 */
Chris@18 17 class ValidatePEARPackageXML
Chris@18 18 {
Chris@18 19
Chris@18 20 /**
Chris@18 21 * The root directory of the project.
Chris@18 22 *
Chris@18 23 * @var string
Chris@18 24 */
Chris@18 25 protected $projectRoot = '';
Chris@18 26
Chris@18 27 /**
Chris@18 28 * The contents of the package.xml file.
Chris@18 29 *
Chris@18 30 * @var \SimpleXMLElement
Chris@18 31 */
Chris@18 32 protected $packageXML;
Chris@18 33
Chris@18 34 /**
Chris@18 35 * List of all files in the repo.
Chris@18 36 *
Chris@18 37 * @var array
Chris@18 38 */
Chris@18 39 protected $allFiles = [];
Chris@18 40
Chris@18 41 /**
Chris@18 42 * Valid file roles.
Chris@18 43 *
Chris@18 44 * @var array
Chris@18 45 *
Chris@18 46 * @link https://pear.php.net/manual/en/developers.packagedef.intro.php#developers.packagedef.roles
Chris@18 47 */
Chris@18 48 private $validRoles = [
Chris@18 49 'data' => true,
Chris@18 50 'doc' => true,
Chris@18 51 'ext' => true,
Chris@18 52 'extsrc' => true,
Chris@18 53 'php' => true,
Chris@18 54 'script' => true,
Chris@18 55 'src' => true,
Chris@18 56 'test' => true,
Chris@18 57 ];
Chris@18 58
Chris@18 59 /**
Chris@18 60 * Files encountered in the package.xml <contents> tag.
Chris@18 61 *
Chris@18 62 * @var array
Chris@18 63 */
Chris@18 64 private $listedContents = [];
Chris@18 65
Chris@18 66
Chris@18 67 /**
Chris@18 68 * Constructor.
Chris@18 69 */
Chris@18 70 public function __construct()
Chris@18 71 {
Chris@18 72 $this->projectRoot = dirname(dirname(__DIR__)).'/';
Chris@18 73 $this->packageXML = simplexml_load_file($this->projectRoot.'package.xml');
Chris@18 74
Chris@18 75 $allFiles = (new FileList($this->projectRoot, $this->projectRoot))->getList();
Chris@18 76 $this->allFiles = array_flip($allFiles);
Chris@18 77
Chris@18 78 }//end __construct()
Chris@18 79
Chris@18 80
Chris@18 81 /**
Chris@18 82 * Validate the file listings in the package.xml file.
Chris@18 83 *
Chris@18 84 * @return void
Chris@18 85 */
Chris@18 86 public function validate()
Chris@18 87 {
Chris@18 88 $exitCode = 0;
Chris@18 89 if ($this->checkContents() !== true) {
Chris@18 90 $exitCode = 1;
Chris@18 91 }
Chris@18 92
Chris@18 93 if ($this->checkPHPRelease() !== true) {
Chris@18 94 $exitCode = 1;
Chris@18 95 }
Chris@18 96
Chris@18 97 exit($exitCode);
Chris@18 98
Chris@18 99 }//end validate()
Chris@18 100
Chris@18 101
Chris@18 102 /**
Chris@18 103 * Validate the file listings in the <contents> tag.
Chris@18 104 *
Chris@18 105 * @return bool
Chris@18 106 */
Chris@18 107 protected function checkContents()
Chris@18 108 {
Chris@18 109 echo PHP_EOL.'Checking Contents tag'.PHP_EOL;
Chris@18 110 echo '====================='.PHP_EOL;
Chris@18 111
Chris@18 112 $valid = true;
Chris@18 113
Chris@18 114 /*
Chris@18 115 * - Check that every file that is mentioned in the `<content>` tag exists in the repo.
Chris@18 116 * - Check that the "role" value is valid.
Chris@18 117 * - Check that the "baseinstalldir" value is valid.
Chris@18 118 */
Chris@18 119
Chris@18 120 $valid = $this->walkDirTag($this->packageXML->contents);
Chris@18 121 if ($valid === true) {
Chris@18 122 echo "Existing listings in the Contents tag are valid.".PHP_EOL;
Chris@18 123 }
Chris@18 124
Chris@18 125 /*
Chris@18 126 * Verify that all files in the `src` and the `tests` directories are listed in the `<contents>` tag.
Chris@18 127 */
Chris@18 128
Chris@18 129 $srcFiles = (new FileList(
Chris@18 130 $this->projectRoot.'src/',
Chris@18 131 $this->projectRoot,
Chris@18 132 '`\.(css|fixed|inc|js|php|xml)$`Di'
Chris@18 133 ))->getList();
Chris@18 134 $testsFiles = (new FileList(
Chris@18 135 $this->projectRoot.'tests/',
Chris@18 136 $this->projectRoot,
Chris@18 137 '`\.(css|inc|js|php|xml)$`Di'
Chris@18 138 ))->getList();
Chris@18 139 $files = array_merge($srcFiles, $testsFiles);
Chris@18 140
Chris@18 141 foreach ($files as $file) {
Chris@18 142 if (isset($this->listedContents[$file]) === true) {
Chris@18 143 continue;
Chris@18 144 }
Chris@18 145
Chris@18 146 echo "- File '{$file}' is missing from Contents tag.".PHP_EOL;
Chris@18 147 $valid = false;
Chris@18 148 }
Chris@18 149
Chris@18 150 if ($valid === true) {
Chris@18 151 echo "No missing files in the Contents tag.".PHP_EOL;
Chris@18 152 }
Chris@18 153
Chris@18 154 return $valid;
Chris@18 155
Chris@18 156 }//end checkContents()
Chris@18 157
Chris@18 158
Chris@18 159 /**
Chris@18 160 * Validate all child tags within a <dir> tag.
Chris@18 161 *
Chris@18 162 * @param \SimpleXMLElement $tag The current XML tag to examine.
Chris@18 163 * @param string $currentDirectory The complete relative path to the
Chris@18 164 * directory being examined.
Chris@18 165 *
Chris@18 166 * @return bool
Chris@18 167 */
Chris@18 168 protected function walkDirTag($tag, $currentDirectory='')
Chris@18 169 {
Chris@18 170 $valid = true;
Chris@18 171 $name = (string) $tag['name'];
Chris@18 172 if ($name !== '/' && empty($name) === false) {
Chris@18 173 $currentDirectory .= $name.'/';
Chris@18 174 }
Chris@18 175
Chris@18 176 $children = $tag->children();
Chris@18 177 foreach ($children as $key => $value) {
Chris@18 178 if ($key === 'dir') {
Chris@18 179 if ($this->walkDirTag($value, $currentDirectory) === false) {
Chris@18 180 $valid = false;
Chris@18 181 }
Chris@18 182 }
Chris@18 183
Chris@18 184 if ($key === 'file') {
Chris@18 185 if ($this->checkFileTag($value, $currentDirectory) === false) {
Chris@18 186 $valid = false;
Chris@18 187 }
Chris@18 188 }
Chris@18 189 }
Chris@18 190
Chris@18 191 return $valid;
Chris@18 192
Chris@18 193 }//end walkDirTag()
Chris@18 194
Chris@18 195
Chris@18 196 /**
Chris@18 197 * Validate the information within a <file> tag.
Chris@18 198 *
Chris@18 199 * @param \SimpleXMLElement $tag The current XML tag to examine.
Chris@18 200 * @param string $currentDirectory The complete relative path to the
Chris@18 201 * directory being examined.
Chris@18 202 *
Chris@18 203 * @return bool
Chris@18 204 */
Chris@18 205 protected function checkFileTag($tag, $currentDirectory='')
Chris@18 206 {
Chris@18 207 $valid = true;
Chris@18 208 $attributes = $tag->attributes();
Chris@18 209 $baseinstalldir = (string) $attributes['baseinstalldir'];
Chris@18 210 $name = $currentDirectory.(string) $attributes['name'];
Chris@18 211 $role = (string) $attributes['role'];
Chris@18 212
Chris@18 213 $this->listedContents[$name] = true;
Chris@18 214
Chris@18 215 if (empty($name) === true) {
Chris@18 216 echo "- Name attribute missing.".PHP_EOL;
Chris@18 217 $valid = false;
Chris@18 218 } else {
Chris@18 219 if (isset($this->allFiles[$name]) === false) {
Chris@18 220 echo "- File '{$name}' does not exist.".PHP_EOL;
Chris@18 221 $valid = false;
Chris@18 222 }
Chris@18 223
Chris@18 224 if (empty($role) === true) {
Chris@18 225 echo "- Role attribute missing for file '{$name}'.".PHP_EOL;
Chris@18 226 $valid = false;
Chris@18 227 } else {
Chris@18 228 if (isset($this->validRoles[$role]) === false) {
Chris@18 229 echo "- Role for file '{$name}' is invalid.".PHP_EOL;
Chris@18 230 $valid = false;
Chris@18 231 } else {
Chris@18 232 // Limited validation of the "role" tags.
Chris@18 233 if (strpos($name, 'Test.') !== false && $role !== 'test') {
Chris@18 234 echo "- Test files should have the role 'test'. Found: '$role' for file '{$name}'.".PHP_EOL;
Chris@18 235 $valid = false;
Chris@18 236 } else if ((strpos($name, 'Standard.xml') !== false || strpos($name, 'Sniff.php') !== false)
Chris@18 237 && $role !== 'php'
Chris@18 238 ) {
Chris@18 239 echo "- Sniff files, including sniff documentation files should have the role 'php'. Found: '$role' for file '{$name}'.".PHP_EOL;
Chris@18 240 $valid = false;
Chris@18 241 }
Chris@18 242 }
Chris@18 243
Chris@18 244 if (empty($baseinstalldir) === true) {
Chris@18 245 if ($role !== 'script' && strpos($name, 'tests/') !== 0) {
Chris@18 246 echo "- Baseinstalldir attribute missing for file '{$name}'.".PHP_EOL;
Chris@18 247 $valid = false;
Chris@18 248 }
Chris@18 249 } else {
Chris@18 250 if ($role === 'script' || strpos($name, 'tests/') === 0) {
Chris@18 251 echo "- Baseinstalldir for file '{$name}' should be empty.".PHP_EOL;
Chris@18 252 $valid = false;
Chris@18 253 }
Chris@18 254
Chris@18 255 if ($role !== 'script' && $baseinstalldir !== 'PHP/CodeSniffer') {
Chris@18 256 echo "- Baseinstalldir for file '{$name}' is invalid.".PHP_EOL;
Chris@18 257 $valid = false;
Chris@18 258 }
Chris@18 259 }
Chris@18 260 }//end if
Chris@18 261 }//end if
Chris@18 262
Chris@18 263 return $valid;
Chris@18 264
Chris@18 265 }//end checkFileTag()
Chris@18 266
Chris@18 267
Chris@18 268 /**
Chris@18 269 * Validate the file listings in the <phprelease> tags.
Chris@18 270 *
Chris@18 271 * @return bool True if the info in the "phprelease" tags is valid. False otherwise.
Chris@18 272 */
Chris@18 273 protected function checkPHPRelease()
Chris@18 274 {
Chris@18 275 echo PHP_EOL.'Checking PHPRelease tags'.PHP_EOL;
Chris@18 276 echo '========================'.PHP_EOL;
Chris@18 277
Chris@18 278 $valid = true;
Chris@18 279 $listedFiles = [];
Chris@18 280 $releaseTags = 1;
Chris@18 281
Chris@18 282 /*
Chris@18 283 * - Check that every file that is mentioned in the `<phprelease>` tags exists in the repo.
Chris@18 284 * - Check that the "as" value is valid.
Chris@18 285 */
Chris@18 286
Chris@18 287 foreach ($this->packageXML->phprelease as $release) {
Chris@18 288 foreach ($release->filelist->install as $install) {
Chris@18 289 $attributes = $install->attributes();
Chris@18 290 $name = (string) $attributes['name'];
Chris@18 291 $as = (string) $attributes['as'];
Chris@18 292
Chris@18 293 $listedFiles[$releaseTags][$name] = $as;
Chris@18 294
Chris@18 295 if (empty($as) === true || empty($name) === true) {
Chris@18 296 continue;
Chris@18 297 }
Chris@18 298
Chris@18 299 if (isset($this->allFiles[$name]) === false) {
Chris@18 300 echo "- File '{$name}' does not exist.".PHP_EOL;
Chris@18 301 $valid = false;
Chris@18 302 }
Chris@18 303
Chris@18 304 // Rest of the checks only apply to the test files.
Chris@18 305 if (strpos($name, 'tests/') !== 0) {
Chris@18 306 continue;
Chris@18 307 }
Chris@18 308
Chris@18 309 // Check validity of the tags for files in the tests root directory.
Chris@18 310 if (preg_match('`^tests/([^/]+\.php)$`', $name, $matches) === 1
Chris@18 311 && ($as === $name || $as === $matches[1])
Chris@18 312 ) {
Chris@18 313 continue;
Chris@18 314 }
Chris@18 315
Chris@18 316 // Check validity of the tags for files in the tests root subdirectories.
Chris@18 317 if (preg_match('`^tests/.+\.(php|inc|js|css|xml)$`', $name) === 1
Chris@18 318 && $as === str_replace('tests/', 'CodeSniffer/', $name)
Chris@18 319 ) {
Chris@18 320 continue;
Chris@18 321 }
Chris@18 322
Chris@18 323 echo "- Invalid 'as' attribute '{$as}' for test file '{$name}'.".PHP_EOL;
Chris@18 324 $valid = false;
Chris@18 325 }//end foreach
Chris@18 326
Chris@18 327 ++$releaseTags;
Chris@18 328 }//end foreach
Chris@18 329
Chris@18 330 if ($valid === true) {
Chris@18 331 echo "Existing PHPRelease tags are valid.".PHP_EOL;
Chris@18 332 }
Chris@18 333
Chris@18 334 /*
Chris@18 335 * Verify that all files in the `tests` directory are listed in both `<phprelease>` tags.
Chris@18 336 */
Chris@18 337
Chris@18 338 $testFiles = (new FileList($this->projectRoot.'tests/', $this->projectRoot, '`\.(inc|php|js|css|xml)$`Di'))->getList();
Chris@18 339
Chris@18 340 foreach ($testFiles as $file) {
Chris@18 341 foreach ($listedFiles as $key => $listed) {
Chris@18 342 if (isset($listed[$file]) === true) {
Chris@18 343 continue;
Chris@18 344 }
Chris@18 345
Chris@18 346 echo "- File '{$file}' is missing from PHPRelease tag [{$key}] .".PHP_EOL;
Chris@18 347 $valid = false;
Chris@18 348 }
Chris@18 349 }
Chris@18 350
Chris@18 351 if ($valid === true) {
Chris@18 352 echo "No missing PHPRelease tags.".PHP_EOL;
Chris@18 353 }
Chris@18 354
Chris@18 355 return $valid;
Chris@18 356
Chris@18 357 }//end checkPHPRelease()
Chris@18 358
Chris@18 359
Chris@18 360 }//end class