Skip to content
Permalink
Browse files

Add support for absolute plugin paths.

  • Loading branch information...
jwage authored and muglug committed May 3, 2019
1 parent dd40987 commit ecb7a6c069fd6aa09ed374f8fd8c240314fcfbe6
Showing with 135 additions and 14 deletions.
  1. +8 −1 docs/authoring_plugins.md
  2. +1 −1 phpunit.xml.dist
  3. +4 −2 src/Psalm/Config.php
  4. +29 −0 src/command_functions.php
  5. +36 −0 tests/IsAbsolutePathTest.php
  6. +55 −0 tests/PluginTest.php
  7. +2 −10 tests/bootstrap.php
@@ -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
<plugins>
<plugin filename="src/plugins/SomePlugin.php" />
</plugins>
```

You can also specify an absolute path to your plugin:
```xml
<plugins>
<plugin filename="/path/to/SomePlugin.php" />
</plugins>
```

## Type system

Understand how Psalm handles types by [reading this guide](plugins_type_system.md).
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/5.7/phpunit.xsd"
bootstrap="vendor/autoload.php"
bootstrap="tests/bootstrap.php"
backupGlobals="false"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
@@ -792,9 +792,11 @@ public static function loadFromXML($base_dir, $file_contents)
if (isset($config_xml->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);
}
@@ -220,3 +220,32 @@ function getPathsToCheck($f_paths)
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;
}
@@ -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],
];
}
}
@@ -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(
'<?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);
}
}
@@ -1,13 +1,5 @@
<?php
ini_set('display_startup_errors', '1');
ini_set('html_errors', '1');
ini_set('memory_limit', '-1');
error_reporting(E_ALL);
require_once(__DIR__.'/../src/command_functions.php');
foreach ([__DIR__ . '/../../../autoload.php', __DIR__ . '/../vendor/autoload.php'] as $file) {
if (file_exists($file)) {
require $file;
break;
}
}
return require_once(__DIR__.'/../vendor/autoload.php');

0 comments on commit ecb7a6c

Please sign in to comment.
You can’t perform that action at this time.