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));
+ }
+
+ }
}