Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 46 additions & 8 deletions source/dub/commandline.d
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,7 @@ class DescribeCommand : PackageBuildCommand {
private {
bool m_importPaths = false;
bool m_stringImportPaths = false;
string[] m_data;
}

this()
Expand All @@ -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",
];
}

Expand All @@ -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."
]);
}

Expand All @@ -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);
Expand All @@ -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 {
dub.describeProject(m_buildPlatform, config);
}
Expand Down
9 changes: 9 additions & 0 deletions source/dub/dub.d
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,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)
{
Expand Down
123 changes: 106 additions & 17 deletions source/dub/project.d
Original file line number Diff line number Diff line change
Expand Up @@ -582,45 +582,134 @@ class Project {
}
}

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) {
// 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);
auto getPackageBuildSetting(Package pack) {
auto values = __traits(getMember, pack.getBuildSettings(platform, configs[pack.name]), attributeName);

//TODO: This needs redesigned to cleanly separate "handle the various
// data types from BuildSettings" from "fixup the paths"
static if(attributeName == "importPaths" || attributeName == "stringImportPaths")
{
// Return full paths for the import paths, making sure a
// directory separator is on the end of each path.
return values
.map!(importPath => buildPath(pack.path.toString(), importPath))
.map!(path => path.endsWith(dirSeparator) ? path : path ~ dirSeparator);
}
else static if(attributeName == "sourceFiles" || attributeName == "importFiles" || attributeName == "stringImportFiles")
{
// Return full paths.
return values
.map!(importPath => buildPath(pack.path.toString(), importPath));
}
else static if(attributeName == "targetPath" || attributeName == "workingDirectory")
{
// Return full path, making sure a
// directory separator is on the end of each path.
auto path = buildPath(pack.path.toString(), values);
return [path.endsWith(dirSeparator) ? path : path ~ dirSeparator];
}
else static if(attributeName == "mainSourceFile")
{
if(values.empty)
return null;

// Return full path.
return [ buildPath(pack.path.toString(), values) ];
}
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()
Expand Down