Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'dub describe --data=' #572

Merged
merged 18 commits into from Jun 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f3c6639
Add 'dub describe --data='.
May 22, 2015
5c09ba4
Split --data=libs into two: --data=libs (for installed/system libs) a…
Jun 3, 2015
34e2969
Add 'dub describe --data-format=' to format the output of --data= dir…
Jun 5, 2015
bbf5183
Replace --data-format with --compiler and --data-list.
Jun 5, 2015
f8ac07e
Fixed: When formatting output for a compiler, if the package is a lib…
Jun 5, 2015
74a0106
Add --data-0 to output --data= info null-delimited for (ex.) xargs -0
Jun 14, 2015
6300036
Allow comma-separated list in --data, for brevity.
Jun 17, 2015
6085add
Replace 'getBuildSettingBitField' with 'to!BuildSetting'.
Jun 19, 2015
0e2356d
buildPath -> buildNormalizedPath
Jun 19, 2015
e997095
Make targetLookup return an index into targets[], instead of a redund…
Jun 19, 2015
33bf49a
Accidentally left in some old commented-out code.
Jun 19, 2015
1ecfcc2
Rework --data's handling of sourceFiles and static library dependencies.
Jun 21, 2015
b8a2ef8
Skip DMD-centric tests when DMD isn't available.
Jun 21, 2015
d6655e2
Again, rework --data's handling of sourceFiles and static library dep…
Jun 24, 2015
c0f0587
Change order of describe-data tests, list should run before dmd as it…
Jun 24, 2015
6950aae
TargetDescriptionGenerator: Don't add linker files to BuildSettings.s…
Abscissa Jun 25, 2015
a667601
Fixed: --data=linker-files misses linker files specified in dub.json.
Abscissa Jun 25, 2015
9a4f4e0
Fixed: Compile error on anything before DMD 2.067.
Abscissa Jun 26, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Expand Up @@ -20,3 +20,7 @@ __dummy.html
/test/ignore-hidden-2/ignore-hidden-2
/test/expected-import-path-output
/test/expected-string-import-path-output
/test/expected-describe-data-1-list-output
/test/expected-describe-data-2-dmd-output
/test/describe-project/dummy.dat
/test/describe-project/dummy-dep1.dat
62 changes: 52 additions & 10 deletions source/dub/commandline.d
Expand Up @@ -749,6 +749,9 @@ class DescribeCommand : PackageBuildCommand {
private {
bool m_importPaths = false;
bool m_stringImportPaths = false;
bool m_dataList = false;
bool m_dataNullDelim = false;
string[] m_data;
}

this()
Expand All @@ -761,14 +764,28 @@ 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, formatted for the current compiler).",
"",
"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. A comma-separated list is "
"also acceptable (ex: --data=dflags,libs). The data will be output in "
"the same order requested on the command line.",
"",
"The accepted values for --data=VALUE are:",
"",
"main-source-file, dflags, lflags, libs, linker-files, "
"source-files, versions, debug-versions, import-paths, "
"string-import-paths, import-files, options",
"",
"The following are also accepted by --data if --data-list is used:",
"",
"target-type, target-path, target-name, working-directory, "
"copy-files, string-import-files, pre-generate-commands,"
"post-generate-commands, pre-build-commands, post-build-commands, "
"requirements",
];
}

Expand All @@ -777,11 +794,28 @@ class DescribeCommand : PackageBuildCommand {
super.prepare(args);

args.getopt("import-paths", &m_importPaths, [
"List the import paths for project."
"Shortcut for --data=import-paths --data-list"
]);

args.getopt("string-import-paths", &m_stringImportPaths, [
"List the string import paths for project."
"Shortcut for --data=string-import-paths --data-list"
]);

args.getopt("data", &m_data, [
"Just list the values of a particular build setting, either for this "~
"package alone or recursively including all dependencies. Accepts a "~
"comma-separated list. See above for more details and accepted "~
"possibilities for VALUE."
]);

args.getopt("data-list", &m_dataList, [
"Output --data information in list format (line-by-line), instead "~
"of formatting for a compiler command line.",
]);

args.getopt("data-0", &m_dataNullDelim, [
"Output --data information using null-delimiters, rather than "~
"spaces or newlines. Result is usable with, ex., xargs -0.",
]);
}

