diff --git a/changelog/lint.dd b/changelog/lint.dd new file mode 100644 index 0000000..d28bc9b --- /dev/null +++ b/changelog/lint.dd @@ -0,0 +1,9 @@ +Lint command added + +Dub supports now command `lint`, which will execute D-Scanner on the dub package. +By default `dub lint` will execute style check. Import paths to dependent dub +packages will be passed to D-Scanner. + +$(CONSOLE +> dub lint +) diff --git a/source/dub/commandline.d b/source/dub/commandline.d index a0e16c6..fc06a32 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -49,6 +49,7 @@ new RunCommand, new BuildCommand, new TestCommand, + new LintCommand, new GenerateCommand, new DescribeCommand, new CleanCommand, @@ -1042,6 +1043,88 @@ } } +class LintCommand : PackageBuildCommand { + private { + bool m_syntaxCheck = false; + bool m_styleCheck = false; + string m_errorFormat; + bool m_report = false; + string m_reportFormat; + string[] m_importPaths; + string m_config; + } + + this() + { + this.name = "lint"; + this.argumentsPattern = "[]"; + this.description = "Executes the linter tests of the selected package"; + this.helpText = [ + `Builds the package and executes D-Scanner linter tests.` + ]; + this.acceptsAppArgs = true; + } + + override void prepare(scope CommandArgs args) + { + args.getopt("syntax-check", &m_syntaxCheck, [ + "Lexes and parses sourceFile, printing the line and column number of " ~ + "any syntax errors to stdout." + ]); + + args.getopt("style-check", &m_styleCheck, [ + "Lexes and parses sourceFiles, printing the line and column number of " ~ + "any static analysis check failures stdout." + ]); + + args.getopt("error-format", &m_errorFormat, [ + "Format errors produced by the style/syntax checkers." + ]); + + args.getopt("report", &m_report, [ + "Generate a static analysis report in JSON format." + ]); + + args.getopt("report-format", &m_reportFormat, [ + "Specifies the format of the generated report." + ]); + + if (m_reportFormat) m_report = true; + + args.getopt("import-paths", &m_importPaths, [ + "Import paths" + ]); + + args.getopt("config", &m_config, [ + "Use the given configuration file." + ]); + + super.prepare(args); + } + + override int execute(Dub dub, string[] free_args, string[] app_args) + { + string package_name; + enforceUsage(free_args.length <= 1, "Expected one or zero arguments."); + if (free_args.length >= 1) package_name = free_args[0]; + + string[] args; + if (!m_syntaxCheck && !m_styleCheck && !m_report && app_args.length == 0) { m_styleCheck = true; } + + if (m_syntaxCheck) args ~= "--syntaxCheck"; + if (m_styleCheck) args ~= "--styleCheck"; + if (m_errorFormat) args ~= ["--errorFormat", m_errorFormat]; + if (m_report) args ~= "--report"; + if (m_reportFormat) args ~= ["--reportFormat", m_reportFormat]; + foreach (import_path; m_importPaths) args ~= ["-I", import_path]; + if (m_config) args ~= ["--config", m_config]; + + setupPackage(dub, package_name); + dub.lintProject(args ~ app_args); + return 0; + } +} + class DescribeCommand : PackageBuildCommand { private { bool m_importPaths = false; diff --git a/source/dub/dub.d b/source/dub/dub.d index c2b75d0..3f0d9ca 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -744,6 +744,53 @@ generator.generate(settings); } + /** Executes D-Scanner tests on the current project. **/ + void lintProject(string[] args) + { + import std.path : buildPath, buildNormalizedPath; + + if (m_dryRun) return; + + auto tool = "dscanner"; + + auto tool_pack = m_packageManager.getBestPackage(tool, ">=0.0.0"); + if (!tool_pack) tool_pack = m_packageManager.getBestPackage(tool, "~master"); + if (!tool_pack) { + logInfo("%s is not present, getting and storing it user wide", tool); + tool_pack = fetch(tool, Dependency(">=0.0.0"), defaultPlacementLocation, FetchOptions.none); + } + + auto dscanner_dub = new Dub(null, m_packageSuppliers); + dscanner_dub.loadPackage(tool_pack.path); + dscanner_dub.upgrade(UpgradeOptions.select); + + auto compiler_binary = this.defaultCompiler; + + GeneratorSettings settings; + settings.config = "application"; + settings.compiler = getCompiler(compiler_binary); + settings.platform = settings.compiler.determinePlatform(settings.buildSettings, compiler_binary, m_defaultArchitecture); + settings.buildType = "debug"; + settings.run = true; + + foreach (dependencyPackage; m_project.dependencies) + { + auto cfgs = m_project.getPackageConfigs(settings.platform, null, true); + auto buildSettings = dependencyPackage.getBuildSettings(settings.platform, cfgs[dependencyPackage.name]); + foreach (importPath; buildSettings.importPaths) { + settings.runArgs ~= ["-I", buildNormalizedPath(dependencyPackage.path.toNativeString(), importPath.idup)]; + } + } + + string configFilePath = buildPath(m_project.rootPackage.path.toNativeString(), "dscanner.ini"); + if (!args.canFind("--config") && exists(configFilePath)) { + settings.runArgs ~= ["--config", configFilePath]; + } + + settings.runArgs ~= args ~ [m_project.rootPackage.path.toNativeString()]; + dscanner_dub.generateProject("build", settings); + } + /** Prints the specified build settings necessary for building the root package. */ void listProjectData(GeneratorSettings settings, string[] requestedData, ListBuildSettingsFormat list_type) diff --git a/test/issue1773-lint.sh b/test/issue1773-lint.sh new file mode 100755 index 0000000..9a00262 --- /dev/null +++ b/test/issue1773-lint.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +. $(dirname "${BASH_SOURCE[0]}")/common.sh +DIR=$(dirname "${BASH_SOURCE[0]}") + +if ! { ${DUB} lint --root ${DIR}/issue1773-lint || true; } | grep -cF "Parameter args is never used."; then + die $LINENO 'DUB lint did not find expected warning.' +fi + diff --git a/test/issue1773-lint/.gitignore b/test/issue1773-lint/.gitignore new file mode 100644 index 0000000..304e955 --- /dev/null +++ b/test/issue1773-lint/.gitignore @@ -0,0 +1,8 @@ +.dub +docs.json +__dummy.html +docs/ +*.exe +*.o +*.obj +*.lst diff --git a/test/issue1773-lint/.no_build b/test/issue1773-lint/.no_build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1773-lint/.no_build diff --git a/test/issue1773-lint/dub.json b/test/issue1773-lint/dub.json new file mode 100644 index 0000000..016de7e --- /dev/null +++ b/test/issue1773-lint/dub.json @@ -0,0 +1,3 @@ +{ + "name": "test" +} \ No newline at end of file diff --git a/test/issue1773-lint/source/app.d b/test/issue1773-lint/source/app.d new file mode 100644 index 0000000..e1edea8 --- /dev/null +++ b/test/issue1773-lint/source/app.d @@ -0,0 +1,4 @@ +void main(string[] args) +{ + +} \ No newline at end of file