diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 5110c9c7a..9f49e53a4 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -749,6 +749,7 @@ class DescribeCommand : PackageBuildCommand { private { bool m_importPaths = false; bool m_stringImportPaths = false; + string[] m_data; } this() @@ -761,14 +762,38 @@ class DescribeCommand : PackageBuildCommand { "their dependencies in a format similar to a JSON package " "description file. This is useful mostly for IDEs.", "", - "When --import-paths is supplied, the import paths for a project ", - "will be printed line-by-line instead. The paths for D source " - "files across all dependent projects will be included.", + "All usual options that are also used for build/run/generate apply.", "", - "--string-import-paths can can supplied to print the string " - "import paths for a project.", + "When --data=VALUE is supplied, specific build settings for a project ", + "will be printed instead (by default, line-by-line). The VALUE must " + `be prefixed with either "recursive-" or "package-" to indicate ` + `whether to include dependencies ("recursive-") or just this ` + `package alone ("package-").`, "", - "All usual options that are also used for build/run/generate apply." + "The --data=VALUE option can be specified multiple times to retrieve " + "several pieces of information at once. The data will be output in " + "the same order requested on the command line.", + "", + "The accepted values for --data=VALUE are:", + "package-target-path, recursive-target-path", + "package-target-name, recursive-target-name", + "package-working-directory, recursive-working-directory", + "package-main-source-file, recursive-main-source-file", + "package-dflags, recursive-dflags", + "package-lflags, recursive-lflags", + "package-libs, recursive-libs", + "package-source-files, recursive-source-files", + "package-copy-files, recursive-copy-files", + "package-versions, recursive-versions", + "package-debug-versions, recursive-debug-versions", + "package-import-paths, recursive-import-paths", + "package-string-import-paths, recursive-string-import-paths", + "package-import-files, recursive-import-files", + "package-string-import-files, recursive-string-import-files", + "package-pre-generate-commands, recursive-pre-generate-commands", + "package-post-generate-commands, recursive-post-generate-commands", + "package-pre-build-commands, recursive-pre-build-commands", + "package-post-build-commands, recursive-post-build-commands", ]; } @@ -777,11 +802,17 @@ class DescribeCommand : PackageBuildCommand { super.prepare(args); args.getopt("import-paths", &m_importPaths, [ - "List the import paths for project." + "Shortcut for --data=recursive-import-paths" ]); args.getopt("string-import-paths", &m_stringImportPaths, [ - "List the string import paths for project." + "Shortcut for --data=recursive-string-import-paths" + ]); + + args.getopt("data", &m_data, [ + "Just list the values of a particular build setting, either for this "~ + "package alone or recursively including all dependencies. See "~ + "above for more details and accepted possibilities for VALUE." ]); } @@ -792,6 +823,11 @@ class DescribeCommand : PackageBuildCommand { "--import-paths and --string-import-paths may not be used together." ); + enforceUsage( + !(m_data && (m_importPaths || m_stringImportPaths)), + "--data may not be used together with --import-paths or --string-import-paths." + ); + // disable all log output and use "writeln" to output the JSON description auto ll = getLogLevel(); setLogLevel(LogLevel.none); @@ -810,6 +846,8 @@ class DescribeCommand : PackageBuildCommand { dub.listImportPaths(m_buildPlatform, config); } else if (m_stringImportPaths) { dub.listStringImportPaths(m_buildPlatform, config); + } else if (m_data) { + dub.listProjectData(m_buildPlatform, config, m_data); } else { auto desc = dub.project.describe(m_buildPlatform, config, m_buildType); writeln(desc.serializeToPrettyJson()); diff --git a/source/dub/dub.d b/source/dub/dub.d index 9e0329abd..d0cf7c13c 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -439,6 +439,15 @@ class Dub { } } + void listProjectData(BuildPlatform platform, string config, string[] requestedData) + { + import std.stdio; + + foreach(data; m_project.listBuildSettings(platform, config, requestedData)) { + writeln(data); + } + } + /// Cleans intermediate/cache files of the given package void cleanPackage(Path path) { diff --git a/source/dub/project.d b/source/dub/project.d index 027326337..15f80fa49 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -609,45 +609,111 @@ class Project { dst[key] = value; } - private string[] listPaths(string attributeName)(BuildPlatform platform, string config) + // recursive: Should settings from dependencies be included? + private string[] listBuildSetting(string attributeName)(BuildPlatform platform, string config, bool recursive=true) + { + return listBuildSetting!attributeName(platform, getPackageConfigs(platform, config), recursive); + } + + private string[] listBuildSetting(string attributeName)(BuildPlatform platform, string[string] configs, bool recursive=true) { import std.path : buildPath, dirSeparator; - - auto configs = getPackageConfigs(platform, config); + import std.traits : isArray; string[] list; - auto fullPackagePaths(Package pack) { + auto getPackageBuildSetting(Package pack) { + auto values = __traits(getMember, pack.getBuildSettings(platform, configs[pack.name]), attributeName); + // Return full paths for the import paths, making sure a // directory separator is on the end of each path. - return __traits(getMember, pack.getBuildSettings(platform, configs[pack.name]), attributeName) - .map!(importPath => buildPath(pack.path.toString(), importPath)) - .map!(path => path.endsWith(dirSeparator) ? path : path ~ dirSeparator); + static if(attributeName == "importPaths" || attributeName == "stringImportPaths") + { + return values + .map!(importPath => buildPath(pack.path.toString(), importPath)) + .map!(path => path.endsWith(dirSeparator) ? path : path ~ dirSeparator); + } + else static if( is(typeof(values) == string[]) ) // Is a string[]? + return values; + else + return values.empty()? null : [values]; } - foreach(path; fullPackagePaths(m_rootPackage)) { - list ~= path; + foreach(value; getPackageBuildSetting(m_rootPackage)) { + list ~= value; } - foreach (dep; m_dependencies) { - foreach(path; fullPackagePaths(dep)) { - list ~= path; + if(recursive) { + foreach(dep; m_dependencies) { + foreach(value; getPackageBuildSetting(dep)) { + list ~= value; + } } } return list; } + // requestedData is of the form "package-(attr-name)" or "recursive-(attr-name)", + // for example: "package-main-source-file" or "recursive-import-paths" + private string[] listBuildSetting(BuildPlatform platform, string[string] configs, string requestedData) + { + auto requestedDataParts = requestedData.findSplit("-"); + enforce(requestedDataParts[0] == "package" || requestedDataParts[0] == "recursive", + "The name of requested data, '"~requestedData~"', doesn't begin with 'package-' or 'recursive-' as required."); + + bool recursive = requestedDataParts[0] == "recursive"; + switch(requestedDataParts[2]) + { + case "target-path": return listBuildSetting!"targetPath"(platform, configs, recursive); + case "target-name": return listBuildSetting!"targetName"(platform, configs, recursive); + case "working-directory": return listBuildSetting!"workingDirectory"(platform, configs, recursive); + case "main-source-file": return listBuildSetting!"mainSourceFile"(platform, configs, recursive); + case "dflags": return listBuildSetting!"dflags"(platform, configs, recursive); + case "lflags": return listBuildSetting!"lflags"(platform, configs, recursive); + case "libs": return listBuildSetting!"libs"(platform, configs, recursive); + case "source-files": return listBuildSetting!"sourceFiles"(platform, configs, recursive); + case "copy-files": return listBuildSetting!"copyFiles"(platform, configs, recursive); + case "versions": return listBuildSetting!"versions"(platform, configs, recursive); + case "debug-versions": return listBuildSetting!"debugVersions"(platform, configs, recursive); + case "import-paths": return listBuildSetting!"importPaths"(platform, configs, recursive); + case "string-import-paths": return listBuildSetting!"stringImportPaths"(platform, configs, recursive); + case "import-files": return listBuildSetting!"importFiles"(platform, configs, recursive); + case "string-import-files": return listBuildSetting!"stringImportFiles"(platform, configs, recursive); + case "pre-generate-commands": return listBuildSetting!"preGenerateCommands"(platform, configs, recursive); + case "post-generate-commands": return listBuildSetting!"postGenerateCommands"(platform, configs, recursive); + case "pre-build-commands": return listBuildSetting!"preBuildCommands"(platform, configs, recursive); + case "post-build-commands": return listBuildSetting!"postBuildCommands"(platform, configs, recursive); + + default: + enforce(false, "'"~requestedData~ + "' is not a valid name for requested data. See 'dub describe --help' for accepted values."); + } + + assert(0); + } + + /// Outputs requested data for the project, optionally including its dependencies. + string[] listBuildSettings(BuildPlatform platform, string config, string[] requestedData) + { + auto configs = getPackageConfigs(platform, config); + + return requestedData + .map!(dataName => listBuildSetting(platform, configs, dataName)) + .joiner([""]) // Blank line between each type of requestedData + .array(); + } + /// Outputs the import paths for the project, including its dependencies. - string [] listImportPaths(BuildPlatform platform, string config) + string[] listImportPaths(BuildPlatform platform, string config) { - return listPaths!"importPaths"(platform, config); + return listBuildSetting!"importPaths"(platform, config); } /// Outputs the string import paths for the project, including its dependencies. string[] listStringImportPaths(BuildPlatform platform, string config) { - return listPaths!"stringImportPaths"(platform, config); + return listBuildSetting!"stringImportPaths"(platform, config); } void saveSelections()