Expand All @@ -792,6 +826,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 @@ -807,9 +846,12 @@ class DescribeCommand : PackageBuildCommand {
auto config = m_buildConfig.length ? m_buildConfig : m_defaultConfig;

if (m_importPaths) {
dub.listImportPaths(m_buildPlatform, config);
dub.listImportPaths(m_buildPlatform, config, m_buildType, m_dataNullDelim);
} else if (m_stringImportPaths) {
dub.listStringImportPaths(m_buildPlatform, config);
dub.listStringImportPaths(m_buildPlatform, config, m_buildType, m_dataNullDelim);
} else if (m_data) {
dub.listProjectData(m_buildPlatform, config, m_buildType, m_data,
m_dataList? null : m_compiler, m_dataNullDelim);
} else {
auto desc = dub.project.describe(m_buildPlatform, config, m_buildType);
writeln(desc.serializeToPrettyJson());
Expand Down
3 changes: 3 additions & 0 deletions source/dub/compilers/buildsettings.d
Expand Up @@ -28,6 +28,7 @@ struct BuildSettings {
string[] dflags;
string[] lflags;
string[] libs;
string[] linkerFiles;
string[] sourceFiles;
string[] copyFiles;
string[] versions;
Expand Down Expand Up @@ -63,6 +64,7 @@ struct BuildSettings {
addDFlags(bs.dflags);
addLFlags(bs.lflags);
addLibs(bs.libs);
addLinkerFiles(bs.linkerFiles);
addSourceFiles(bs.sourceFiles);
addCopyFiles(bs.copyFiles);
addVersions(bs.versions);
Expand All @@ -81,6 +83,7 @@ struct BuildSettings {
void removeDFlags(in string[] value...) { remove(dflags, value); }
void addLFlags(in string[] value...) { lflags ~= value; }
void addLibs(in string[] value...) { add(libs, value); }
void addLinkerFiles(in string[] value...) { add(linkerFiles, value); }
void addSourceFiles(in string[] value...) { add(sourceFiles, value); }
void prependSourceFiles(in string[] value...) { prepend(sourceFiles, value); }
void removeSourceFiles(in string[] value...) { removePaths(sourceFiles, value); }
Expand Down
7 changes: 7 additions & 0 deletions source/dub/description.d
Expand Up @@ -28,6 +28,13 @@ struct ProjectDescription {
string[] platform;
PackageDescription[] packages; /// All packages in the dependency tree
TargetDescription[] targets; /// Build targets
@ignore size_t[string] targetLookup; /// Target index by name

/// Targets by name
ref inout(TargetDescription) lookupTarget(string name) inout
{
return targets[ targetLookup[name] ];
}
}


Expand Down
29 changes: 25 additions & 4 deletions source/dub/dub.d
Expand Up @@ -421,24 +421,45 @@ class Dub {
writeln(desc.serializeToPrettyJson());
}

void listImportPaths(BuildPlatform platform, string config)
void listImportPaths(BuildPlatform platform, string config, string buildType, bool nullDelim)
{
import std.stdio;

foreach(path; m_project.listImportPaths(platform, config)) {
foreach(path; m_project.listImportPaths(platform, config, buildType, nullDelim)) {
writeln(path);
}
}

void listStringImportPaths(BuildPlatform platform, string config)
void listStringImportPaths(BuildPlatform platform, string config, string buildType, bool nullDelim)
{
import std.stdio;

foreach(path; m_project.listStringImportPaths(platform, config)) {
foreach(path; m_project.listStringImportPaths(platform, config, buildType, nullDelim)) {
writeln(path);
}
}

void listProjectData(BuildPlatform platform, string config, string buildType,
string[] requestedData, Compiler formattingCompiler, bool nullDelim)
{
import std.stdio;
import std.ascii : newline;

// Split comma-separated lists
string[] requestedDataSplit =
requestedData
.map!(a => a.splitter(",").map!strip)
.joiner()
.array();

auto data = m_project.listBuildSettings(platform, config, buildType,
requestedDataSplit, formattingCompiler, nullDelim);

write( data.joiner(nullDelim? "\0" : newline) );
if(!nullDelim)
writeln();
}

/// Cleans intermediate/cache files of the given package
void cleanPackage(Path path)
{
Expand Down
25 changes: 25 additions & 0 deletions source/dub/generators/targetdescription.d
Expand Up @@ -7,12 +7,16 @@
*/
module dub.generators.targetdescription;

import dub.compilers.buildsettings;
import dub.compilers.compiler;
import dub.description;
import dub.generators.generator;
import dub.internal.vibecompat.inet.path;
import dub.project;

class TargetDescriptionGenerator : ProjectGenerator {
TargetDescription[] targetDescriptions;
size_t[string] targetDescriptionLookup;

this(Project project)
{
Expand All @@ -21,17 +25,38 @@ class TargetDescriptionGenerator : ProjectGenerator {

protected override void generateTargets(GeneratorSettings settings, in TargetInfo[string] targets)
{
auto configs = m_project.getPackageConfigs(settings.platform, settings.config);
targetDescriptions.length = targets.length;
size_t i = 0;
size_t rootIndex;
foreach (t; targets) {
if (t.pack.name == m_project.rootPackage.name)
rootIndex = i;

TargetDescription d;
d.rootPackage = t.pack.name;
d.packages = t.packages.map!(p => p.name).array;
d.rootConfiguration = t.config;
d.buildSettings = t.buildSettings.dup;
d.dependencies = t.dependencies.dup;
d.linkDependencies = t.linkDependencies.dup;

targetDescriptionLookup[d.rootPackage] = i;
targetDescriptions[i++] = d;
}

// Add static library dependencies
auto bs = targetDescriptions[rootIndex].buildSettings;
foreach (ref desc; targetDescriptions) {
foreach (linkDepName; desc.linkDependencies) {
auto linkDepTarget = targetDescriptions[ targetDescriptionLookup[linkDepName] ];
auto dbs = linkDepTarget.buildSettings;
if (bs.targetType != TargetType.staticLibrary) {
auto linkerFile = (Path(dbs.targetPath) ~ getTargetFileName(dbs, settings.platform)).toNativeString();
bs.addLinkerFiles(linkerFile);
}
}
}
targetDescriptions[rootIndex].buildSettings = bs;
}
}
31 changes: 31 additions & 0 deletions source/dub/internal/utils.d
Expand Up @@ -21,6 +21,7 @@ import std.exception;
import std.file;
import std.process;
import std.string;
import std.traits : isIntegral;
import std.typecons;
import std.zip;
version(DubUseCurl) import std.net.curl;
Expand Down Expand Up @@ -253,3 +254,33 @@ auto fuzzySearch(R)(R strings, string input){
return strings.partition3!((a, b) => a.length + threshold < b.length)(input)[1]
.schwartzSort!(p => levenshteinDistance(input.toUpper, p.toUpper));
}

/**
If T is a bitfield-style enum, this function returns a string range
listing the names of all members included in the given value.

Example:
---------
enum Bits {
none = 0,
a = 1<<0,
b = 1<<1,
c = 1<<2,
a_c = a | c,
}

assert( bitFieldNames(Bits.none).equals(["none"]) );
assert( bitFieldNames(Bits.a).equals(["a"]) );
assert( bitFieldNames(Bits.a_c).equals(["a", "c", "a_c"]) );
---------
*/
auto bitFieldNames(T)(T value) if(is(T==enum) && isIntegral!T)
{
import std.algorithm : filter, map;
import std.conv : to;
import std.traits : EnumMembers;

return [ EnumMembers!(T) ]
.filter!(member => member==0? value==0 : (value & member) == member)
.map!(member => to!string(member));
}
4 changes: 2 additions & 2 deletions source/dub/package_.d
Expand Up @@ -364,14 +364,14 @@ class Package {
/** Returns a description of the package for use in IDEs or build tools.
*/
PackageDescription describe(BuildPlatform platform, string config)
{
const {
PackageDescription ret;
ret.path = m_path.toNativeString();
ret.name = this.name;
ret.version_ = this.ver;
ret.description = m_info.description;
ret.homepage = m_info.homepage;
ret.authors = m_info.authors;
ret.authors = m_info.authors.dup;
ret.copyright = m_info.copyright;
ret.license = m_info.license;
ret.dependencies = getDependencies(config).keys;
Expand Down