diff --git a/src/lint/engine/ArcanistConfigurationDrivenLintEngine.php b/src/lint/engine/ArcanistConfigurationDrivenLintEngine.php --- a/src/lint/engine/ArcanistConfigurationDrivenLintEngine.php +++ b/src/lint/engine/ArcanistConfigurationDrivenLintEngine.php @@ -5,37 +5,14 @@ private $debugMode; public function buildLinters() { - $working_copy = $this->getWorkingCopy(); - $config_path = $working_copy->getProjectPath('.arclint'); - - if (!Filesystem::pathExists($config_path)) { - throw new Exception( - "Unable to find '.arclint' file to configure linters. Create a ". - "'.arclint' file in the root directory of the working copy."); - } - - $data = Filesystem::readFile($config_path); - $config = json_decode($data, true); - if (!is_array($config)) { - throw new Exception( - "Expected '.arclint' file to be a valid JSON file, but failed to ". - "decode it: {$config_path}"); - } - + $config = $this->parseConfiguration(); $linters = $this->loadAvailableLinters(); - - PhutilTypeSpec::checkMap( - $config, - array( - 'linters' => 'map<string, map<string, wild>>', - 'debug' => 'optional bool', - )); - - $this->debugMode = idx($config, 'debug', false); + $this->debugMode = true; $built_linters = array(); $all_paths = $this->getPaths(); - foreach ($config['linters'] as $name => $spec) { + + foreach ($config as $name => $spec) { $type = idx($spec, 'type'); if ($type !== null) { if (empty($linters[$type])) { @@ -81,9 +58,6 @@ $include = (array)idx($spec, 'include', array()); $exclude = (array)idx($spec, 'exclude', array()); - $this->validateRegexps($include, $name, 'include'); - $this->validateRegexps($exclude, $name, 'exclude'); - $this->debugLog('Examining paths for linter "%s".', $name); $paths = $this->matchPaths($all_paths, $include, $exclude); $this->debugLog( @@ -93,13 +67,36 @@ $linter->setPaths($paths); - $built_linters[] = $linter; } return $built_linters; } + private function parseConfiguration() { + $working_copy = $this->getWorkingCopy(); + $config_path = $working_copy->getProjectPath('.arclint'); + + // Parse the `.arclint` file, throwing an exception if the file + // doesn't exist. + Filesystem::assertExists($config_path); + Filesystem::assertIsFile($config_path); + Filesystem::assertReadable($config_path); + $config = parse_ini_file($config_path, true); + + // Check that the `.arclint` file was valid. + if ($config === false) { + throw new Exception( + "Expected '.arclint' file to be a valid INI file, but failed to ". + "decode it: {$config_path}"); + } + + $spec = PhutilTypeSpec::newFromString('map<string, map<string, wild>>'); + $spec->check($config); + + return $config; + } + private function loadAvailableLinters() { $linters = id(new PhutilSymbolLoader()) ->setAncestorClass('ArcanistLinter') @@ -131,8 +128,6 @@ } private function matchPaths(array $paths, array $include, array $exclude) { - $debug = $this->debugMode; - $match = array(); foreach ($paths as $path) { $this->debugLog("Examining path '%s'...", $path); @@ -145,7 +140,7 @@ } else { $this->debugLog(' Testing "include" rules.'); foreach ($include as $rule) { - if (preg_match($rule, $path)) { + if (fnmatch($rule, $path)) { $keep = true; $this->debugLog(' Path matches include rule: %s', $rule); break; @@ -163,7 +158,7 @@ if ($exclude) { $this->debugLog(' Testing "exclude" rules.'); foreach ($exclude as $rule) { - if (preg_match($rule, $path)) { + if (fnmatch($rule, $path)) { $this->debugLog(' Path matches "exclude" rule: %s', $rule); continue 2; } else { @@ -179,21 +174,6 @@ return $match; } - private function validateRegexps(array $regexps, $linter, $config) { - foreach ($regexps as $regexp) { - $ok = @preg_match($regexp, ''); - if ($ok === false) { - throw new Exception( - pht( - 'Regular expression "%s" (in "%s" configuration for linter "%s") '. - 'is not a valid regular expression.', - $regexp, - $config, - $linter)); - } - } - } - private function debugLog($pattern /* , $arg, ... */) { if (!$this->debugMode) { return; @@ -205,5 +185,4 @@ call_user_func_array(array($console, 'writeErr'), $argv); } - }