1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-01-11 07:11:03 +01:00

Add ArcanistConduitLinter, a linter that delegates through Conduit

Summary:
Julien built a really cool static analysis database of our codebase. One
capability is that it can suggest typehints that are not in the code. The
analysis to do this is very expensive, so it can't reasonably be run locally.
But it can remain indexed on a server.

The idea here is to provide a familiar interface to it through arc lint, via a
generic Conduit service call.

In our lint engine, this will probably be gated on --advice for performance.
This will introduce a slight awkwardness in that running with --advice can add
new non-advice lint if the server chooses, but this isn't likely to cause a
practical problem.

Test Plan:
Construct a fake Conduit lint endpoint, attach this linter to it, and see bogus
lint
appear with --advice.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran

Differential Revision: https://secure.phabricator.com/D1462
This commit is contained in:
adonohue 2012-01-19 17:09:27 -08:00
parent 3299f1fc73
commit 2c4eb00a12
3 changed files with 129 additions and 0 deletions

View file

@ -21,6 +21,7 @@ phutil_register_library_map(array(
'ArcanistChooseInvalidRevisionException' => 'exception',
'ArcanistChooseNoRevisionsException' => 'exception',
'ArcanistCommitWorkflow' => 'workflow/commit',
'ArcanistConduitLinter' => 'lint/linter/conduit',
'ArcanistConfiguration' => 'configuration',
'ArcanistCoverWorkflow' => 'workflow/cover',
'ArcanistDiffChange' => 'parser/diff/change',
@ -119,6 +120,7 @@ phutil_register_library_map(array(
'ArcanistBundleTestCase' => 'ArcanistPhutilTestCase',
'ArcanistCallConduitWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistCommitWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistConduitLinter' => 'ArcanistLinter',
'ArcanistCoverWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistDiffParserTestCase' => 'ArcanistPhutilTestCase',
'ArcanistDiffUtilsTestCase' => 'ArcanistPhutilTestCase',

View file

@ -0,0 +1,110 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Implements linting via Conduit RPC call.
* Slow by definition, but allows sophisticated linting that relies on
* stuff like big indexes of a codebase.
* Recommended usage is to gate these to the advice lint level.
*
* The conduit endpoint should implement a method named the same as
* the value of ArcanistConduitLinter::CONDUIT_METHOD.
*
* It takes an array with a key 'file_contents' which is an array mapping
* file paths to their complete contents.
*
* It should return an array mapping those same paths to arrays describing the
* lint for each path.
*
* The lint for a path is described as a list of structured dictionaries.
*
* The dictionary structure is effectively defined by
* ArcanistLintMessage::newFromDictionary.
*
* Effective keys are:
* 'path' => must match passed in path.
* 'line'
* 'char'
* 'code'
* 'severity' => Must match a constant in ArcanistLintSeverity.
* 'name'
* 'description'
* 'original' & 'replacement' => optional patch information
*
* This class is intended for customization via instantiation, not via
* subclassing.
*/
class ArcanistConduitLinter extends ArcanistLinter {
const CONDUIT_METHOD = 'lint.getalllint';
private $conduitURI;
private $linterName;
private $lintByPath; // array(/pa/th/ => <lint>), valid after willLintPaths().
public function __construct($conduit_uri, $linter_name) {
$this->conduitURI = $conduit_uri;
$this->linterName = $linter_name;
}
public function willLintPaths(array $paths) {
// Load all file path data into $this->data.
array_map(array($this, 'getData'), $paths);
$conduit = new ConduitClient($this->conduitURI);
$this->lintByPath = $conduit->callMethodSynchronous(
self::CONDUIT_METHOD,
array(
'file_contents' => $this->data,
)
);
}
public function lintPath($path) {
$lint_for_path = idx($this->lintByPath, $path);
if (!$lint_for_path) {
return;
}
foreach ($lint_for_path as $lint) {
$this->addLintMessage(ArcanistLintMessage::newFromDictionary($lint));
}
}
public function getLinterName() {
return $this->linterName;
}
public function getLintSeverityMap() {
// The rationale here is that this class will only be used for custom
// linting in installations. No two server endpoints will be the same across
// different instantiations. Therefore, the server can handle all severity
// customization directly.
throw new ArcanistUsageException(
'ArcanistConduitLinter does not support client-side severity '.
'customization.'
);
}
public function getLintNameMap() {
// See getLintSeverityMap for rationale.
throw new ArcanistUsageException(
'ArcanistConduitLinter does not support a name map.'
);
}
}

View file

@ -0,0 +1,17 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('arcanist', 'exception/usage');
phutil_require_module('arcanist', 'lint/linter/base');
phutil_require_module('arcanist', 'lint/message');
phutil_require_module('phutil', 'conduit/client');
phutil_require_module('phutil', 'utils');
phutil_require_source('ArcanistConduitLinter.php');