diff --git a/assets/config_levels/1.xml b/assets/config_levels/1.xml new file mode 100644 index 000000000..07fe02633 --- /dev/null +++ b/assets/config_levels/1.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/assets/config_levels/2.xml b/assets/config_levels/2.xml new file mode 100644 index 000000000..4b221d423 --- /dev/null +++ b/assets/config_levels/2.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/assets/config_levels/3.xml b/assets/config_levels/3.xml new file mode 100644 index 000000000..fb90be299 --- /dev/null +++ b/assets/config_levels/3.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/config_levels/4.xml b/assets/config_levels/4.xml new file mode 100644 index 000000000..ad6f5a226 --- /dev/null +++ b/assets/config_levels/4.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/config_levels/5.xml b/assets/config_levels/5.xml new file mode 100644 index 000000000..e2a885fc7 --- /dev/null +++ b/assets/config_levels/5.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/psalm b/bin/psalm index 63632e103..0d99c3644 100755 --- a/bin/psalm +++ b/bin/psalm @@ -20,11 +20,11 @@ ini_set('xdebug.max_nesting_level', 512); // get options from command line $options = getopt( - 'f:mhc:', + 'f:mhc:i', [ 'help', 'debug', 'config:', 'monochrome', 'show-info:', 'diff', 'file:', 'self-check', 'update-docblocks', 'output-format:', - 'find-dead-code', + 'find-dead-code', 'init', ] ); @@ -32,6 +32,10 @@ if (array_key_exists('help', $options)) { $options['h'] = false; } +if (array_key_exists('init', $options)) { + $options['i'] = false; +} + if (array_key_exists('monochrome', $options)) { $options['m'] = false; } @@ -50,16 +54,39 @@ Usage: psalm [options] [file...] Options: - -h, --help Display this help message - --debug Debug information - -c, --config=psalm.xml Path to a psalm.xml configuration file - -m, --monochrome Enable monochrome output - --show-info[=BOOLEAN] Show non-exception parser findings. - --diff File to check is a diff - --self-check Psalm checks itself - --update-docblocks Adds correct return types to the given file(s) - --output-format=console Changes the output format - --find-dead-code Look for dead code + -h, --help + Display this help message + + -i, --init [source_dir=src] [--level=3] + Create a psalm config file in the current directory that points to [source_dir] + at the required level, from 1, most strict, to 5, most permissive + + --debug + Debug information + + -c, --config=psalm.xml + Path to a psalm.xml configuration file. Run psalm --init to create one. + + -m, --monochrome + Enable monochrome output + + --show-info[=BOOLEAN] + Show non-exception parser findings + + --diff + Runs Psalm in diff mode, only checking files that have changed (and their dependents) + + --self-check + Psalm checks itself + + --update-docblocks + Adds correct return types to the given file(s) + + --output-format=console + Changes the output format + + --find-dead-code + Look for dead code HELP; @@ -71,6 +98,58 @@ if (getcwd() === false) { die('Cannot get current working directory'); } +if (isset($options['i'])) { + $args = array_slice($argv, 2); + + if (file_exists('psalm.xml')) { + die('A config file already exists in the current directory' . PHP_EOL); + } + + $level = 3; + $source_dir = 'src'; + + if (count($args)) { + if (count($args) > 2) { + die('Too many arguments provided for psalm --init' . PHP_EOL); + } + + if (isset($args[1])) { + if (!preg_match('/^[1-5]$/', $args[1])) { + die('Config strictness must be a number between 1 and 5 inclusive' . PHP_EOL); + } + + $level = (int)$args[1]; + } + + if (!file_exists($args[0])) { + $bad_dir_path = getcwd() . DIRECTORY_SEPARATOR . $args[0]; + die('The given path ' . $bad_dir_path . ' does not appear to be a directory' . PHP_EOL); + } + + $source_dir = $args[0]; + } + + $template_file_name = 'assets/config_levels/' . $level . '.xml'; + + if (!file_exists($template_file_name)) { + die('Could not open config template' . PHP_EOL); + } + + $template = (string)file_get_contents($template_file_name); + + $template = str_replace(' + + ', ' + + ', $template); + + if (!file_put_contents('psalm.xml', $template)) { + die('Could not write to psalm.xml' . PHP_EOL); + } + + exit('Config file created successfully. Please re-run psalm.' . PHP_EOL); +} + // get vars from options $debug = array_key_exists('debug', $options); diff --git a/src/Psalm/Checker/ProjectChecker.php b/src/Psalm/Checker/ProjectChecker.php index cdf307f2b..875b9353d 100644 --- a/src/Psalm/Checker/ProjectChecker.php +++ b/src/Psalm/Checker/ProjectChecker.php @@ -823,6 +823,10 @@ class ProjectChecker } while (dirname($dir_path) !== $dir_path); if (!$config) { + if ($this->output_format === self::TYPE_CONSOLE) { + exit('Could not locate a config XML file in path ' . $path . '. Have you run \'psalm --init\' ?' . PHP_EOL); + } + throw new Exception\ConfigException('Config not found for path ' . $path); } @@ -858,6 +862,9 @@ class ProjectChecker } $this->config = Config::loadFromXMLFile($path_to_config); + + $this->config->visitStubFiles($this); + $this->config->initializePlugins($this); } /** diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index db7b86ba9..2ee9720e3 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -361,4 +361,15 @@ class ConfigTest extends PHPUnit_Framework_TestCase $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } + + /** + * @return void + */ + public function testTemplatedFiles() + { + foreach (['1.xml', '2.xml', '3.xml', '4.xml', '5.xml'] as $file_name) { + Config::loadFromXMLFile(realpath(dirname(__DIR__) . '/assets/config_levels/' . $file_name)); + } + + } }