From ecb7a6c069fd6aa09ed374f8fd8c240314fcfbe6 Mon Sep 17 00:00:00 2001 From: "Jonathan H. Wage" Date: Fri, 3 May 2019 09:27:09 -0500 Subject: [PATCH] Add support for absolute plugin paths. --- docs/authoring_plugins.md | 9 +++++- phpunit.xml.dist | 2 +- src/Psalm/Config.php | 6 ++-- src/command_functions.php | 29 +++++++++++++++++++ tests/IsAbsolutePathTest.php | 36 +++++++++++++++++++++++ tests/PluginTest.php | 55 ++++++++++++++++++++++++++++++++++++ tests/bootstrap.php | 12 ++------ 7 files changed, 135 insertions(+), 14 deletions(-) create mode 100644 tests/IsAbsolutePathTest.php diff --git a/docs/authoring_plugins.md b/docs/authoring_plugins.md index c31dc27643f..1fffbbc4e76 100644 --- a/docs/authoring_plugins.md +++ b/docs/authoring_plugins.md @@ -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 To ensure your plugin runs when Psalm does, add it to your [config](configuration.md): -```php +```xml ``` +You can also specify an absolute path to your plugin: +```xml + + + +``` + ## Type system Understand how Psalm handles types by [reading this guide](plugins_type_system.md). diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bffb5d07baf..3985e89dfab 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ plugins->plugin)) { /** @var \SimpleXMLElement $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); } diff --git a/src/command_functions.php b/src/command_functions.php index af35ad0d87d..b7f265b29ec 100644 --- a/src/command_functions.php +++ b/src/command_functions.php @@ -220,3 +220,32 @@ function getPathsToCheck($f_paths) return $paths_to_check; } + +/** + * @param string $path + * + * @return bool + */ +function isAbsolutePath($path) +{ + // Optional wrapper(s). + $regex = '%^(?(?:[[:print:]]{2,}://)*)'; + + // Optional root prefix. + $regex .= '(?(?:[[:alpha:]]:/|/)?)'; + + // Actual path. + $regex .= '(?(?:[[: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; +} diff --git a/tests/IsAbsolutePathTest.php b/tests/IsAbsolutePathTest.php new file mode 100644 index 00000000000..8effdbd948a --- /dev/null +++ b/tests/IsAbsolutePathTest.php @@ -0,0 +1,36 @@ + + */ + 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], + ]; + } +} diff --git a/tests/PluginTest.php b/tests/PluginTest.php index f31fe456ab4..5a6591ca89f 100644 --- a/tests/PluginTest.php +++ b/tests/PluginTest.php @@ -770,4 +770,59 @@ public function testAfterAnalysisHooks() $this->project_analyzer->check('tests/DummyProject', 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( + ' + + + + + + + + ', + __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( + ' + + + + + + + + ', + __DIR__.'/..' + ) + ) + ); + + $this->project_analyzer->getCodebase()->config->initializePlugins($this->project_analyzer); + } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 84687b5ddf0..1e856ae7129 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,13 +1,5 @@