1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Add support for absolute plugin paths.

This commit is contained in:
Jonathan H. Wage 2019-05-03 09:27:09 -05:00 committed by Matthew Brown
parent dd40987187
commit ecb7a6c069
7 changed files with 135 additions and 14 deletions

View File

@ -24,12 +24,19 @@ Here are a couple of example plugins:
- [FunctionCasingChecker](https://github.com/vimeo/psalm/blob/master/examples/plugins/FunctionCasingChecker.php) - checks that your functions and methods are correctly-cased - [FunctionCasingChecker](https://github.com/vimeo/psalm/blob/master/examples/plugins/FunctionCasingChecker.php) - checks that your functions and methods are correctly-cased
To ensure your plugin runs when Psalm does, add it to your [config](configuration.md): To ensure your plugin runs when Psalm does, add it to your [config](configuration.md):
```php ```xml
<plugins> <plugins>
<plugin filename="src/plugins/SomePlugin.php" /> <plugin filename="src/plugins/SomePlugin.php" />
</plugins> </plugins>
``` ```
You can also specify an absolute path to your plugin:
```xml
<plugins>
<plugin filename="/path/to/SomePlugin.php" />
</plugins>
```
## Type system ## Type system
Understand how Psalm handles types by [reading this guide](plugins_type_system.md). Understand how Psalm handles types by [reading this guide](plugins_type_system.md).

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/5.7/phpunit.xsd" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/5.7/phpunit.xsd"
bootstrap="vendor/autoload.php" bootstrap="tests/bootstrap.php"
backupGlobals="false" backupGlobals="false"
beStrictAboutCoversAnnotation="true" beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true" beStrictAboutOutputDuringTests="true"

View File

@ -792,9 +792,11 @@ class Config
if (isset($config_xml->plugins->plugin)) { if (isset($config_xml->plugins->plugin)) {
/** @var \SimpleXMLElement $plugin */ /** @var \SimpleXMLElement $plugin */
foreach ($config_xml->plugins->plugin as $plugin) { foreach ($config_xml->plugins->plugin as $plugin) {
$plugin_file_name = $plugin['filename']; $plugin_file_name = (string) $plugin['filename'];
$path = $config->base_dir . $plugin_file_name; $path = isAbsolutePath($plugin_file_name)
? $plugin_file_name
: $config->base_dir . $plugin_file_name;
$config->addPluginPath($path); $config->addPluginPath($path);
} }

View File

@ -220,3 +220,32 @@ function getPathsToCheck($f_paths)
return $paths_to_check; return $paths_to_check;
} }
/**
* @param string $path
*
* @return bool
*/
function isAbsolutePath($path)
{
// Optional wrapper(s).
$regex = '%^(?<wrappers>(?:[[:print:]]{2,}://)*)';
// Optional root prefix.
$regex .= '(?<root>(?:[[:alpha:]]:/|/)?)';
// Actual path.
$regex .= '(?<path>(?:[[:print:]]*))$%';
$parts = [];
if (!preg_match($regex, $path, $parts)) {
throw new InvalidArgumentException(sprintf('Path is not valid, "%s" given.', $path));
}
if ('' !== $parts['root']) {
return true;
}
return false;
}

View File

@ -0,0 +1,36 @@
<?php
namespace Psalm\Tests;
class IsAbsolutePathTest extends TestCase
{
/**
* @param string $path
* @param bool $expected
*
* @return void
*
* @dataProvider providerForTestIsAbsolutePath
*/
public function testIsAbsolutePath($path, $expected)
{
require_once __DIR__.'/../src/command_functions.php';
self::assertSame($expected, isAbsolutePath($path));
}
/**
* @return array<int, array{0:string, 1:bool}>
*/
public function providerForTestIsAbsolutePath()
{
return [
['/path/to/something', true],
['/path/to/something/file.php', true],
['relative/path/to/something', false],
['relative/path/to/something/file.php', false],
['c:/path/to/something', true],
['file://c:/path/to/something', true],
['zlib://c:/path/to/something', true],
];
}
}

View File

@ -770,4 +770,59 @@ class PluginTest extends TestCase
$this->project_analyzer->check('tests/DummyProject', true); $this->project_analyzer->check('tests/DummyProject', true);
\Psalm\IssueBuffer::finish($this->project_analyzer, true, microtime(true)); \Psalm\IssueBuffer::finish($this->project_analyzer, true, microtime(true));
} }
/**
* @return void
*/
public function testPluginFilenameCanBeAbsolute()
{
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__) . DIRECTORY_SEPARATOR,
sprintf(
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<plugins>
<plugin filename="%s/examples/plugins/StringChecker.php" />
</plugins>
</psalm>',
__DIR__.'/..'
)
)
);
$this->project_analyzer->getCodebase()->config->initializePlugins($this->project_analyzer);
}
/**
* @expectedException InvalidArgumentException
* @expectedExceptionMessage does-not-exist/plugins/StringChecker.php
*
* @return void
*/
public function testPluginInvalidAbsoluteFilenameThrowsException()
{
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__) . DIRECTORY_SEPARATOR,
sprintf(
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<plugins>
<plugin filename="%s/does-not-exist/plugins/StringChecker.php" />
</plugins>
</psalm>',
__DIR__.'/..'
)
)
);
$this->project_analyzer->getCodebase()->config->initializePlugins($this->project_analyzer);
}
} }

View File

@ -1,13 +1,5 @@
<?php <?php
ini_set('display_startup_errors', '1'); require_once(__DIR__.'/../src/command_functions.php');
ini_set('html_errors', '1');
ini_set('memory_limit', '-1');
error_reporting(E_ALL);
foreach ([__DIR__ . '/../../../autoload.php', __DIR__ . '/../vendor/autoload.php'] as $file) { return require_once(__DIR__.'/../vendor/autoload.php');
if (file_exists($file)) {
require $file;
break;
}
}