Changeset View
Changeset View
Standalone View
Standalone View
src/lint/linter/ArcanistExternalLinter.php
<?php | <?php | ||||
/** | /** | ||||
* Base class for linters which operate by invoking an external program and | * Base class for linters which operate by invoking an external program and | ||||
* parsing results. | * parsing results. | ||||
* | * | ||||
* @task bin Interpreters, Binaries and Flags | * @task bin Interpreters, Binaries and Flags | ||||
* @task parse Parsing Linter Output | * @task parse Parsing Linter Output | ||||
* @task exec Executing the Linter | * @task exec Executing the Linter | ||||
*/ | */ | ||||
abstract class ArcanistExternalLinter extends ArcanistFutureLinter { | abstract class ArcanistExternalLinter extends ArcanistFutureLinter { | ||||
private $bin; | private $bin; | ||||
private $interpreter; | private $interpreter; | ||||
private $flags; | private $flags; | ||||
private $versionRequirement; | private $versionRequirement; | ||||
private $interpreterFlags; | |||||
/* -( Interpreters, Binaries and Flags )----------------------------------- */ | /* -( Interpreters, Binaries and Flags )----------------------------------- */ | ||||
/** | /** | ||||
* Return the default binary name or binary path where the external linter | * Return the default binary name or binary path where the external linter | ||||
* lives. This can either be a binary name which is expected to be installed | * lives. This can either be a binary name which is expected to be installed | ||||
* in PATH (like "jshint"), or a relative path from the project root | * in PATH (like "jshint"), or a relative path from the project root | ||||
▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | /* -( Interpreters, Binaries and Flags )----------------------------------- */ | ||||
* @return this | * @return this | ||||
* @task bin | * @task bin | ||||
*/ | */ | ||||
final public function setInterpreter($interpreter) { | final public function setInterpreter($interpreter) { | ||||
$this->interpreter = $interpreter; | $this->interpreter = $interpreter; | ||||
return $this; | return $this; | ||||
} | } | ||||
/** | |||||
* Return array of flags needed by the interpreter, such as "-jar" when | |||||
* using java as the interpreter. This method is only invoked if | |||||
* @{method:shouldUseInterpreter} has been overridden to return 'true'. | |||||
* | |||||
* @return array Flags to pass to interpreter | |||||
* @task bin | |||||
*/ | |||||
protected function getDefaultInterpreterFlags() { | |||||
return array(); | |||||
} | |||||
/** | |||||
* Provide mandatory, non-overridable flags to the linter interpreter. | |||||
* Generally these are arguments to configure invocation of the interpreter | |||||
* such as (assuming Java interpreter) `-Xmx1024m`, `-Dproperty=value`, or | |||||
* in the case of the binary being a jar file, the last one should be `-jar`. | |||||
* | |||||
* Due to the specific case of using java as interpreter and a jarfile as | |||||
* the binary, the `-jar` argument must appear last in the list of all | |||||
* flags passed to interpreter. For this, manadatory flags are ensured to | |||||
* always be listed before any default or user overridden flags. | |||||
* | |||||
* Flags which are not mandatory should be provided in | |||||
* @{method:getDefaultInterpreterFlags} instead. | |||||
* | |||||
* @return list<string> Mandatory flags, like `"-jar"`. | |||||
* @task bin | |||||
*/ | |||||
protected function getMandatoryInterpreterFlags() { | |||||
return array(); | |||||
} | |||||
/** | |||||
* Override default interpreter flags with custom flags. If not overridden, | |||||
* flags provided by @{method:getDefaultInterpreterFlags} are used. | |||||
* | |||||
* @param list<string> New flags for the interpreter. | |||||
* @return this | |||||
* @task bin | |||||
*/ | |||||
final public function setInterpreterFlags(array $interpreter_flags) { | |||||
$this->interpreterFlags = $interpreter_flags; | |||||
return $this; | |||||
} | |||||
/* -( Parsing Linter Output )---------------------------------------------- */ | /* -( Parsing Linter Output )---------------------------------------------- */ | ||||
/** | /** | ||||
* Parse the output of the external lint program into objects of class | * Parse the output of the external lint program into objects of class | ||||
* @{class:ArcanistLintMessage} which `arc` can consume. Generally, this | * @{class:ArcanistLintMessage} which `arc` can consume. Generally, this | ||||
* means examining the output and converting each warning or error into a | * means examining the output and converting each warning or error into a | ||||
* message. | * message. | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | /* -( Executing the Linter )----------------------------------------------- */ | ||||
* | * | ||||
* @return string Command to execute the raw linter. | * @return string Command to execute the raw linter. | ||||
* @task exec | * @task exec | ||||
*/ | */ | ||||
final protected function getExecutableCommand() { | final protected function getExecutableCommand() { | ||||
$this->checkBinaryConfiguration(); | $this->checkBinaryConfiguration(); | ||||
$interpreter = null; | $interpreter = null; | ||||
$interpreter_flags = array(); | |||||
if ($this->shouldUseInterpreter()) { | if ($this->shouldUseInterpreter()) { | ||||
$interpreter = $this->getInterpreter(); | $interpreter = $this->getInterpreter(); | ||||
$interpreter_flags = $this->getInterpreterFlags(); | |||||
} | } | ||||
$binary = $this->getBinary(); | $binary = $this->getBinary(); | ||||
if ($interpreter) { | if ($interpreter) { | ||||
if (!empty($interpreter_flags)) { | |||||
$bin = csprintf('%s %Ls %s', $interpreter, $interpreter_flags, $binary); | |||||
} else { | |||||
$bin = csprintf('%s %s', $interpreter, $binary); | $bin = csprintf('%s %s', $interpreter, $binary); | ||||
} | |||||
} else { | } else { | ||||
$bin = csprintf('%s', $binary); | $bin = csprintf('%s', $binary); | ||||
} | } | ||||
return $bin; | return $bin; | ||||
} | } | ||||
/** | /** | ||||
* Get the composed flags for the executable, including both mandatory and | * Get the composed flags for the executable, including both mandatory and | ||||
* configured flags. | * configured flags. | ||||
* | * | ||||
* @return list<string> Composed flags. | * @return list<string> Composed flags. | ||||
* @task exec | * @task exec | ||||
*/ | */ | ||||
final protected function getCommandFlags() { | final protected function getCommandFlags() { | ||||
return array_merge( | return array_merge( | ||||
$this->getMandatoryFlags(), | $this->getMandatoryFlags(), | ||||
nonempty($this->flags, $this->getDefaultFlags())); | nonempty($this->flags, $this->getDefaultFlags())); | ||||
} | } | ||||
/** | |||||
* Get the composed flags for the interpreter, including both mandatory and | |||||
* configured flags. | |||||
* | |||||
* @return list<string> Composed interpreter flags. | |||||
* @task exec | |||||
*/ | |||||
final protected function getInterpreterFlags() { | |||||
// Note that this forces the mandatory flags to appear before any other | |||||
// flags provided through default or overridden. This is to handle the | |||||
// the case of java interpreter needing to combine the `-jar` flag followed | |||||
// immediately by the binary which would be the jar file. | |||||
return array_merge( | |||||
nonempty($this->interpreterFlags, $this->getDefaultInterpreterFlags()), | |||||
$this->getMandatoryInterpreterFlags()); | |||||
} | |||||
public function getCacheVersion() { | public function getCacheVersion() { | ||||
try { | try { | ||||
$this->checkBinaryConfiguration(); | $this->checkBinaryConfiguration(); | ||||
} catch (ArcanistMissingLinterException $e) { | } catch (ArcanistMissingLinterException $e) { | ||||
return null; | return null; | ||||
} | } | ||||
$version = $this->getVersion(); | $version = $this->getVersion(); | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | if ($this->shouldUseInterpreter()) { | ||||
$options['interpreter'] = array( | $options['interpreter'] = array( | ||||
'type' => 'optional string | list<string>', | 'type' => 'optional string | list<string>', | ||||
'help' => pht( | 'help' => pht( | ||||
'Specify a string (or list of strings) identifying the interpreter '. | 'Specify a string (or list of strings) identifying the interpreter '. | ||||
'which should be used to invoke the linter binary. If you provide '. | 'which should be used to invoke the linter binary. If you provide '. | ||||
'a list of possible interpreters, the first one that exists '. | 'a list of possible interpreters, the first one that exists '. | ||||
'will be used.'), | 'will be used.'), | ||||
); | ); | ||||
$options['interpreter.flags'] = array( | |||||
'type' => 'optional list<string>', | |||||
'help' => pht( | |||||
'Provide a list of additional flags to pass to the interpreter on '. | |||||
'the command line.'), | |||||
); | |||||
} | } | ||||
return $options + parent::getLinterConfigurationOptions(); | return $options + parent::getLinterConfigurationOptions(); | ||||
} | } | ||||
public function setLinterConfigurationValue($key, $value) { | public function setLinterConfigurationValue($key, $value) { | ||||
switch ($key) { | switch ($key) { | ||||
case 'interpreter': | case 'interpreter': | ||||
Show All 34 Lines | switch ($key) { | ||||
} | } | ||||
} | } | ||||
throw new Exception( | throw new Exception( | ||||
pht('None of the configured binaries can be located.')); | pht('None of the configured binaries can be located.')); | ||||
case 'flags': | case 'flags': | ||||
$this->setFlags($value); | $this->setFlags($value); | ||||
return; | return; | ||||
case 'interpreter.flags': | |||||
$this->setInterpreterFlags($value); | |||||
return; | |||||
case 'version': | case 'version': | ||||
$this->setVersionRequirement($value); | $this->setVersionRequirement($value); | ||||
return; | return; | ||||
} | } | ||||
return parent::setLinterConfigurationValue($key, $value); | return parent::setLinterConfigurationValue($key, $value); | ||||
} | } | ||||
Show All 15 Lines |