Chris@17: Chris@17: * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) Chris@17: * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence Chris@17: */ Chris@17: Chris@17: namespace PHP_CodeSniffer\Util; Chris@17: Chris@17: use PHP_CodeSniffer\Config; Chris@17: Chris@17: class Standards Chris@17: { Chris@17: Chris@17: Chris@17: /** Chris@17: * Get a list paths where standards are installed. Chris@17: * Chris@17: * @return array Chris@17: */ Chris@17: public static function getInstalledStandardPaths() Chris@17: { Chris@17: $ds = DIRECTORY_SEPARATOR; Chris@17: Chris@17: $installedPaths = [dirname(dirname(__DIR__)).$ds.'src'.$ds.'Standards']; Chris@17: $configPaths = Config::getConfigData('installed_paths'); Chris@17: if ($configPaths !== null) { Chris@17: $installedPaths = array_merge($installedPaths, explode(',', $configPaths)); Chris@17: } Chris@17: Chris@17: $resolvedInstalledPaths = []; Chris@17: foreach ($installedPaths as $installedPath) { Chris@17: if (substr($installedPath, 0, 1) === '.') { Chris@17: $installedPath = Common::realPath(__DIR__.$ds.'..'.$ds.'..'.$ds.$installedPath); Chris@17: } Chris@17: Chris@17: $resolvedInstalledPaths[] = $installedPath; Chris@17: } Chris@17: Chris@17: return $resolvedInstalledPaths; Chris@17: Chris@17: }//end getInstalledStandardPaths() Chris@17: Chris@17: Chris@17: /** Chris@17: * Get the details of all coding standards installed. Chris@17: * Chris@17: * Coding standards are directories located in the Chris@17: * CodeSniffer/Standards directory. Valid coding standards Chris@17: * include a Sniffs subdirectory. Chris@17: * Chris@17: * The details returned for each standard are: Chris@17: * - path: the path to the coding standard's main directory Chris@17: * - name: the name of the coding standard, as sourced from the ruleset.xml file Chris@17: * - namespace: the namespace used by the coding standard, as sourced from the ruleset.xml file Chris@17: * Chris@17: * If you only need the paths to the installed standards, Chris@17: * use getInstalledStandardPaths() instead as it performs less work to Chris@17: * retrieve coding standard names. Chris@17: * Chris@17: * @param boolean $includeGeneric If true, the special "Generic" Chris@17: * coding standard will be included Chris@17: * if installed. Chris@17: * @param string $standardsDir A specific directory to look for standards Chris@17: * in. If not specified, PHP_CodeSniffer will Chris@17: * look in its default locations. Chris@17: * Chris@17: * @return array Chris@17: * @see getInstalledStandardPaths() Chris@17: */ Chris@17: public static function getInstalledStandardDetails( Chris@17: $includeGeneric=false, Chris@17: $standardsDir='' Chris@17: ) { Chris@17: $rulesets = []; Chris@17: Chris@17: if ($standardsDir === '') { Chris@17: $installedPaths = self::getInstalledStandardPaths(); Chris@17: } else { Chris@17: $installedPaths = [$standardsDir]; Chris@17: } Chris@17: Chris@17: foreach ($installedPaths as $standardsDir) { Chris@17: // Check if the installed dir is actually a standard itself. Chris@17: $csFile = $standardsDir.'/ruleset.xml'; Chris@17: if (is_file($csFile) === true) { Chris@17: $rulesets[] = $csFile; Chris@17: continue; Chris@17: } Chris@17: Chris@17: if (is_dir($standardsDir) === false) { Chris@17: continue; Chris@17: } Chris@17: Chris@17: $di = new \DirectoryIterator($standardsDir); Chris@17: foreach ($di as $file) { Chris@17: if ($file->isDir() === true && $file->isDot() === false) { Chris@17: $filename = $file->getFilename(); Chris@17: Chris@17: // Ignore the special "Generic" standard. Chris@17: if ($includeGeneric === false && $filename === 'Generic') { Chris@17: continue; Chris@17: } Chris@17: Chris@17: // Valid coding standard dirs include a ruleset. Chris@17: $csFile = $file->getPathname().'/ruleset.xml'; Chris@17: if (is_file($csFile) === true) { Chris@17: $rulesets[] = $csFile; Chris@17: } Chris@17: } Chris@17: } Chris@17: }//end foreach Chris@17: Chris@17: $installedStandards = []; Chris@17: Chris@17: foreach ($rulesets as $rulesetPath) { Chris@18: $ruleset = @simplexml_load_string(file_get_contents($rulesetPath)); Chris@17: if ($ruleset === false) { Chris@17: continue; Chris@17: } Chris@17: Chris@17: $standardName = (string) $ruleset['name']; Chris@17: $dirname = basename(dirname($rulesetPath)); Chris@17: Chris@17: if (isset($ruleset['namespace']) === true) { Chris@17: $namespace = (string) $ruleset['namespace']; Chris@17: } else { Chris@17: $namespace = $dirname; Chris@17: } Chris@17: Chris@17: $installedStandards[$dirname] = [ Chris@17: 'path' => dirname($rulesetPath), Chris@17: 'name' => $standardName, Chris@17: 'namespace' => $namespace, Chris@17: ]; Chris@17: }//end foreach Chris@17: Chris@17: return $installedStandards; Chris@17: Chris@17: }//end getInstalledStandardDetails() Chris@17: Chris@17: Chris@17: /** Chris@17: * Get a list of all coding standards installed. Chris@17: * Chris@17: * Coding standards are directories located in the Chris@17: * CodeSniffer/Standards directory. Valid coding standards Chris@17: * include a Sniffs subdirectory. Chris@17: * Chris@17: * @param boolean $includeGeneric If true, the special "Generic" Chris@17: * coding standard will be included Chris@17: * if installed. Chris@17: * @param string $standardsDir A specific directory to look for standards Chris@17: * in. If not specified, PHP_CodeSniffer will Chris@17: * look in its default locations. Chris@17: * Chris@17: * @return array Chris@17: * @see isInstalledStandard() Chris@17: */ Chris@17: public static function getInstalledStandards( Chris@17: $includeGeneric=false, Chris@17: $standardsDir='' Chris@17: ) { Chris@17: $installedStandards = []; Chris@17: Chris@17: if ($standardsDir === '') { Chris@17: $installedPaths = self::getInstalledStandardPaths(); Chris@17: } else { Chris@17: $installedPaths = [$standardsDir]; Chris@17: } Chris@17: Chris@17: foreach ($installedPaths as $standardsDir) { Chris@17: // Check if the installed dir is actually a standard itself. Chris@17: $csFile = $standardsDir.'/ruleset.xml'; Chris@17: if (is_file($csFile) === true) { Chris@17: $installedStandards[] = basename($standardsDir); Chris@17: continue; Chris@17: } Chris@17: Chris@17: if (is_dir($standardsDir) === false) { Chris@17: // Doesn't exist. Chris@17: continue; Chris@17: } Chris@17: Chris@17: $di = new \DirectoryIterator($standardsDir); Chris@17: foreach ($di as $file) { Chris@17: if ($file->isDir() === true && $file->isDot() === false) { Chris@17: $filename = $file->getFilename(); Chris@17: Chris@17: // Ignore the special "Generic" standard. Chris@17: if ($includeGeneric === false && $filename === 'Generic') { Chris@17: continue; Chris@17: } Chris@17: Chris@17: // Valid coding standard dirs include a ruleset. Chris@17: $csFile = $file->getPathname().'/ruleset.xml'; Chris@17: if (is_file($csFile) === true) { Chris@17: $installedStandards[] = $filename; Chris@17: } Chris@17: } Chris@17: } Chris@17: }//end foreach Chris@17: Chris@17: return $installedStandards; Chris@17: Chris@17: }//end getInstalledStandards() Chris@17: Chris@17: Chris@17: /** Chris@17: * Determine if a standard is installed. Chris@17: * Chris@17: * Coding standards are directories located in the Chris@17: * CodeSniffer/Standards directory. Valid coding standards Chris@17: * include a ruleset.xml file. Chris@17: * Chris@17: * @param string $standard The name of the coding standard. Chris@17: * Chris@17: * @return boolean Chris@17: * @see getInstalledStandards() Chris@17: */ Chris@17: public static function isInstalledStandard($standard) Chris@17: { Chris@17: $path = self::getInstalledStandardPath($standard); Chris@17: if ($path !== null && strpos($path, 'ruleset.xml') !== false) { Chris@17: return true; Chris@17: } else { Chris@17: // This could be a custom standard, installed outside our Chris@17: // standards directory. Chris@17: $standard = Common::realPath($standard); Chris@17: Chris@17: // Might be an actual ruleset file itUtil. Chris@17: // If it has an XML extension, let's at least try it. Chris@17: if (is_file($standard) === true Chris@17: && (substr(strtolower($standard), -4) === '.xml' Chris@17: || substr(strtolower($standard), -9) === '.xml.dist') Chris@17: ) { Chris@17: return true; Chris@17: } Chris@17: Chris@17: // If it is a directory with a ruleset.xml file in it, Chris@17: // it is a standard. Chris@17: $ruleset = rtrim($standard, ' /\\').DIRECTORY_SEPARATOR.'ruleset.xml'; Chris@17: if (is_file($ruleset) === true) { Chris@17: return true; Chris@17: } Chris@17: }//end if Chris@17: Chris@17: return false; Chris@17: Chris@17: }//end isInstalledStandard() Chris@17: Chris@17: Chris@17: /** Chris@17: * Return the path of an installed coding standard. Chris@17: * Chris@17: * Coding standards are directories located in the Chris@17: * CodeSniffer/Standards directory. Valid coding standards Chris@17: * include a ruleset.xml file. Chris@17: * Chris@17: * @param string $standard The name of the coding standard. Chris@17: * Chris@17: * @return string|null Chris@17: */ Chris@17: public static function getInstalledStandardPath($standard) Chris@17: { Chris@17: if (strpos($standard, '.') !== false) { Chris@17: return null; Chris@17: } Chris@17: Chris@17: $installedPaths = self::getInstalledStandardPaths(); Chris@17: foreach ($installedPaths as $installedPath) { Chris@17: $standardPath = $installedPath.DIRECTORY_SEPARATOR.$standard; Chris@17: if (file_exists($standardPath) === false) { Chris@17: if (basename($installedPath) !== $standard) { Chris@17: continue; Chris@17: } Chris@17: Chris@17: $standardPath = $installedPath; Chris@17: } Chris@17: Chris@17: $path = Common::realpath($standardPath.DIRECTORY_SEPARATOR.'ruleset.xml'); Chris@17: Chris@17: if (is_file($path) === true) { Chris@17: return $path; Chris@17: } else if (Common::isPharFile($standardPath) === true) { Chris@17: $path = Common::realpath($standardPath); Chris@17: if ($path !== false) { Chris@17: return $path; Chris@17: } Chris@17: } Chris@17: }//end foreach Chris@17: Chris@17: return null; Chris@17: Chris@17: }//end getInstalledStandardPath() Chris@17: Chris@17: Chris@17: /** Chris@17: * Prints out a list of installed coding standards. Chris@17: * Chris@17: * @return void Chris@17: */ Chris@17: public static function printInstalledStandards() Chris@17: { Chris@17: $installedStandards = self::getInstalledStandards(); Chris@17: $numStandards = count($installedStandards); Chris@17: Chris@17: if ($numStandards === 0) { Chris@17: echo 'No coding standards are installed.'.PHP_EOL; Chris@17: } else { Chris@17: $lastStandard = array_pop($installedStandards); Chris@17: if ($numStandards === 1) { Chris@17: echo "The only coding standard installed is $lastStandard".PHP_EOL; Chris@17: } else { Chris@17: $standardList = implode(', ', $installedStandards); Chris@17: $standardList .= ' and '.$lastStandard; Chris@17: echo 'The installed coding standards are '.$standardList.PHP_EOL; Chris@17: } Chris@17: } Chris@17: Chris@17: }//end printInstalledStandards() Chris@17: Chris@17: Chris@17: }//end class