annotate vendor/squizlabs/php_codesniffer/scripts/ValidatePEAR/ValidatePEARPackageXML.php @ 5:12f9dff5fda9 tip

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