diff --git a/src/lint/linter/ArcanistExternalLinter.php b/src/lint/linter/ArcanistExternalLinter.php --- a/src/lint/linter/ArcanistExternalLinter.php +++ b/src/lint/linter/ArcanistExternalLinter.php @@ -13,6 +13,8 @@ private $bin; private $interpreter; private $flags; + private $minimumVersion; + private $maximumVersion; /* -( Interpreters, Binaries and Flags )----------------------------------- */ @@ -134,6 +136,24 @@ } /** + * TODO + * + * @return string + */ + protected function getDefaultMinimumVersion() { + return null; + } + + /** + * TODO + * + * @return string + */ + protected function getDefaultMaximumVersion() { + return null; + } + + /** * Override default flags with custom flags. If not overridden, flags provided * by @{method:getDefaultFlags} are used. * @@ -218,6 +238,54 @@ return $this; } + /** + * TODO + * + * @return string + */ + final public function getMinimumVersion() { + return coalesce($this->minimumVersion, $this->getDefaultMinimumVersion()); + } + + /** + * TODO + * + * @param string + * @return this + */ + final public function setMinimumVersion($version) { + if (!$this->hasVersion()) { + throw new Exception('TODO'); + } + + $this->minimumVersion = $version; + return $this; + } + + /** + * TODO + * + * @return string + */ + final public function getMaximumVersion() { + return coalesce($this->maximumVersion, $this->getDefaultMaximumVersion()); + } + + /** + * TODO + * + * @param string + * @return this + */ + final public function setMaximumVersion($version) { + if (!$this->hasVersion()) { + throw new Exception('TODO'); + } + + $this->maximumVersion = $version; + return $this; + } + /* -( Parsing Linter Output )---------------------------------------------- */ @@ -378,6 +446,22 @@ final protected function buildFutures(array $paths) { $executable = $this->getExecutableCommand(); + $min_version = $this->getMinimumVersion(); + if ($min_version) { + if (!$this->compareVersion($min_version, '>=')) { + // TODO: Provide a more descriptive error message. + throw new ArcanistUsageException('Wrong version'); + } + } + + $max_version = $this->getMaximumVersion(); + if ($max_version) { + if (!$this->compareVersion($max_version, '<=')) { + // TODO: Provide a more descriptive error message. + throw new ArcanistUsageException('Wrong version'); + } + } + $bin = csprintf('%C %Ls', $executable, $this->getCommandFlags()); $futures = array(); @@ -440,6 +524,14 @@ 'Provide a list of additional flags to pass to the linter on the '. 'command line.'), ), + 'version.min' => array( + 'type' => 'optional string', + 'help' => pht('TODO'), + ), + 'version.max' => array( + 'type' => 'optional string', + 'help' => pht('TODO'), + ), ); if ($this->shouldUseInterpreter()) { @@ -509,6 +601,13 @@ } $this->setFlags($value); return; + case 'minimum-version': + $this->minimumVersion = $value; + return; + case 'maximum-version': + $this->maximumVersion = $value; + return; + } return parent::setLinterConfigurationValue($key, $value); diff --git a/src/lint/linter/ArcanistLinter.php b/src/lint/linter/ArcanistLinter.php --- a/src/lint/linter/ArcanistLinter.php +++ b/src/lint/linter/ArcanistLinter.php @@ -307,10 +307,54 @@ abstract public function lintPath($path); abstract public function getLinterName(); + /** + * TODO + * + * @return string + */ public function getVersion() { return null; } + /** + * TODO + * + * @return bool + */ + final public function hasVersion() { + $method = new ReflectionMethod($this, 'getVersion'); + return $method->getDeclaringClass()->isAbstract(); + } + + /** + * Compare the version of the linter with a target version. + * + * @param string The target version for the linter. + * @param string The desired version relationship. The possible values are + * `<`, `<=`, `>`, `>=`, `==`, `=`, `!=` and `<>`. + * @return bool True if the relationship is the one specified by the operator, + * false otherwise. + */ + protected function compareVersion($target_version, $operator) { + if (!$this->hasVersion()) { + throw new Exception(pht( + 'Version cannot be compared because %s does not provide version '. + 'information.', + get_class($this))); + } + + $version = $this->getVersion(); + + if (!$version) { + // TODO: We should output the minimum version requirement here. + throw new Exception(pht('Unable to parse version.')); + } + + // The PHP version_compare method does a pretty good job in the general + // case. + return version_compare($version, $target_version, $operator); + } + public function didRunLinters() { // This is a hook. }