mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-25 08:12:40 +01:00
Merge branch 'master' of github.com:facebook/arcanist
This commit is contained in:
commit
042081b47f
6 changed files with 86 additions and 22 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
._*
|
._*
|
||||||
|
/src/.phutil_module_cache
|
||||||
|
|
|
@ -26,6 +26,7 @@ if ($argc != 2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
phutil_require_module('phutil', 'filesystem');
|
phutil_require_module('phutil', 'filesystem');
|
||||||
|
phutil_require_module('phutil', 'filesystem/filefinder');
|
||||||
phutil_require_module('phutil', 'future/exec');
|
phutil_require_module('phutil', 'future/exec');
|
||||||
|
|
||||||
$root = Filesystem::resolvePath($argv[1]);
|
$root = Filesystem::resolvePath($argv[1]);
|
||||||
|
@ -35,31 +36,85 @@ if (!@file_exists($root.'/__phutil_library_init__.php')) {
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "Finding phutil modules...\n";
|
echo "Finding phutil modules...\n";
|
||||||
|
$files = id(new FileFinder($root))
|
||||||
|
->withType('f')
|
||||||
|
->withSuffix('php')
|
||||||
|
->excludePath('*/.*')
|
||||||
|
->setGenerateChecksums(true)
|
||||||
|
->find();
|
||||||
|
|
||||||
list($stdout) = execx(
|
// NOTE: Sorting by filename ensures that hash computation is stable; it is
|
||||||
"(cd %s && find . -type d -path '*/.*' -prune -o -type d -print0)",
|
// important we sort by name instead of by hash because sorting by hash could
|
||||||
$root);
|
// create a bad cache hit if the user swaps the contents of two files.
|
||||||
|
ksort($files);
|
||||||
|
|
||||||
$futures = array();
|
$modules = array();
|
||||||
foreach (array_filter(explode("\0", $stdout)) as $dir) {
|
foreach ($files as $file => $hash) {
|
||||||
if ($dir == '.') {
|
if (dirname($file) == $root) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$module = preg_replace('@^\\./@', '', $dir);
|
$modules[Filesystem::readablePath(dirname($file), $root)][] = $hash;
|
||||||
$futures[$module] = new ExecFuture(
|
}
|
||||||
'%s %s',
|
|
||||||
dirname(__FILE__).'/phutil_analyzer.php',
|
echo "Found ".count($files)." files in ".count($modules)." modules.\n";
|
||||||
$root.'/'.$module);
|
|
||||||
|
$signatures = array();
|
||||||
|
foreach ($modules as $module => $hashes) {
|
||||||
|
$hashes = implode(' ', $hashes);
|
||||||
|
$signature = md5($hashes);
|
||||||
|
$signatures[$module] = $signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$cache = Filesystem::readFile($root.'/.phutil_module_cache');
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$cache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$signature_cache = array();
|
||||||
|
if ($cache) {
|
||||||
|
$signature_cache = json_decode($cache, true);
|
||||||
|
if (!is_array($signature_cache)) {
|
||||||
|
$signature_cache = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$specs = array();
|
||||||
|
|
||||||
|
$futures = array();
|
||||||
|
foreach ($signatures as $module => $signature) {
|
||||||
|
if (isset($signature_cache[$module]) &&
|
||||||
|
$signature_cache[$module]['signature'] == $signature) {
|
||||||
|
$specs[$module] = $signature_cache[$module];
|
||||||
|
} else {
|
||||||
|
$futures[$module] = new ExecFuture(
|
||||||
|
'%s %s',
|
||||||
|
dirname(__FILE__).'/phutil_analyzer.php',
|
||||||
|
$root.'/'.$module);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($futures) {
|
||||||
|
echo "Found ".count($specs)." modules in cache; ".
|
||||||
|
"analyzing ".count($futures)." modified modules";
|
||||||
|
foreach (Futures($futures)->limit(8) as $module => $future) {
|
||||||
|
echo ".";
|
||||||
|
$specs[$module] = array(
|
||||||
|
'signature' => $signatures[$module],
|
||||||
|
'spec' => $future->resolveJSON(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
echo "\n";
|
||||||
|
} else {
|
||||||
|
echo "All modules were found in cache.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "Analyzing ".number_format(count($futures))." modules";
|
|
||||||
$class_map = array();
|
$class_map = array();
|
||||||
$requires_class_map = array();
|
$requires_class_map = array();
|
||||||
$requires_interface_map = array();
|
$requires_interface_map = array();
|
||||||
$function_map = array();
|
$function_map = array();
|
||||||
foreach (Futures($futures)->limit(16) as $module => $future) {
|
foreach ($specs as $module => $info) {
|
||||||
echo ".";
|
$spec = $info['spec'];
|
||||||
$spec = $future->resolveJSON();
|
|
||||||
foreach (array('class', 'interface') as $type) {
|
foreach (array('class', 'interface') as $type) {
|
||||||
foreach ($spec['declares'][$type] as $class => $where) {
|
foreach ($spec['declares'][$type] as $class => $where) {
|
||||||
if (!empty($class_map[$class])) {
|
if (!empty($class_map[$class])) {
|
||||||
|
@ -125,4 +180,10 @@ echo "Writing library map file...\n";
|
||||||
|
|
||||||
Filesystem::writeFile($root.'/__phutil_library_map__.php', $map_file);
|
Filesystem::writeFile($root.'/__phutil_library_map__.php', $map_file);
|
||||||
|
|
||||||
|
echo "Writing module cache...\n";
|
||||||
|
|
||||||
|
Filesystem::writeFile(
|
||||||
|
$root.'/.phutil_module_cache',
|
||||||
|
json_encode($specs));
|
||||||
|
|
||||||
echo "Done.\n";
|
echo "Done.\n";
|
||||||
|
|
|
@ -38,6 +38,11 @@ class PhutilLintEngine extends ArcanistLintEngine {
|
||||||
if (!$this->pathExists($path)) {
|
if (!$this->pathExists($path)) {
|
||||||
unset($paths[$key]);
|
unset($paths[$key]);
|
||||||
}
|
}
|
||||||
|
if (preg_match('@^externals/@', $path)) {
|
||||||
|
// Third-party stuff lives in /externals/; don't run lint engines
|
||||||
|
// against it.
|
||||||
|
unset($paths[$key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$generated_linter = new ArcanistGeneratedLinter();
|
$generated_linter = new ArcanistGeneratedLinter();
|
||||||
|
@ -47,7 +52,7 @@ class PhutilLintEngine extends ArcanistLintEngine {
|
||||||
$linters[] = $text_linter;
|
$linters[] = $text_linter;
|
||||||
foreach ($paths as $path) {
|
foreach ($paths as $path) {
|
||||||
$is_text = false;
|
$is_text = false;
|
||||||
if (preg_match('/\.php$/', $path)) {
|
if (preg_match('/\.(php|css|js)$/', $path)) {
|
||||||
$is_text = true;
|
$is_text = true;
|
||||||
}
|
}
|
||||||
if ($is_text) {
|
if ($is_text) {
|
||||||
|
|
|
@ -43,9 +43,7 @@ class ArcanistApacheLicenseLinter extends ArcanistLinter {
|
||||||
$copyright_holder = $working_copy->getConfig('copyright_holder');
|
$copyright_holder = $working_copy->getConfig('copyright_holder');
|
||||||
|
|
||||||
if (!$copyright_holder) {
|
if (!$copyright_holder) {
|
||||||
throw new ArcanistUsageException(
|
return;
|
||||||
"This project uses the ArcanistApacheLicenseLinter, but does not ".
|
|
||||||
"define a 'copyright_holder' in its .arcconfig.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$year = date('Y');
|
$year = date('Y');
|
||||||
|
|
|
@ -143,7 +143,6 @@ abstract class ArcanistLinter {
|
||||||
$code,
|
$code,
|
||||||
$desc) {
|
$desc) {
|
||||||
|
|
||||||
$path = $this->getActivePath();
|
|
||||||
return $this->raiseLintAtLine(null, null, $code, $desc, null, null);
|
return $this->raiseLintAtLine(null, null, $code, $desc, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -904,8 +904,8 @@ class ArcanistXHPASTLinter extends ArcanistLinter {
|
||||||
$decl_name = $declaration->getChildByIndex(1);
|
$decl_name = $declaration->getChildByIndex(1);
|
||||||
$decl_string = $decl_name->getConcreteString();
|
$decl_string = $decl_name->getConcreteString();
|
||||||
|
|
||||||
//Exclude strangely named classes.
|
// Exclude strangely named classes, e.g. XHP tags.
|
||||||
if (!preg_match('/\w+/', $decl_string)) {
|
if (!preg_match('/^\w+$/', $decl_string)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue