Skip to content

Commit

Permalink
Work in progress - resolve directories from config file location (#1904)
Browse files Browse the repository at this point in the history
* Add resolveFromConfigFile config option

Treats all paths as relative to the location of the config file, not
the current working directory of the process.

This commit just changes psalm, further commits will be needed to
apply the change to psalter and the LSP server.

* Copy asset xml files into project root for testing, delete during teardown

Needed since paths are now resolved relative to the position of the
file.

Not sure why I only saw a test failre for 1.xml - would have expected it
for all eight files.

* Fix following rebase

* Move psalm --init handly code above working directory setting code

If there's no psalm.xml yet we can't use the location of psalm.xml to
set our working directory

* Move Psalm version output code above working directory resolution

Working directory doesn't need to be known to output version constant

* Rely on new config file based working directory in end to end test

* Dont use rely on config dir for --alter - not currently working

* Fix code style error

* Add failing test for supporting config without `resolveFromConfigFile="true"`

* Don't treat config directory as a path to check

* Document resolveFromConfigFile setting
  • Loading branch information
bdsl authored and muglug committed Jul 6, 2019
1 parent 40a5194 commit 94f9346
Show file tree
Hide file tree
Showing 17 changed files with 221 additions and 100 deletions.
1 change: 1 addition & 0 deletions assets/config_levels/1.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
totallyTyped="true" totallyTyped="true"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
Expand Down
1 change: 1 addition & 0 deletions assets/config_levels/2.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
totallyTyped="false" totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
Expand Down
1 change: 1 addition & 0 deletions assets/config_levels/3.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
totallyTyped="false" totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
Expand Down
1 change: 1 addition & 0 deletions assets/config_levels/4.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
totallyTyped="false" totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
Expand Down
1 change: 1 addition & 0 deletions assets/config_levels/5.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
totallyTyped="false" totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
Expand Down
1 change: 1 addition & 0 deletions assets/config_levels/6.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
totallyTyped="false" totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
Expand Down
1 change: 1 addition & 0 deletions assets/config_levels/7.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
totallyTyped="false" totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
Expand Down
1 change: 1 addition & 0 deletions assets/config_levels/8.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
totallyTyped="false" totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
Expand Down
1 change: 1 addition & 0 deletions config.xsd
Expand Up @@ -52,6 +52,7 @@
<xs:attribute name="findUnusedVariablesAndParams" type="xs:string" /> <xs:attribute name="findUnusedVariablesAndParams" type="xs:string" />
<xs:attribute name="parseSql" type="xs:string" /> <xs:attribute name="parseSql" type="xs:string" />
<xs:attribute name="maxStringLength" type="xs:string" /> <xs:attribute name="maxStringLength" type="xs:string" />
<xs:attribute name="resolveFromConfigFile" type="xs:string" />
</xs:complexType> </xs:complexType>


<xs:complexType name="ProjectFilesType"> <xs:complexType name="ProjectFilesType">
Expand Down
12 changes: 12 additions & 0 deletions docs/running_psalm/configuration.md
Expand Up @@ -24,6 +24,18 @@ Psalm uses an XML config file (by default, `psalm.xml`). A barebones example loo
``` ```
Enabling this will make Psalm very strict, such that it needs to be able to evaluate the type of every single statement, and emitting a bevy of `Mixed*` issues if the types cannot be determined. Defaults to `false`. Enabling this will make Psalm very strict, such that it needs to be able to evaluate the type of every single statement, and emitting a bevy of `Mixed*` issues if the types cannot be determined. Defaults to `false`.


#### resolveFromConfigFile

```xml
<psalm
resolveFromConfigFile="[bool]"
/>
```
If this is enabled, relative directories mentioned in the config file will be resolved relative to the location
of the config file. If it is disabled, or absent they will be resolved relative to the working directory of the Psalm process.

New versions of Psalm enable this option when generating config files. Older versions did not include it.

#### useDocblockTypes #### useDocblockTypes


```xml ```xml
Expand Down
1 change: 1 addition & 0 deletions psalm.xml.dist
Expand Up @@ -10,6 +10,7 @@
checkForThrowsDocblock="false" checkForThrowsDocblock="false"
throwExceptionOnError="0" throwExceptionOnError="0"
findUnusedCode="true" findUnusedCode="true"
resolveFromConfigFile="true"
xsi:schemaLocation="https://getpsalm.org/schema/config config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config config.xsd"
> >
<projectFiles> <projectFiles>
Expand Down
49 changes: 38 additions & 11 deletions src/Psalm/Config.php
Expand Up @@ -333,6 +333,14 @@ class Config
*/ */
public $find_unused_variables = false; public $find_unused_variables = false;


/**
* Whether to resolve file and directory paths from the location of the config file,
* instead of the current working directory.
*
* @var bool
*/
public $resolve_from_config_file = false;

/** /**
* @var string[] * @var string[]
*/ */
Expand Down Expand Up @@ -466,15 +474,15 @@ protected function __construct()
* Searches up a folder hierarchy for the most immediate config. * Searches up a folder hierarchy for the most immediate config.
* *
* @param string $path * @param string $path
* @param string $base_dir * @param string $current_dir
* @param string $output_format * @param string $output_format
* *
* @throws ConfigException if a config path is not found
*
* @return Config * @return Config
* @psalm-suppress MixedArgument * @psalm-suppress MixedArgument
*@throws ConfigException if a config path is not found
*
*/ */
public static function getConfigForPath($path, $base_dir, $output_format) public static function getConfigForPath($path, $current_dir, $output_format)
{ {
$config_path = self::locateConfigFile($path); $config_path = self::locateConfigFile($path);


Expand All @@ -487,7 +495,7 @@ public static function getConfigForPath($path, $base_dir, $output_format)
throw new ConfigException('Config not found for path ' . $path); throw new ConfigException('Config not found for path ' . $path);
} }


return self::loadFromXMLFile($config_path, $base_dir); return self::loadFromXMLFile($config_path, $current_dir);
} }


/** /**
Expand Down Expand Up @@ -526,20 +534,22 @@ public static function locateConfigFile(string $path)
* Creates a new config object from the file * Creates a new config object from the file
* *
* @param string $file_path * @param string $file_path
* @param string $base_dir * @param string $current_dir
* *
* @return self * @return self
*/ */
public static function loadFromXMLFile($file_path, $base_dir) public static function loadFromXMLFile($file_path, $current_dir)
{ {
$file_contents = file_get_contents($file_path); $file_contents = file_get_contents($file_path);


$base_dir = dirname($file_path) . DIRECTORY_SEPARATOR;

if ($file_contents === false) { if ($file_contents === false) {
throw new \InvalidArgumentException('Cannot open ' . $file_path); throw new \InvalidArgumentException('Cannot open ' . $file_path);
} }


try { try {
$config = self::loadFromXML($base_dir, $file_contents); $config = self::loadFromXML($base_dir, $file_contents, $current_dir);
$config->hash = sha1($file_contents . \PSALM_VERSION); $config->hash = sha1($file_contents . \PSALM_VERSION);
} catch (ConfigException $e) { } catch (ConfigException $e) {
throw new ConfigException( throw new ConfigException(
Expand All @@ -555,6 +565,7 @@ public static function loadFromXMLFile($file_path, $base_dir)
* *
* @param string $base_dir * @param string $base_dir
* @param string $file_contents * @param string $file_contents
* @param string|null $current_dir Current working directory, if different to $base_dir
* *
* @return self * @return self
* @psalm-suppress MixedArgument * @psalm-suppress MixedArgument
Expand All @@ -564,11 +575,13 @@ public static function loadFromXMLFile($file_path, $base_dir)
* @psalm-suppress MixedOperand * @psalm-suppress MixedOperand
* @psalm-suppress MixedPropertyAssignment * @psalm-suppress MixedPropertyAssignment
*/ */
public static function loadFromXML($base_dir, $file_contents) public static function loadFromXML($base_dir, $file_contents, $current_dir = null)
{ {
$config = new static(); if ($current_dir === null) {
$current_dir = $base_dir;
}


$config->base_dir = $base_dir; $config = new static();


$schema_path = dirname(dirname(__DIR__)) . '/config.xsd'; $schema_path = dirname(dirname(__DIR__)) . '/config.xsd';


Expand Down Expand Up @@ -635,6 +648,20 @@ public static function loadFromXML($base_dir, $file_contents)
$config->hide_external_errors = $attribute_text === 'true' || $attribute_text === '1'; $config->hide_external_errors = $attribute_text === 'true' || $attribute_text === '1';
} }



if (isset($config_xml['resolveFromConfigFile'])) {
$attribute_text = (string) $config_xml['resolveFromConfigFile'];
$config->resolve_from_config_file = $attribute_text === 'true' || $attribute_text === '1';
}


if ($config->resolve_from_config_file) {
$config->base_dir = $base_dir;
} else {
$config->base_dir = $current_dir;
$base_dir = $current_dir;
}

if (isset($config_xml['autoloader'])) { if (isset($config_xml['autoloader'])) {
$autoloader_path = $config->base_dir . DIRECTORY_SEPARATOR . $config_xml['autoloader']; $autoloader_path = $config->base_dir . DIRECTORY_SEPARATOR . $config_xml['autoloader'];


Expand Down
5 changes: 5 additions & 0 deletions src/command_functions.php
Expand Up @@ -201,6 +201,11 @@ function getPathsToCheck($f_paths)
/** @var string */ /** @var string */
$input_path = $input_paths[$i]; $input_path = $input_paths[$i];


if ($i > 0 && in_array($input_paths[$i-1], ['-c', '--config'])) {
// This is the path to the config file, not a path to check.
continue;
}

if (realpath($input_path) === realpath(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'psalm') if (realpath($input_path) === realpath(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'psalm')
|| realpath($input_path) === realpath(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'psalter') || realpath($input_path) === realpath(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'psalter')
|| realpath($input_path) === realpath(Phar::running(false)) || realpath($input_path) === realpath(Phar::running(false))
Expand Down

0 comments on commit 94f9346

Please sign in to comment.