diff --git a/changelog/add_env.dd b/changelog/add_env.dd
new file mode 100644
index 0000000..c75ef7a
--- /dev/null
+++ b/changelog/add_env.dd
@@ -0,0 +1,29 @@
+Added support for environment variables to use compilation and run(or test) option to the $(LINK2 https://dub.pm/settings, dub settings file) and dub.json/dub.sdl.
+
+The following items have been added to the dub setting file: `defaultEnvironments`, `defaultBuildEnvironments`, `defaultRunEnvironments`, `defaultPreGenerateEnvironments`, `defaultPostGenerateEnvironments`, `defaultPreBuildEnvironments`, `defaultPostBuildEnvironments`, `defaultPreRunEnvironments`, `defaultPostRunEnvironments`.
+They are used when there are no project-specific settings.
+
+```
+{
+ "defaultEnvironments": {
+ "VAR": "Foo"
+ }
+}
+```
+
+The following items are available in each project-specific setting: `environments`, `buildEnvironments`, `runEnvironments`, `preGenerateEnvironments`, `postGenerateEnvironments`, `preBuildEnvironments`, `postBuildEnvironments`, `preRunEnvironments`, `postRunEnvironments`.
+
+In JSON
+```
+{
+ "environments": {
+ "VAR": "Foo"
+ }
+}
+```
+
+In SDL
+```
+environments "VAR" "Foo"
+```
+
diff --git a/source/dub/commandline.d b/source/dub/commandline.d
index 7a799d2..5b62fe6 100644
--- a/source/dub/commandline.d
+++ b/source/dub/commandline.d
@@ -999,6 +999,15 @@
if (!m_compilerName.length) m_compilerName = dub.defaultCompiler;
if (!m_arch.length) m_arch = dub.defaultArchitecture;
if (dub.defaultLowMemory) m_buildSettings.options |= BuildOption.lowmem;
+ if (dub.defaultEnvironments) m_buildSettings.addEnvironments(dub.defaultEnvironments);
+ if (dub.defaultBuildEnvironments) m_buildSettings.addBuildEnvironments(dub.defaultBuildEnvironments);
+ if (dub.defaultRunEnvironments) m_buildSettings.addRunEnvironments(dub.defaultRunEnvironments);
+ if (dub.defaultPreGenerateEnvironments) m_buildSettings.addPreGenerateEnvironments(dub.defaultPreGenerateEnvironments);
+ if (dub.defaultPostGenerateEnvironments) m_buildSettings.addPostGenerateEnvironments(dub.defaultPostGenerateEnvironments);
+ if (dub.defaultPreBuildEnvironments) m_buildSettings.addPreBuildEnvironments(dub.defaultPreBuildEnvironments);
+ if (dub.defaultPostBuildEnvironments) m_buildSettings.addPostBuildEnvironments(dub.defaultPostBuildEnvironments);
+ if (dub.defaultPreRunEnvironments) m_buildSettings.addPreRunEnvironments(dub.defaultPreRunEnvironments);
+ if (dub.defaultPostRunEnvironments) m_buildSettings.addPostRunEnvironments(dub.defaultPostRunEnvironments);
m_compiler = getCompiler(m_compilerName);
m_buildPlatform = m_compiler.determinePlatform(m_buildSettings, m_compilerName, m_arch);
m_buildSettings.addDebugVersions(m_debugVersions);
diff --git a/source/dub/compilers/buildsettings.d b/source/dub/compilers/buildsettings.d
index 49965e7..594d38f 100644
--- a/source/dub/compilers/buildsettings.d
+++ b/source/dub/compilers/buildsettings.d
@@ -13,7 +13,8 @@
import std.algorithm : filter, any;
import std.path : globMatch;
import std.typecons : BitFlags;
-
+import std.algorithm.iteration : uniq;
+import std.range : chain;
/// BuildPlatform specific settings, like needed libraries or additional
/// include paths.
@@ -46,17 +47,33 @@
string[] postBuildCommands;
string[] preRunCommands;
string[] postRunCommands;
+ string[string] environments;
+ string[string] buildEnvironments;
+ string[string] runEnvironments;
+ string[string] preGenerateEnvironments;
+ string[string] postGenerateEnvironments;
+ string[string] preBuildEnvironments;
+ string[string] postBuildEnvironments;
+ string[string] preRunEnvironments;
+ string[string] postRunEnvironments;
@byName BuildRequirements requirements;
@byName BuildOptions options;
BuildSettings dup()
const {
+ import std.traits: FieldNameTuple;
+ import std.algorithm: map;
+ import std.typecons: tuple;
+ import std.array: assocArray;
BuildSettings ret;
- foreach (m; __traits(allMembers, BuildSettings)) {
+ foreach (m; FieldNameTuple!BuildSettings) {
static if (is(typeof(__traits(getMember, ret, m) = __traits(getMember, this, m).dup)))
__traits(getMember, ret, m) = __traits(getMember, this, m).dup;
+ else static if (is(typeof(add(__traits(getMember, ret, m), __traits(getMember, this, m)))))
+ add(__traits(getMember, ret, m), __traits(getMember, this, m));
else static if (is(typeof(__traits(getMember, ret, m) = __traits(getMember, this, m))))
__traits(getMember, ret, m) = __traits(getMember, this, m);
+ else static assert(0, "Cannot duplicate BuildSettings." ~ m);
}
assert(ret.targetType == targetType);
assert(ret.targetName == targetName);
@@ -89,7 +106,7 @@
addPostRunCommands(bs.postRunCommands);
}
- void addDFlags(in string[] value...) { dflags ~= value; }
+ void addDFlags(in string[] value...) { dflags = chain(dflags, value.dup).uniq.array; }
void prependDFlags(in string[] value...) { prepend(dflags, value); }
void removeDFlags(in string[] value...) { remove(dflags, value); }
void addLFlags(in string[] value...) { lflags ~= value; }
@@ -115,6 +132,24 @@
void addPostBuildCommands(in string[] value...) { add(postBuildCommands, value, false); }
void addPreRunCommands(in string[] value...) { add(preRunCommands, value, false); }
void addPostRunCommands(in string[] value...) { add(postRunCommands, value, false); }
+ void addEnvironments(in string[string] value) { add(environments, value); }
+ void updateEnvironments(in string[string] value) { update(environments, value); }
+ void addBuildEnvironments(in string[string] value) { add(buildEnvironments, value); }
+ void updateBuildEnvironments(in string[string] value) { update(buildEnvironments, value); }
+ void addRunEnvironments(in string[string] value) { add(runEnvironments, value); }
+ void updateRunEnvironments(in string[string] value) { update(runEnvironments, value); }
+ void addPreGenerateEnvironments(in string[string] value) { add(preGenerateEnvironments, value); }
+ void updatePreGenerateEnvironments(in string[string] value) { update(preGenerateEnvironments, value); }
+ void addPostGenerateEnvironments(in string[string] value) { add(postGenerateEnvironments, value); }
+ void updatePostGenerateEnvironments(in string[string] value) { update(postGenerateEnvironments, value); }
+ void addPreBuildEnvironments(in string[string] value) { add(preBuildEnvironments, value); }
+ void updatePreBuildEnvironments(in string[string] value) { update(preBuildEnvironments, value); }
+ void addPostBuildEnvironments(in string[string] value) { add(postBuildEnvironments, value); }
+ void updatePostBuildEnvironments(in string[string] value) { update(postBuildEnvironments, value); }
+ void addPreRunEnvironments(in string[string] value) { add(preRunEnvironments, value); }
+ void updatePreRunEnvironments(in string[string] value) { update(preRunEnvironments, value); }
+ void addPostRunEnvironments(in string[string] value) { add(postRunEnvironments, value); }
+ void updatePostRunEnvironments(in string[string] value) { update(postRunEnvironments, value); }
void addRequirements(in BuildRequirement[] value...) { foreach (v; value) this.requirements |= v; }
void addRequirements(in BuildRequirements value) { this.requirements |= value; }
void addOptions(in BuildOption[] value...) { foreach (v; value) this.options |= v; }
@@ -137,6 +172,21 @@
foreach (val; vals)
arr ~= filterDuplicates(arr, [val], noDuplicates);
}
+ // Append vals to AA
+ static void add(ref string[string] aa, in string[string] vals)
+ {
+ // vals might contain duplicated keys, add each val individually
+ foreach (key, val; vals)
+ if (key !in aa)
+ aa[key] = val;
+ }
+ // Update vals to AA
+ static void update(ref string[string] aa, in string[string] vals)
+ {
+ // If there are duplicate keys, they will be ignored and overwritten.
+ foreach (key, val; vals)
+ aa[key] = val;
+ }
unittest
{
diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d
index 80331c5..72e0aeb 100644
--- a/source/dub/compilers/compiler.d
+++ b/source/dub/compilers/compiler.d
@@ -95,17 +95,17 @@
This method should be used by `Compiler` implementations to invoke the
compiler or linker binary.
*/
- protected final void invokeTool(string[] args, void delegate(int, string) output_callback)
+ protected final void invokeTool(string[] args, void delegate(int, string) output_callback, string[string] env = null)
{
import std.string;
int status;
if (output_callback) {
- auto result = executeShell(escapeShellCommand(args));
+ auto result = executeShell(escapeShellCommand(args), env);
output_callback(result.status, result.output);
status = result.status;
} else {
- auto compiler_pid = spawnShell(escapeShellCommand(args));
+ auto compiler_pid = spawnShell(escapeShellCommand(args), env);
status = compiler_pid.wait();
}
diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d
index add0308..1263f13 100644
--- a/source/dub/compilers/dmd.d
+++ b/source/dub/compilers/dmd.d
@@ -318,7 +318,11 @@
std.file.write(res_file.toNativeString(), escapeArgs(args).join("\n"));
logDiagnostic("%s %s", platform.compilerBinary, escapeArgs(args).join(" "));
- invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback);
+ string[string] env;
+ foreach (aa; [settings.environments, settings.buildEnvironments])
+ foreach (k, v; aa)
+ env[k] = v;
+ invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env);
}
void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback)
@@ -343,7 +347,11 @@
std.file.write(res_file.toNativeString(), escapeArgs(args).join("\n"));
logDiagnostic("%s %s", platform.compilerBinary, escapeArgs(args).join(" "));
- invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback);
+ string[string] env;
+ foreach (aa; [settings.environments, settings.buildEnvironments])
+ foreach (k, v; aa)
+ env[k] = v;
+ invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env);
}
string[] lflagsToDFlags(in string[] lflags) const
diff --git a/source/dub/compilers/gdc.d b/source/dub/compilers/gdc.d
index f615cbb..4f2afcd 100644
--- a/source/dub/compilers/gdc.d
+++ b/source/dub/compilers/gdc.d
@@ -206,7 +206,11 @@
std.file.write(res_file.toNativeString(), join(settings.dflags.map!(s => escape(s)), "\n"));
logDiagnostic("%s %s", platform.compilerBinary, join(cast(string[])settings.dflags, " "));
- invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback);
+ string[string] env;
+ foreach (aa; [settings.environments, settings.buildEnvironments])
+ foreach (k, v; aa)
+ env[k] = v;
+ invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env);
}
void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback)
@@ -224,7 +228,11 @@
args ~= "-L--no-as-needed"; // avoids linker errors due to libraries being specified in the wrong order
}
logDiagnostic("%s", args.join(" "));
- invokeTool(args, output_callback);
+ string[string] env;
+ foreach (aa; [settings.environments, settings.buildEnvironments])
+ foreach (k, v; aa)
+ env[k] = v;
+ invokeTool(args, output_callback, env);
}
string[] lflagsToDFlags(in string[] lflags) const
diff --git a/source/dub/compilers/ldc.d b/source/dub/compilers/ldc.d
index 18a4c47..5ddabe7 100644
--- a/source/dub/compilers/ldc.d
+++ b/source/dub/compilers/ldc.d
@@ -237,7 +237,11 @@
std.file.write(res_file.toNativeString(), escapeArgs(args).join("\n"));
logDiagnostic("%s %s", platform.compilerBinary, escapeArgs(args).join(" "));
- invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback);
+ string[string] env;
+ foreach (aa; [settings.environments, settings.buildEnvironments])
+ foreach (k, v; aa)
+ env[k] = v;
+ invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env);
}
void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback)
@@ -256,7 +260,11 @@
std.file.write(res_file.toNativeString(), escapeArgs(args).join("\n"));
logDiagnostic("%s %s", platform.compilerBinary, escapeArgs(args).join(" "));
- invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback);
+ string[string] env;
+ foreach (aa; [settings.environments, settings.buildEnvironments])
+ foreach (k, v; aa)
+ env[k] = v;
+ invokeTool([platform.compilerBinary, "@"~res_file.toNativeString()], output_callback, env);
}
string[] lflagsToDFlags(in string[] lflags) const
diff --git a/source/dub/description.d b/source/dub/description.d
index 7758751..2953107 100644
--- a/source/dub/description.d
+++ b/source/dub/description.d
@@ -96,6 +96,15 @@
string[] postBuildCommands; /// Commands to execute after every build
string[] preRunCommands; /// Commands to execute prior to every run
string[] postRunCommands; /// Commands to execute after every run
+ string[string] environments;
+ string[string] buildEnvironments;
+ string[string] runEnvironments;
+ string[string] preGenerateEnvironments;
+ string[string] postGenerateEnvironments;
+ string[string] preBuildEnvironments;
+ string[string] postBuildEnvironments;
+ string[string] preRunEnvironments;
+ string[string] postRunEnvironments;
@byName BuildRequirement[] buildRequirements;
@byName BuildOption[] options;
SourceFileDescription[] files; /// A list of all source/import files possibly used by the package
diff --git a/source/dub/dub.d b/source/dub/dub.d
index 3bfb042..4b8711a 100644
--- a/source/dub/dub.d
+++ b/source/dub/dub.d
@@ -133,6 +133,16 @@
string m_defaultCompiler;
string m_defaultArchitecture;
bool m_defaultLowMemory;
+ string[string] m_defaultEnvironments;
+ string[string] m_defaultBuildEnvironments;
+ string[string] m_defaultRunEnvironments;
+ string[string] m_defaultPreGenerateEnvironments;
+ string[string] m_defaultPostGenerateEnvironments;
+ string[string] m_defaultPreBuildEnvironments;
+ string[string] m_defaultPostBuildEnvironments;
+ string[string] m_defaultPreRunEnvironments;
+ string[string] m_defaultPostRunEnvironments;
+
}
/** The default placement location of fetched packages.
@@ -290,6 +300,15 @@
m_defaultArchitecture = m_config.defaultArchitecture;
m_defaultLowMemory = m_config.defaultLowMemory;
+ m_defaultEnvironments = m_config.defaultEnvironments;
+ m_defaultBuildEnvironments = m_config.defaultBuildEnvironments;
+ m_defaultRunEnvironments = m_config.defaultRunEnvironments;
+ m_defaultPreGenerateEnvironments = m_config.defaultPreGenerateEnvironments;
+ m_defaultPostGenerateEnvironments = m_config.defaultPostGenerateEnvironments;
+ m_defaultPreBuildEnvironments = m_config.defaultPreBuildEnvironments;
+ m_defaultPostBuildEnvironments = m_config.defaultPostBuildEnvironments;
+ m_defaultPreRunEnvironments = m_config.defaultPreRunEnvironments;
+ m_defaultPostRunEnvironments = m_config.defaultPostRunEnvironments;
}
@property void dryRun(bool v) { m_dryRun = v; }
@@ -340,6 +359,16 @@
configuration file will be used. Otherwise false will be returned.
*/
@property bool defaultLowMemory() const { return m_defaultLowMemory; }
+
+ @property const(string[string]) defaultEnvironments() const { return m_defaultEnvironments; }
+ @property const(string[string]) defaultBuildEnvironments() const { return m_defaultBuildEnvironments; }
+ @property const(string[string]) defaultRunEnvironments() const { return m_defaultRunEnvironments; }
+ @property const(string[string]) defaultPreGenerateEnvironments() const { return m_defaultPreGenerateEnvironments; }
+ @property const(string[string]) defaultPostGenerateEnvironments() const { return m_defaultPostGenerateEnvironments; }
+ @property const(string[string]) defaultPreBuildEnvironments() const { return m_defaultPreBuildEnvironments; }
+ @property const(string[string]) defaultPostBuildEnvironments() const { return m_defaultPostBuildEnvironments; }
+ @property const(string[string]) defaultPreRunEnvironments() const { return m_defaultPreRunEnvironments; }
+ @property const(string[string]) defaultPostRunEnvironments() const { return m_defaultPostRunEnvironments; }
/** Loads the package that resides within the configured `rootPath`.
*/
@@ -431,6 +460,7 @@
auto recipe_default_package_name = path.toString.baseName.stripExtension.strip;
auto recipe = parsePackageRecipe(recipe_content, recipe_filename, null, recipe_default_package_name);
+ import dub.internal.vibecompat.core.log; logInfo("parsePackageRecipe %s", recipe_filename);
enforce(recipe.buildSettings.sourceFiles.length == 0, "Single-file packages are not allowed to specify source files.");
enforce(recipe.buildSettings.sourcePaths.length == 0, "Single-file packages are not allowed to specify source paths.");
enforce(recipe.buildSettings.importPaths.length == 0, "Single-file packages are not allowed to specify import paths.");
@@ -686,7 +716,7 @@
if (fname == "package.d") {
if (firstTimePackage) {
firstTimePackage = false;
- logWarn("Excluding package.d file from test due to https://issues.dlang.org/show_bug.cgi?id=11847");
+ logDiagnostic("Excluding package.d file from test due to https://issues.dlang.org/show_bug.cgi?id=11847");
}
continue;
}
@@ -779,6 +809,15 @@
settings.platform = settings.compiler.determinePlatform(settings.buildSettings, compiler_binary, m_defaultArchitecture);
settings.buildType = "debug";
if (m_defaultLowMemory) settings.buildSettings.options |= BuildOption.lowmem;
+ if (m_defaultEnvironments) settings.buildSettings.addEnvironments(m_defaultEnvironments);
+ if (m_defaultBuildEnvironments) settings.buildSettings.addBuildEnvironments(m_defaultBuildEnvironments);
+ if (m_defaultRunEnvironments) settings.buildSettings.addRunEnvironments(m_defaultRunEnvironments);
+ if (m_defaultPreGenerateEnvironments) settings.buildSettings.addPreGenerateEnvironments(m_defaultPreGenerateEnvironments);
+ if (m_defaultPostGenerateEnvironments) settings.buildSettings.addPostGenerateEnvironments(m_defaultPostGenerateEnvironments);
+ if (m_defaultPreBuildEnvironments) settings.buildSettings.addPreBuildEnvironments(m_defaultPreBuildEnvironments);
+ if (m_defaultPostBuildEnvironments) settings.buildSettings.addPostBuildEnvironments(m_defaultPostBuildEnvironments);
+ if (m_defaultPreRunEnvironments) settings.buildSettings.addPreRunEnvironments(m_defaultPreRunEnvironments);
+ if (m_defaultPostRunEnvironments) settings.buildSettings.addPostRunEnvironments(m_defaultPostRunEnvironments);
settings.run = true;
foreach (dependencyPackage; m_project.dependencies)
@@ -1276,6 +1315,15 @@
settings.run = true;
settings.runArgs = runArgs;
if (m_defaultLowMemory) settings.buildSettings.options |= BuildOption.lowmem;
+ if (m_defaultEnvironments) settings.buildSettings.addEnvironments(m_defaultEnvironments);
+ if (m_defaultBuildEnvironments) settings.buildSettings.addBuildEnvironments(m_defaultBuildEnvironments);
+ if (m_defaultRunEnvironments) settings.buildSettings.addRunEnvironments(m_defaultRunEnvironments);
+ if (m_defaultPreGenerateEnvironments) settings.buildSettings.addPreGenerateEnvironments(m_defaultPreGenerateEnvironments);
+ if (m_defaultPostGenerateEnvironments) settings.buildSettings.addPostGenerateEnvironments(m_defaultPostGenerateEnvironments);
+ if (m_defaultPreBuildEnvironments) settings.buildSettings.addPreBuildEnvironments(m_defaultPreBuildEnvironments);
+ if (m_defaultPostBuildEnvironments) settings.buildSettings.addPostBuildEnvironments(m_defaultPostBuildEnvironments);
+ if (m_defaultPreRunEnvironments) settings.buildSettings.addPreRunEnvironments(m_defaultPreRunEnvironments);
+ if (m_defaultPostRunEnvironments) settings.buildSettings.addPostRunEnvironments(m_defaultPostRunEnvironments);
initSubPackage.recipe.buildSettings.workingDirectory = path.toNativeString();
template_dub.generateProject("build", settings);
}
@@ -1347,6 +1395,15 @@
settings.platform = settings.compiler.determinePlatform(settings.buildSettings, compiler_binary, m_defaultArchitecture);
settings.buildType = "debug";
if (m_defaultLowMemory) settings.buildSettings.options |= BuildOption.lowmem;
+ if (m_defaultEnvironments) settings.buildSettings.addEnvironments(m_defaultEnvironments);
+ if (m_defaultBuildEnvironments) settings.buildSettings.addBuildEnvironments(m_defaultBuildEnvironments);
+ if (m_defaultRunEnvironments) settings.buildSettings.addRunEnvironments(m_defaultRunEnvironments);
+ if (m_defaultPreGenerateEnvironments) settings.buildSettings.addPreGenerateEnvironments(m_defaultPreGenerateEnvironments);
+ if (m_defaultPostGenerateEnvironments) settings.buildSettings.addPostGenerateEnvironments(m_defaultPostGenerateEnvironments);
+ if (m_defaultPreBuildEnvironments) settings.buildSettings.addPreBuildEnvironments(m_defaultPreBuildEnvironments);
+ if (m_defaultPostBuildEnvironments) settings.buildSettings.addPostBuildEnvironments(m_defaultPostBuildEnvironments);
+ if (m_defaultPreRunEnvironments) settings.buildSettings.addPreRunEnvironments(m_defaultPreRunEnvironments);
+ if (m_defaultPostRunEnvironments) settings.buildSettings.addPostRunEnvironments(m_defaultPostRunEnvironments);
settings.run = true;
auto filterargs = m_project.rootPackage.recipe.ddoxFilterArgs.dup;
@@ -1445,11 +1502,67 @@
// If nothing found next to dub, search the user's PATH, starting
// with the compiler name from their DUB config file, if specified.
- if (m_defaultCompiler.length)
- compilers = m_defaultCompiler ~ compilers;
auto paths = environment.get("PATH", "").splitter(sep).map!NativePath;
- auto res = compilers.find!(bin => paths.canFind!(p => existsFile(p ~ (bin~exe))));
- m_defaultCompiler = res.empty ? compilers[0] : res.front;
+ if (m_defaultCompiler.length && paths.canFind!(p => existsFile(p ~ (m_defaultCompiler~exe))))
+ return;
+ foreach (p; paths) {
+ auto res = compilers.find!(bin => existsFile(p ~ (bin~exe)));
+ if (!res.empty) {
+ m_defaultCompiler = res.front;
+ return;
+ }
+ }
+ m_defaultCompiler = compilers[0];
+ }
+
+ unittest
+ {
+ import std.path: buildPath, absolutePath;
+ auto dub = new Dub(".", null, SkipPackageSuppliers.configured);
+ immutable olddc = environment.get("DC", null);
+ immutable oldpath = environment.get("PATH", null);
+ immutable testdir = "test-determineDefaultCompiler";
+ void repairenv(string name, string var)
+ {
+ if (var !is null)
+ environment[name] = var;
+ else if (name in environment)
+ environment.remove(name);
+ }
+ scope (exit) repairenv("DC", olddc);
+ scope (exit) repairenv("PATH", oldpath);
+ scope (exit) rmdirRecurse(testdir);
+
+ version (Windows) enum sep = ";", exe = ".exe";
+ version (Posix) enum sep = ":", exe = "";
+
+ immutable dmdpath = testdir.buildPath("dmd", "bin");
+ immutable ldcpath = testdir.buildPath("ldc", "bin");
+ mkdirRecurse(dmdpath);
+ mkdirRecurse(ldcpath);
+ immutable dmdbin = dmdpath.buildPath("dmd"~exe);
+ immutable ldcbin = ldcpath.buildPath("ldc2"~exe);
+ std.file.write(dmdbin, null);
+ std.file.write(ldcbin, null);
+
+ environment["DC"] = dmdbin.absolutePath();
+ dub.determineDefaultCompiler();
+ assert(dub.m_defaultCompiler == dmdbin.absolutePath());
+
+ environment["DC"] = "dmd";
+ environment["PATH"] = dmdpath ~ sep ~ ldcpath;
+ dub.determineDefaultCompiler();
+ assert(dub.m_defaultCompiler == "dmd");
+
+ environment["DC"] = "ldc2";
+ environment["PATH"] = dmdpath ~ sep ~ ldcpath;
+ dub.determineDefaultCompiler();
+ assert(dub.m_defaultCompiler == "ldc2");
+
+ environment.remove("DC");
+ environment["PATH"] = ldcpath ~ sep ~ dmdpath;
+ dub.determineDefaultCompiler();
+ assert(dub.m_defaultCompiler == "ldc2");
}
private NativePath makeAbsolute(NativePath p) const { return p.absolute ? p : m_rootPath ~ p; }
@@ -1857,4 +1970,76 @@
if (m_parentConfig) return m_parentConfig.defaultLowMemory;
return false;
}
+
+ @property string[string] defaultEnvironments()
+ const {
+ if (auto pv = "defaultEnvironments" in m_data)
+ return deserializeJson!(string[string])(*cast(Json*)pv);
+ if (m_parentConfig) return m_parentConfig.defaultEnvironments;
+ return null;
+ }
+
+ @property string[string] defaultBuildEnvironments()
+ const {
+ if (auto pv = "defaultBuildEnvironments" in m_data)
+ return deserializeJson!(string[string])(*cast(Json*)pv);
+ if (m_parentConfig) return m_parentConfig.defaultBuildEnvironments;
+ return null;
+ }
+
+ @property string[string] defaultRunEnvironments()
+ const {
+ if (auto pv = "defaultRunEnvironments" in m_data)
+ return deserializeJson!(string[string])(*cast(Json*)pv);
+ if (m_parentConfig) return m_parentConfig.defaultRunEnvironments;
+ return null;
+ }
+
+ @property string[string] defaultPreGenerateEnvironments()
+ const {
+ if (auto pv = "defaultPreGenerateEnvironments" in m_data)
+ return deserializeJson!(string[string])(*cast(Json*)pv);
+ if (m_parentConfig) return m_parentConfig.defaultPreGenerateEnvironments;
+ return null;
+ }
+
+ @property string[string] defaultPostGenerateEnvironments()
+ const {
+ if (auto pv = "defaultPostGenerateEnvironments" in m_data)
+ return deserializeJson!(string[string])(*cast(Json*)pv);
+ if (m_parentConfig) return m_parentConfig.defaultPostGenerateEnvironments;
+ return null;
+ }
+
+ @property string[string] defaultPreBuildEnvironments()
+ const {
+ if (auto pv = "defaultPreBuildEnvironments" in m_data)
+ return deserializeJson!(string[string])(*cast(Json*)pv);
+ if (m_parentConfig) return m_parentConfig.defaultPreBuildEnvironments;
+ return null;
+ }
+
+ @property string[string] defaultPostBuildEnvironments()
+ const {
+ if (auto pv = "defaultPostBuildEnvironments" in m_data)
+ return deserializeJson!(string[string])(*cast(Json*)pv);
+ if (m_parentConfig) return m_parentConfig.defaultPostBuildEnvironments;
+ return null;
+ }
+
+ @property string[string] defaultPreRunEnvironments()
+ const {
+ if (auto pv = "defaultPreRunEnvironments" in m_data)
+ return deserializeJson!(string[string])(*cast(Json*)pv);
+ if (m_parentConfig) return m_parentConfig.defaultPreRunEnvironments;
+ return null;
+ }
+
+ @property string[string] defaultPostRunEnvironments()
+ const {
+ if (auto pv = "defaultPostRunEnvironments" in m_data)
+ return deserializeJson!(string[string])(*cast(Json*)pv);
+ if (m_parentConfig) return m_parentConfig.defaultPostRunEnvironments;
+ return null;
+ }
}
diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d
index 575081c..2f6f611 100644
--- a/source/dub/generators/build.d
+++ b/source/dub/generators/build.d
@@ -175,7 +175,8 @@
// run post-build commands
if (!cached && buildsettings.postBuildCommands.length) {
logInfo("Running post-build commands...");
- runBuildCommands(buildsettings.postBuildCommands, pack, m_project, settings, buildsettings);
+ runBuildCommands(buildsettings.postBuildCommands, pack, m_project, settings, buildsettings,
+ [buildsettings.environments, buildsettings.buildEnvironments, buildsettings.postBuildEnvironments]);
}
return cached;
@@ -213,7 +214,8 @@
if( buildsettings.preBuildCommands.length ){
logInfo("Running pre-build commands...");
- runBuildCommands(buildsettings.preBuildCommands, pack, m_project, settings, buildsettings);
+ runBuildCommands(buildsettings.preBuildCommands, pack, m_project, settings, buildsettings,
+ [buildsettings.environments, buildsettings.buildEnvironments, buildsettings.preBuildEnvironments]);
}
// override target path
@@ -333,7 +335,8 @@
if( buildsettings.preBuildCommands.length ){
logInfo("Running pre-build commands...");
- runBuildCommands(buildsettings.preBuildCommands, pack, m_project, settings, buildsettings);
+ runBuildCommands(buildsettings.preBuildCommands, pack, m_project, settings, buildsettings,
+ [buildsettings.environments, buildsettings.buildEnvironments, buildsettings.preBuildEnvironments]);
}
buildWithCompiler(settings, buildsettings);
@@ -532,15 +535,19 @@
if (!exe_file_path.absolute) exe_file_path = cwd ~ exe_file_path;
runPreRunCommands(m_project.rootPackage, m_project, settings, buildsettings);
logInfo("Running %s %s", exe_file_path.relativeTo(runcwd), run_args.join(" "));
+ string[string] env;
+ foreach (aa; [buildsettings.environments, buildsettings.runEnvironments])
+ foreach (k, v; aa)
+ env[k] = v;
if (settings.runCallback) {
auto res = execute([ exe_file_path.toNativeString() ] ~ run_args,
- null, Config.none, size_t.max, runcwd.toNativeString());
+ env, Config.none, size_t.max, runcwd.toNativeString());
settings.runCallback(res.status, res.output);
settings.targetExitStatus = res.status;
runPostRunCommands(m_project.rootPackage, m_project, settings, buildsettings);
} else {
auto prg_pid = spawnProcess([ exe_file_path.toNativeString() ] ~ run_args,
- null, Config.none, runcwd.toNativeString());
+ env, Config.none, runcwd.toNativeString());
auto result = prg_pid.wait();
settings.targetExitStatus = result;
runPostRunCommands(m_project.rootPackage, m_project, settings, buildsettings);
@@ -555,7 +562,8 @@
{
if (buildsettings.preRunCommands.length) {
logInfo("Running pre-run commands...");
- runBuildCommands(buildsettings.preRunCommands, pack, proj, settings, buildsettings);
+ runBuildCommands(buildsettings.preRunCommands, pack, proj, settings, buildsettings,
+ [buildsettings.environments, buildsettings.runEnvironments, buildsettings.preRunEnvironments]);
}
}
@@ -564,7 +572,8 @@
{
if (buildsettings.postRunCommands.length) {
logInfo("Running post-run commands...");
- runBuildCommands(buildsettings.postRunCommands, pack, proj, settings, buildsettings);
+ runBuildCommands(buildsettings.postRunCommands, pack, proj, settings, buildsettings,
+ [buildsettings.environments, buildsettings.runEnvironments, buildsettings.postRunEnvironments]);
}
}
diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d
index db21e51..cba8f09 100644
--- a/source/dub/generators/generator.d
+++ b/source/dub/generators/generator.d
@@ -71,6 +71,51 @@
string[] linkDependencies;
}
+ private struct EnvironmentVariables
+ {
+ string[string] environments;
+ string[string] buildEnvironments;
+ string[string] runEnvironments;
+ string[string] preGenerateEnvironments;
+ string[string] postGenerateEnvironments;
+ string[string] preBuildEnvironments;
+ string[string] postBuildEnvironments;
+ string[string] preRunEnvironments;
+ string[string] postRunEnvironments;
+
+ this(const scope ref BuildSettings bs)
+ {
+ update(bs);
+ }
+
+ void update(Envs)(const scope auto ref Envs envs)
+ {
+ import std.algorithm: each;
+ envs.environments.byKeyValue.each!(pair => environments[pair.key] = pair.value);
+ envs.buildEnvironments.byKeyValue.each!(pair => buildEnvironments[pair.key] = pair.value);
+ envs.runEnvironments.byKeyValue.each!(pair => runEnvironments[pair.key] = pair.value);
+ envs.preGenerateEnvironments.byKeyValue.each!(pair => preGenerateEnvironments[pair.key] = pair.value);
+ envs.postGenerateEnvironments.byKeyValue.each!(pair => postGenerateEnvironments[pair.key] = pair.value);
+ envs.preBuildEnvironments.byKeyValue.each!(pair => preBuildEnvironments[pair.key] = pair.value);
+ envs.postBuildEnvironments.byKeyValue.each!(pair => postBuildEnvironments[pair.key] = pair.value);
+ envs.preRunEnvironments.byKeyValue.each!(pair => preRunEnvironments[pair.key] = pair.value);
+ envs.postRunEnvironments.byKeyValue.each!(pair => postRunEnvironments[pair.key] = pair.value);
+ }
+
+ void updateBuildSettings(ref BuildSettings bs)
+ {
+ bs.updateEnvironments(environments);
+ bs.updateBuildEnvironments(buildEnvironments);
+ bs.updateRunEnvironments(runEnvironments);
+ bs.updatePreGenerateEnvironments(preGenerateEnvironments);
+ bs.updatePostGenerateEnvironments(postGenerateEnvironments);
+ bs.updatePreBuildEnvironments(preBuildEnvironments);
+ bs.updatePostBuildEnvironments(postBuildEnvironments);
+ bs.updatePreRunEnvironments(preRunEnvironments);
+ bs.updatePostRunEnvironments(postRunEnvironments);
+ }
+ }
+
protected {
Project m_project;
NativePath m_tempTargetExecutablePath;
@@ -91,23 +136,43 @@
string[string] configs = m_project.getPackageConfigs(settings.platform, settings.config);
TargetInfo[string] targets;
+ EnvironmentVariables[string] envs;
foreach (pack; m_project.getTopologicalPackageList(true, null, configs)) {
- BuildSettings buildSettings;
auto config = configs[pack.name];
- buildSettings.processVars(m_project, pack, pack.getBuildSettings(settings.platform, config), settings, true);
- if (settings.buildSettings.options & BuildOption.lowmem) buildSettings.options |= BuildOption.lowmem;
-
- prepareGeneration(pack, m_project, settings, buildSettings);
-
- // Regenerate buildSettings.sourceFiles
- if (buildSettings.preGenerateCommands.length) {
- buildSettings = BuildSettings.init;
- buildSettings.processVars(m_project, pack, pack.getBuildSettings(settings.platform, config), settings, true);
+ auto bs = pack.getBuildSettings(settings.platform, config);
+ targets[pack.name] = TargetInfo(pack, [pack], config, bs);
+ envs[pack.name] = EnvironmentVariables(bs);
+ }
+ foreach (pack; m_project.getTopologicalPackageList(false, null, configs)) {
+ auto ti = pack.name in targets;
+ auto parentEnvs = ti.pack.name in envs;
+ foreach (deppkgName, depInfo; pack.getDependencies(ti.config)) {
+ if (auto childEnvs = deppkgName in envs) {
+ childEnvs.update(ti.buildSettings);
+ parentEnvs.update(childEnvs);
+ }
}
- targets[pack.name] = TargetInfo(pack, [pack], config, buildSettings);
+ }
+ BuildSettings makeBuildSettings(in Package pack, ref BuildSettings src)
+ {
+ BuildSettings bs;
+ if (settings.buildSettings.options & BuildOption.lowmem) bs.options |= BuildOption.lowmem;
+ BuildSettings srcbs = src.dup;
+ envs[pack.name].updateBuildSettings(srcbs);
+ bs.processVars(m_project, pack, srcbs, settings, true);
+ return bs;
}
+ foreach (pack; m_project.getTopologicalPackageList(true, null, configs)) {
+ BuildSettings bs = makeBuildSettings(pack, targets[pack.name].buildSettings);
+ prepareGeneration(pack, m_project, settings, bs);
+
+ // Regenerate buildSettings.sourceFiles
+ if (bs.preGenerateCommands.length)
+ bs = makeBuildSettings(pack, targets[pack.name].buildSettings);
+ targets[pack.name].buildSettings = bs;
+ }
configurePackages(m_project.rootPackage, targets, settings);
addBuildTypeSettings(targets, settings);
@@ -116,8 +181,9 @@
generateTargets(settings, targets);
foreach (pack; m_project.getTopologicalPackageList(true, null, configs)) {
- BuildSettings buildsettings;
- buildsettings.processVars(m_project, pack, pack.getBuildSettings(settings.platform, configs[pack.name]), settings, true);
+ auto config = configs[pack.name];
+ auto pkgbs = pack.getBuildSettings(settings.platform, config);
+ BuildSettings buildsettings = makeBuildSettings(pack, pkgbs);
bool generate_binary = !(buildsettings.options & BuildOption.syntaxOnly);
auto bs = &targets[m_project.rootPackage.name].buildSettings;
auto targetPath = !m_tempTargetExecutablePath.empty ? m_tempTargetExecutablePath :
@@ -736,7 +802,8 @@
{
if (buildsettings.preGenerateCommands.length && !isRecursiveInvocation(pack.name)) {
logInfo("Running pre-generate commands for %s...", pack.name);
- runBuildCommands(buildsettings.preGenerateCommands, pack, proj, settings, buildsettings);
+ runBuildCommands(buildsettings.preGenerateCommands, pack, proj, settings, buildsettings,
+ [buildsettings.environments, buildsettings.buildEnvironments, buildsettings.preGenerateEnvironments]);
}
}
@@ -748,7 +815,8 @@
{
if (buildsettings.postGenerateCommands.length && !isRecursiveInvocation(pack.name)) {
logInfo("Running post-generate commands for %s...", pack.name);
- runBuildCommands(buildsettings.postGenerateCommands, pack, proj, settings, buildsettings);
+ runBuildCommands(buildsettings.postGenerateCommands, pack, proj, settings, buildsettings,
+ [buildsettings.environments, buildsettings.buildEnvironments, buildsettings.postGenerateEnvironments]);
}
if (generate_binary) {
@@ -816,7 +884,7 @@
runs "dub describe" or similar functionality.
*/
void runBuildCommands(in string[] commands, in Package pack, in Project proj,
- in GeneratorSettings settings, in BuildSettings build_settings)
+ in GeneratorSettings settings, in BuildSettings build_settings, in string[string][] extraVars = null)
{
import dub.internal.utils : getDUBExePath, runCommands;
import std.conv : to, text;
@@ -870,6 +938,11 @@
env["DUB_ROOT_PACKAGE_TARGET_TYPE"] = to!string(rootPackageBuildSettings.targetType);
env["DUB_ROOT_PACKAGE_TARGET_PATH"] = rootPackageBuildSettings.targetPath;
env["DUB_ROOT_PACKAGE_TARGET_NAME"] = rootPackageBuildSettings.targetName;
+
+ foreach (aa; extraVars) {
+ foreach (k, v; aa)
+ env[k] = v;
+ }
auto depNames = proj.dependencies.map!((a) => a.name).array();
storeRecursiveInvokations(env, proj.rootPackage.name ~ depNames);
diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d
index 6db18ab..7f45122 100644
--- a/source/dub/generators/visuald.d
+++ b/source/dub/generators/visuald.d
@@ -157,7 +157,9 @@
auto ret = appender!(char[])();
auto root_package_path = m_project.rootPackage.path;
- auto project_file_dir = root_package_path ~ projFileName(packname).parentPath;
+ auto basepath = NativePath(".dub/");
+ if (!isWritableDir(basepath, true))
+ throw new Exception(".dub is not writeable");
ret.put("\n");
ret.formattedWrite(" %s\n", guid(packname));
@@ -185,7 +187,7 @@
auto sp = NativePath(s);
assert(sp.absolute, format("Source path in %s expected to be absolute: %s", packname, s));
//if( !sp.absolute ) sp = pack.path ~ sp;
- addSourceFile(sp.relativeTo(project_file_dir), determineStructurePath(sp, targets[packname]), action);
+ addSourceFile(sp.relativeTo(getWorkingDirectory() ~ basepath), determineStructurePath(sp, targets[packname]), action);
}
foreach (p; targets[packname].packages)
@@ -242,9 +244,6 @@
ret.put("\n \n");
logDebug("About to write to '%s.visualdproj' file %s bytes", getPackageFileName(packname), ret.data.length);
- auto basepath = NativePath(".dub/");
- if (!isWritableDir(basepath, true))
- throw new Exception(".dub is not writeable");
auto proj = openFile(projFileName(packname), FileMode.createTrunc);
scope(exit) proj.close();
proj.put(ret.data);
@@ -253,8 +252,8 @@
void generateProjectConfiguration(Appender!(char[]) ret, string pack, string type, GeneratorSettings settings, in TargetInfo[string] targets)
{
- auto project_file_dir = m_project.rootPackage.path ~ projFileName(pack).parentPath;
auto buildsettings = targets[pack].buildSettings.dup;
+ auto basepath = NativePath(".dub/");
string[] getSettings(string setting)(){ return __traits(getMember, buildsettings, setting); }
string[] getPathSettings(string setting)()
@@ -263,7 +262,7 @@
auto ret = new string[settings.length];
foreach (i; 0 .. settings.length) {
// \" is interpreted as an escaped " by cmd.exe, so we need to avoid that
- auto p = NativePath(settings[i]).relativeTo(project_file_dir);
+ auto p = NativePath(settings[i]).relativeTo(getWorkingDirectory() ~ basepath);
p.endsWithSlash = false;
ret[i] = '"' ~ p.toNativeString() ~ '"';
}
@@ -336,7 +335,7 @@
// compute directory for intermediate files (need dummy/ because of how -op determines the resulting path)
size_t ndummy = 0;
foreach (f; buildsettings.sourceFiles) {
- auto rpath = NativePath(f).relativeTo(project_file_dir);
+ auto rpath = NativePath(f).relativeTo(getWorkingDirectory() ~ basepath);
size_t nd = 0;
foreach (s; rpath.bySegment)
if (s == "..")
@@ -431,7 +430,7 @@
auto wdir = NativePath(buildsettings.workingDirectory);
if (!wdir.absolute) wdir = m_project.rootPackage.path ~ wdir;
ret.formattedWrite(" %s\n",
- wdir.relativeTo(project_file_dir).toNativeString());
+ wdir.relativeTo(getWorkingDirectory() ~ basepath).toNativeString());
ret.put(" \n");
ret.put(" \n");
ret.put(" *.obj;*.cmd;*.build;*.dep\n");
diff --git a/source/dub/package_.d b/source/dub/package_.d
index bbcf973..45efe6e 100644
--- a/source/dub/package_.d
+++ b/source/dub/package_.d
@@ -606,6 +606,15 @@
ret.postGenerateCommands = bs.postGenerateCommands;
ret.preBuildCommands = bs.preBuildCommands;
ret.postBuildCommands = bs.postBuildCommands;
+ ret.environments = bs.environments;
+ ret.buildEnvironments = bs.buildEnvironments;
+ ret.runEnvironments = bs.runEnvironments;
+ ret.preGenerateEnvironments = bs.preGenerateEnvironments;
+ ret.postGenerateEnvironments = bs.postGenerateEnvironments;
+ ret.preBuildEnvironments = bs.preBuildEnvironments;
+ ret.postBuildEnvironments = bs.postBuildEnvironments;
+ ret.preRunEnvironments = bs.preRunEnvironments;
+ ret.postRunEnvironments = bs.postRunEnvironments;
// prettify build requirements output
for (int i = 1; i <= BuildRequirement.max; i <<= 1)
diff --git a/source/dub/packagesuppliers/registry.d b/source/dub/packagesuppliers/registry.d
index 3751efb..83b01e5 100644
--- a/source/dub/packagesuppliers/registry.d
+++ b/source/dub/packagesuppliers/registry.d
@@ -48,18 +48,30 @@
return ret;
}
- void fetchPackage(NativePath path, string packageId, Dependency dep, bool pre_release)
+ auto genPackageDownloadUrl(string packageId, Dependency dep, bool pre_release)
{
import std.array : replace;
import std.format : format;
+ import std.typecons : Nullable;
auto md = getMetadata(packageId);
Json best = getBestPackage(md, packageId, dep, pre_release);
- if (best.type == Json.Type.null_)
+ Nullable!URL ret;
+ if (best.type != Json.Type.null_)
+ {
+ auto vers = best["version"].get!string;
+ ret = m_registryUrl ~ NativePath(PackagesPath~"/"~packageId~"/"~vers~".zip");
+ }
+ return ret;
+ }
+
+ void fetchPackage(NativePath path, string packageId, Dependency dep, bool pre_release)
+ {
+ import std.format : format;
+ auto url = genPackageDownloadUrl(packageId, dep, pre_release);
+ if(url.isNull)
return;
- auto vers = best["version"].get!string;
- auto url = m_registryUrl ~ NativePath(PackagesPath~"/"~packageId~"/"~vers~".zip");
try {
- retryDownload(url, path);
+ retryDownload(url.get, path);
return;
}
catch(HTTPStatusException e) {
diff --git a/source/dub/project.d b/source/dub/project.d
index 1c5b4a2..5b9bcd4 100644
--- a/source/dub/project.d
+++ b/source/dub/project.d
@@ -157,7 +157,7 @@
foreach (d; deps) {
auto dependency = getDependency(d.name, true);
assert(dependency || d.spec.optional,
- format("Non-optional dependency %s of %s not found in dependency tree!?.", d.name, p.name));
+ format("Non-optional dependency '%s' of '%s' not found in dependency tree!?.", d.name, p.name));
if(dependency) perform_rec(dependency);
if( ret ) return;
}
@@ -667,9 +667,9 @@
dst.targetPath = psettings.targetPath;
dst.targetName = psettings.targetName;
if (!psettings.workingDirectory.empty)
- dst.workingDirectory = processVars(psettings.workingDirectory, this, pkg, gsettings, true);
+ dst.workingDirectory = processVars(psettings.workingDirectory, this, pkg, gsettings, true, [dst.environments, dst.buildEnvironments]);
if (psettings.mainSourceFile.length)
- dst.mainSourceFile = processVars(psettings.mainSourceFile, this, pkg, gsettings, true);
+ dst.mainSourceFile = processVars(psettings.mainSourceFile, this, pkg, gsettings, true, [dst.environments, dst.buildEnvironments]);
}
}
@@ -890,6 +890,8 @@
return ret;
}
+ else static if( is(typeof(value) == string[string]) )
+ return value.byKeyValue.map!(a => a.key ~ "=" ~ a.value);
else static if( is(typeof(value) == enum) )
return only(value);
else static if( is(typeof(value) == BuildRequirements) )
@@ -972,6 +974,15 @@
case "post-generate-commands":
case "pre-build-commands":
case "post-build-commands":
+ case "environments":
+ case "build-environments":
+ case "run-environments":
+ case "pre-generate-environments":
+ case "post-generate-environments":
+ case "pre-build-environments":
+ case "post-build-environments":
+ case "pre-run-environments":
+ case "post-run-environments":
enforce(false, "--data="~requestedData~" can only be used with --data-list or --data-0.");
break;
@@ -987,32 +998,41 @@
auto args = TypeTuple!(platform, configs, projectDescription, compiler, disableEscaping);
switch (requestedData)
{
- case "target-type": return listBuildSetting!"targetType"(args);
- case "target-path": return listBuildSetting!"targetPath"(args);
- case "target-name": return listBuildSetting!"targetName"(args);
- case "working-directory": return listBuildSetting!"workingDirectory"(args);
- case "main-source-file": return listBuildSetting!"mainSourceFile"(args);
- case "dflags": return listBuildSetting!"dflags"(args);
- case "lflags": return listBuildSetting!"lflags"(args);
- case "libs": return listBuildSetting!"libs"(args);
- case "linker-files": return listBuildSetting!"linkerFiles"(args);
- case "source-files": return listBuildSetting!"sourceFiles"(args);
- case "copy-files": return listBuildSetting!"copyFiles"(args);
- case "extra-dependency-files": return listBuildSetting!"extraDependencyFiles"(args);
- case "versions": return listBuildSetting!"versions"(args);
- case "debug-versions": return listBuildSetting!"debugVersions"(args);
- case "import-paths": return listBuildSetting!"importPaths"(args);
- case "string-import-paths": return listBuildSetting!"stringImportPaths"(args);
- case "import-files": return listBuildSetting!"importFiles"(args);
- case "string-import-files": return listBuildSetting!"stringImportFiles"(args);
- case "pre-generate-commands": return listBuildSetting!"preGenerateCommands"(args);
- case "post-generate-commands": return listBuildSetting!"postGenerateCommands"(args);
- case "pre-build-commands": return listBuildSetting!"preBuildCommands"(args);
- case "post-build-commands": return listBuildSetting!"postBuildCommands"(args);
- case "pre-run-commands": return listBuildSetting!"preRunCommands"(args);
- case "post-run-commands": return listBuildSetting!"postRunCommands"(args);
- case "requirements": return listBuildSetting!"requirements"(args);
- case "options": return listBuildSetting!"options"(args);
+ case "target-type": return listBuildSetting!"targetType"(args);
+ case "target-path": return listBuildSetting!"targetPath"(args);
+ case "target-name": return listBuildSetting!"targetName"(args);
+ case "working-directory": return listBuildSetting!"workingDirectory"(args);
+ case "main-source-file": return listBuildSetting!"mainSourceFile"(args);
+ case "dflags": return listBuildSetting!"dflags"(args);
+ case "lflags": return listBuildSetting!"lflags"(args);
+ case "libs": return listBuildSetting!"libs"(args);
+ case "linker-files": return listBuildSetting!"linkerFiles"(args);
+ case "source-files": return listBuildSetting!"sourceFiles"(args);
+ case "copy-files": return listBuildSetting!"copyFiles"(args);
+ case "extra-dependency-files": return listBuildSetting!"extraDependencyFiles"(args);
+ case "versions": return listBuildSetting!"versions"(args);
+ case "debug-versions": return listBuildSetting!"debugVersions"(args);
+ case "import-paths": return listBuildSetting!"importPaths"(args);
+ case "string-import-paths": return listBuildSetting!"stringImportPaths"(args);
+ case "import-files": return listBuildSetting!"importFiles"(args);
+ case "string-import-files": return listBuildSetting!"stringImportFiles"(args);
+ case "pre-generate-commands": return listBuildSetting!"preGenerateCommands"(args);
+ case "post-generate-commands": return listBuildSetting!"postGenerateCommands"(args);
+ case "pre-build-commands": return listBuildSetting!"preBuildCommands"(args);
+ case "post-build-commands": return listBuildSetting!"postBuildCommands"(args);
+ case "pre-run-commands": return listBuildSetting!"preRunCommands"(args);
+ case "post-run-commands": return listBuildSetting!"postRunCommands"(args);
+ case "environments": return listBuildSetting!"environments"(args);
+ case "build-environments": return listBuildSetting!"buildEnvironments"(args);
+ case "run-environments": return listBuildSetting!"runEnvironments"(args);
+ case "pre-generate-environments": return listBuildSetting!"preGenerateEnvironments"(args);
+ case "post-generate-environments": return listBuildSetting!"postGenerateEnvironments"(args);
+ case "pre-build-environments": return listBuildSetting!"preBuildEnvironments"(args);
+ case "post-build-environments": return listBuildSetting!"postBuildEnvironments"(args);
+ case "pre-run-environments": return listBuildSetting!"preRunEnvironments"(args);
+ case "post-run-environments": return listBuildSetting!"postRunEnvironments"(args);
+ case "requirements": return listBuildSetting!"requirements"(args);
+ case "options": return listBuildSetting!"options"(args);
default:
enforce(false, "--data="~requestedData~
@@ -1160,59 +1180,89 @@
void processVars(ref BuildSettings dst, in Project project, in Package pack,
BuildSettings settings, in GeneratorSettings gsettings, bool include_target_settings = false)
{
- dst.addDFlags(processVars(project, pack, gsettings, settings.dflags));
- dst.addLFlags(processVars(project, pack, gsettings, settings.lflags));
- dst.addLibs(processVars(project, pack, gsettings, settings.libs));
- dst.addSourceFiles(processVars!true(project, pack, gsettings, settings.sourceFiles, true));
- dst.addImportFiles(processVars(project, pack, gsettings, settings.importFiles, true));
- dst.addStringImportFiles(processVars(project, pack, gsettings, settings.stringImportFiles, true));
- dst.addCopyFiles(processVars(project, pack, gsettings, settings.copyFiles, true));
- dst.addExtraDependencyFiles(processVars(project, pack, gsettings, settings.extraDependencyFiles, true));
- dst.addVersions(processVars(project, pack, gsettings, settings.versions));
- dst.addDebugVersions(processVars(project, pack, gsettings, settings.debugVersions));
- dst.addVersionFilters(processVars(project, pack, gsettings, settings.versionFilters));
- dst.addDebugVersionFilters(processVars(project, pack, gsettings, settings.debugVersionFilters));
- dst.addImportPaths(processVars(project, pack, gsettings, settings.importPaths, true));
- dst.addStringImportPaths(processVars(project, pack, gsettings, settings.stringImportPaths, true));
- dst.addPreGenerateCommands(processVars(project, pack, gsettings, settings.preGenerateCommands));
- dst.addPostGenerateCommands(processVars(project, pack, gsettings, settings.postGenerateCommands));
- dst.addPreBuildCommands(processVars(project, pack, gsettings, settings.preBuildCommands));
- dst.addPostBuildCommands(processVars(project, pack, gsettings, settings.postBuildCommands));
- dst.addPreRunCommands(processVars(project, pack, gsettings, settings.preRunCommands));
- dst.addPostRunCommands(processVars(project, pack, gsettings, settings.postRunCommands));
+ string[string] processVerEnvs(in string[string] targetEnvs, in string[string] defaultEnvs)
+ {
+ string[string] retEnv;
+ foreach (k, v; targetEnvs)
+ retEnv[k] = v;
+ foreach (k, v; defaultEnvs) {
+ if (k !in targetEnvs)
+ retEnv[k] = v;
+ }
+ return processVars(project, pack, gsettings, retEnv);
+ }
+ dst.addEnvironments(processVerEnvs(settings.environments, gsettings.buildSettings.environments));
+ dst.addBuildEnvironments(processVerEnvs(settings.buildEnvironments, gsettings.buildSettings.buildEnvironments));
+ dst.addRunEnvironments(processVerEnvs(settings.runEnvironments, gsettings.buildSettings.runEnvironments));
+ dst.addPreGenerateEnvironments(processVerEnvs(settings.preGenerateEnvironments, gsettings.buildSettings.preGenerateEnvironments));
+ dst.addPostGenerateEnvironments(processVerEnvs(settings.postGenerateEnvironments, gsettings.buildSettings.postGenerateEnvironments));
+ dst.addPreBuildEnvironments(processVerEnvs(settings.preBuildEnvironments, gsettings.buildSettings.preBuildEnvironments));
+ dst.addPostBuildEnvironments(processVerEnvs(settings.postBuildEnvironments, gsettings.buildSettings.postBuildEnvironments));
+ dst.addPreRunEnvironments(processVerEnvs(settings.preRunEnvironments, gsettings.buildSettings.preRunEnvironments));
+ dst.addPostRunEnvironments(processVerEnvs(settings.postRunEnvironments, gsettings.buildSettings.postRunEnvironments));
+
+ auto buildEnvs = [dst.environments, dst.buildEnvironments];
+ auto runEnvs = [dst.environments, dst.runEnvironments];
+ auto preGenEnvs = [dst.environments, dst.preGenerateEnvironments];
+ auto postGenEnvs = [dst.environments, dst.postGenerateEnvironments];
+ auto preBuildEnvs = buildEnvs ~ [dst.preBuildEnvironments];
+ auto postBuildEnvs = buildEnvs ~ [dst.postBuildEnvironments];
+ auto preRunEnvs = runEnvs ~ [dst.preRunEnvironments];
+ auto postRunEnvs = runEnvs ~ [dst.postRunEnvironments];
+
+ dst.addDFlags(processVars(project, pack, gsettings, settings.dflags, false, buildEnvs));
+ dst.addLFlags(processVars(project, pack, gsettings, settings.lflags, false, buildEnvs));
+ dst.addLibs(processVars(project, pack, gsettings, settings.libs, false, buildEnvs));
+ dst.addSourceFiles(processVars!true(project, pack, gsettings, settings.sourceFiles, true, buildEnvs));
+ dst.addImportFiles(processVars(project, pack, gsettings, settings.importFiles, true, buildEnvs));
+ dst.addStringImportFiles(processVars(project, pack, gsettings, settings.stringImportFiles, true, buildEnvs));
+ dst.addCopyFiles(processVars(project, pack, gsettings, settings.copyFiles, true, buildEnvs));
+ dst.addExtraDependencyFiles(processVars(project, pack, gsettings, settings.extraDependencyFiles, true, buildEnvs));
+ dst.addVersions(processVars(project, pack, gsettings, settings.versions, false, buildEnvs));
+ dst.addDebugVersions(processVars(project, pack, gsettings, settings.debugVersions, false, buildEnvs));
+ dst.addVersionFilters(processVars(project, pack, gsettings, settings.versionFilters, false, buildEnvs));
+ dst.addDebugVersionFilters(processVars(project, pack, gsettings, settings.debugVersionFilters, false, buildEnvs));
+ dst.addImportPaths(processVars(project, pack, gsettings, settings.importPaths, true, buildEnvs));
+ dst.addStringImportPaths(processVars(project, pack, gsettings, settings.stringImportPaths, true, buildEnvs));
+ dst.addPreGenerateCommands(processVars(project, pack, gsettings, settings.preGenerateCommands, false, preGenEnvs));
+ dst.addPostGenerateCommands(processVars(project, pack, gsettings, settings.postGenerateCommands, false, postGenEnvs));
+ dst.addPreBuildCommands(processVars(project, pack, gsettings, settings.preBuildCommands, false, preBuildEnvs));
+ dst.addPostBuildCommands(processVars(project, pack, gsettings, settings.postBuildCommands, false, postBuildEnvs));
+ dst.addPreRunCommands(processVars(project, pack, gsettings, settings.preRunCommands, false, preRunEnvs));
+ dst.addPostRunCommands(processVars(project, pack, gsettings, settings.postRunCommands, false, postRunEnvs));
dst.addRequirements(settings.requirements);
dst.addOptions(settings.options);
if (include_target_settings) {
dst.targetType = settings.targetType;
- dst.targetPath = processVars(settings.targetPath, project, pack, gsettings, true);
+ dst.targetPath = processVars(settings.targetPath, project, pack, gsettings, true, buildEnvs);
dst.targetName = settings.targetName;
if (!settings.workingDirectory.empty)
- dst.workingDirectory = processVars(settings.workingDirectory, project, pack, gsettings, true);
+ dst.workingDirectory = processVars(settings.workingDirectory, project, pack, gsettings, true, buildEnvs);
if (settings.mainSourceFile.length)
- dst.mainSourceFile = processVars(settings.mainSourceFile, project, pack, gsettings, true);
+ dst.mainSourceFile = processVars(settings.mainSourceFile, project, pack, gsettings, true, buildEnvs);
}
}
-private string[] processVars(bool glob = false)(in Project project, in Package pack, in GeneratorSettings gsettings, string[] vars, bool are_paths = false)
+private string[] processVars(bool glob = false)(in Project project, in Package pack, in GeneratorSettings gsettings, string[] vars, bool are_paths = false, in string[string][] extraVers = null)
{
auto ret = appender!(string[])();
- processVars!glob(ret, project, pack, gsettings, vars, are_paths);
+ processVars!glob(ret, project, pack, gsettings, vars, are_paths, extraVers);
return ret.data;
}
-private void processVars(bool glob = false)(ref Appender!(string[]) dst, in Project project, in Package pack, in GeneratorSettings gsettings, string[] vars, bool are_paths = false)
+private void processVars(bool glob = false)(ref Appender!(string[]) dst, in Project project, in Package pack, in GeneratorSettings gsettings, string[] vars, bool are_paths = false, in string[string][] extraVers = null)
{
static if (glob)
alias process = processVarsWithGlob!(Project, Package);
else
alias process = processVars!(Project, Package);
foreach (var; vars)
- dst.put(process(var, project, pack, gsettings, are_paths));
+ dst.put(process(var, project, pack, gsettings, are_paths, extraVers));
}
-private string processVars(Project, Package)(string var, in Project project, in Package pack, in GeneratorSettings gsettings, bool is_path)
+private string processVars(Project, Package)(string var, in Project project, in Package pack, in GeneratorSettings gsettings, bool is_path, in string[string][] extraVers = null)
{
- var = var.expandVars!(varName => getVariable(varName, project, pack, gsettings));
+ var = var.expandVars!(varName => getVariable(varName, project, pack, gsettings, extraVers));
if (!is_path)
return var;
auto p = NativePath(var);
@@ -1221,11 +1271,26 @@
else
return p.toNativeString();
}
+private string[string] processVars(bool glob = false)(in Project project, in Package pack, in GeneratorSettings gsettings, string[string] vars, in string[string][] extraVers = null)
+{
+ string[string] ret;
+ processVars!glob(ret, project, pack, gsettings, vars, extraVers);
+ return ret;
+}
+private void processVars(bool glob = false)(ref string[string] dst, in Project project, in Package pack, in GeneratorSettings gsettings, string[string] vars, in string[string][] extraVers)
+{
+ static if (glob)
+ alias process = processVarsWithGlob!(Project, Package);
+ else
+ alias process = processVars!(Project, Package);
+ foreach (k, var; vars)
+ dst[k] = process(var, project, pack, gsettings, false, extraVers);
+}
-private string[] processVarsWithGlob(Project, Package)(string var, in Project project, in Package pack, in GeneratorSettings gsettings, bool is_path)
+private string[] processVarsWithGlob(Project, Package)(string var, in Project project, in Package pack, in GeneratorSettings gsettings, bool is_path, in string[string][] extraVers)
{
assert(is_path, "can't glob something that isn't a path");
- string res = processVars(var, project, pack, gsettings, is_path);
+ string res = processVars(var, project, pack, gsettings, is_path, extraVers);
// Find the unglobbed prefix and iterate from there.
size_t i = 0;
size_t sepIdx = 0;
@@ -1337,7 +1402,7 @@
"ARCH", "PLATFORM", "PLATFORM_POSIX", "BUILD_TYPE"
];
-private string getVariable(Project, Package)(string name, in Project project, in Package pack, in GeneratorSettings gsettings)
+private string getVariable(Project, Package)(string name, in Project project, in Package pack, in GeneratorSettings gsettings, in string[string][] extraVars = null)
{
import dub.internal.utils : getDUBExePath;
import std.process : environment, escapeShellFileName;
@@ -1404,6 +1469,11 @@
else if (name == "LFLAGS")
return join(buildSettings.lflags," ");
}
+
+ import std.range;
+ foreach (aa; retro(extraVars))
+ if (auto exvar = name in aa)
+ return *exvar;
auto envvar = environment.get(name);
if (envvar !is null) return envvar;
diff --git a/source/dub/recipe/json.d b/source/dub/recipe/json.d
index 60e7626..0c5597b 100644
--- a/source/dub/recipe/json.d
+++ b/source/dub/recipe/json.d
@@ -235,6 +235,15 @@
case "postBuildCommands": bs.postBuildCommands[suffix] = deserializeJson!(string[])(value); break;
case "preRunCommands": bs.preRunCommands[suffix] = deserializeJson!(string[])(value); break;
case "postRunCommands": bs.postRunCommands[suffix] = deserializeJson!(string[])(value); break;
+ case "environments": bs.environments[suffix] = deserializeJson!(string[string])(value); break;
+ case "buildEnvironments": bs.buildEnvironments[suffix] = deserializeJson!(string[string])(value); break;
+ case "runEnvironments": bs.runEnvironments[suffix] = deserializeJson!(string[string])(value); break;
+ case "preGenerateEnvironments": bs.preGenerateEnvironments[suffix] = deserializeJson!(string[string])(value); break;
+ case "postGenerateEnvironments": bs.postGenerateEnvironments[suffix] = deserializeJson!(string[string])(value); break;
+ case "preBuildEnvironments": bs.preBuildEnvironments[suffix] = deserializeJson!(string[string])(value); break;
+ case "postBuildEnvironments": bs.postBuildEnvironments[suffix] = deserializeJson!(string[string])(value); break;
+ case "preRunEnvironments": bs.preRunEnvironments[suffix] = deserializeJson!(string[string])(value); break;
+ case "postRunEnvironments": bs.postRunEnvironments[suffix] = deserializeJson!(string[string])(value); break;
case "buildRequirements":
BuildRequirements reqs;
foreach (req; deserializeJson!(string[])(value))
@@ -287,6 +296,15 @@
foreach (suffix, arr; bs.postBuildCommands) ret["postBuildCommands"~suffix] = serializeToJson(arr);
foreach (suffix, arr; bs.preRunCommands) ret["preRunCommands"~suffix] = serializeToJson(arr);
foreach (suffix, arr; bs.postRunCommands) ret["postRunCommands"~suffix] = serializeToJson(arr);
+ foreach (suffix, aa; bs.environments) ret["environments"~suffix] = serializeToJson(aa);
+ foreach (suffix, aa; bs.buildEnvironments) ret["buildEnvironments"~suffix] = serializeToJson(aa);
+ foreach (suffix, aa; bs.runEnvironments) ret["runEnvironments"~suffix] = serializeToJson(aa);
+ foreach (suffix, aa; bs.preGenerateEnvironments) ret["preGenerateEnvironments"~suffix] = serializeToJson(aa);
+ foreach (suffix, aa; bs.postGenerateEnvironments) ret["postGenerateEnvironments"~suffix] = serializeToJson(aa);
+ foreach (suffix, aa; bs.preBuildEnvironments) ret["preBuildEnvironments"~suffix] = serializeToJson(aa);
+ foreach (suffix, aa; bs.postBuildEnvironments) ret["postBuildEnvironments"~suffix] = serializeToJson(aa);
+ foreach (suffix, aa; bs.preRunEnvironments) ret["preRunEnvironments"~suffix] = serializeToJson(aa);
+ foreach (suffix, aa; bs.postRunEnvironments) ret["postRunEnvironments"~suffix] = serializeToJson(aa);
foreach (suffix, arr; bs.buildRequirements) {
string[] val;
foreach (i; [EnumMembers!BuildRequirement])
@@ -318,3 +336,55 @@
if (tr.gdc != Dependency.any) ret["gdc"] = serializeToJson(tr.gdc);
return ret;
}
+
+unittest {
+ import std.string: strip, outdent;
+ static immutable json = `
+ {
+ "name": "projectname",
+ "environments": {
+ "Var1": "env"
+ },
+ "buildEnvironments": {
+ "Var2": "buildEnv"
+ },
+ "runEnvironments": {
+ "Var3": "runEnv"
+ },
+ "preGenerateEnvironments": {
+ "Var4": "preGenEnv"
+ },
+ "postGenerateEnvironments": {
+ "Var5": "postGenEnv"
+ },
+ "preBuildEnvironments": {
+ "Var6": "preBuildEnv"
+ },
+ "postBuildEnvironments": {
+ "Var7": "postBuildEnv"
+ },
+ "preRunEnvironments": {
+ "Var8": "preRunEnv"
+ },
+ "postRunEnvironments": {
+ "Var9": "postRunEnv"
+ }
+ }
+ `.strip.outdent;
+ auto jsonValue = parseJsonString(json);
+ PackageRecipe rec1;
+ parseJson(rec1, jsonValue, null);
+ PackageRecipe rec;
+ parseJson(rec, rec1.toJson(), null); // verify that all fields are serialized properly
+
+ assert(rec.name == "projectname");
+ assert(rec.buildSettings.environments == ["": ["Var1": "env"]]);
+ assert(rec.buildSettings.buildEnvironments == ["": ["Var2": "buildEnv"]]);
+ assert(rec.buildSettings.runEnvironments == ["": ["Var3": "runEnv"]]);
+ assert(rec.buildSettings.preGenerateEnvironments == ["": ["Var4": "preGenEnv"]]);
+ assert(rec.buildSettings.postGenerateEnvironments == ["": ["Var5": "postGenEnv"]]);
+ assert(rec.buildSettings.preBuildEnvironments == ["": ["Var6": "preBuildEnv"]]);
+ assert(rec.buildSettings.postBuildEnvironments == ["": ["Var7": "postBuildEnv"]]);
+ assert(rec.buildSettings.preRunEnvironments == ["": ["Var8": "preRunEnv"]]);
+ assert(rec.buildSettings.postRunEnvironments == ["": ["Var9": "postRunEnv"]]);
+}
diff --git a/source/dub/recipe/packagerecipe.d b/source/dub/recipe/packagerecipe.d
index a7a3522..f924c2a 100644
--- a/source/dub/recipe/packagerecipe.d
+++ b/source/dub/recipe/packagerecipe.d
@@ -204,6 +204,15 @@
string[][string] postBuildCommands;
string[][string] preRunCommands;
string[][string] postRunCommands;
+ string[string][string] environments;
+ string[string][string] buildEnvironments;
+ string[string][string] runEnvironments;
+ string[string][string] preGenerateEnvironments;
+ string[string][string] postGenerateEnvironments;
+ string[string][string] preBuildEnvironments;
+ string[string][string] postBuildEnvironments;
+ string[string][string] preRunEnvironments;
+ string[string][string] postRunEnvironments;
BuildRequirements[string] buildRequirements;
BuildOptions[string] buildOptions;
@@ -303,6 +312,15 @@
getPlatformSetting!("postBuildCommands", "addPostBuildCommands")(dst, platform);
getPlatformSetting!("preRunCommands", "addPreRunCommands")(dst, platform);
getPlatformSetting!("postRunCommands", "addPostRunCommands")(dst, platform);
+ getPlatformSetting!("environments", "addEnvironments")(dst, platform);
+ getPlatformSetting!("buildEnvironments", "addBuildEnvironments")(dst, platform);
+ getPlatformSetting!("runEnvironments", "addRunEnvironments")(dst, platform);
+ getPlatformSetting!("preGenerateEnvironments", "addPreGenerateEnvironments")(dst, platform);
+ getPlatformSetting!("postGenerateEnvironments", "addPostGenerateEnvironments")(dst, platform);
+ getPlatformSetting!("preBuildEnvironments", "addPreBuildEnvironments")(dst, platform);
+ getPlatformSetting!("postBuildEnvironments", "addPostBuildEnvironments")(dst, platform);
+ getPlatformSetting!("preRunEnvironments", "addPreRunEnvironments")(dst, platform);
+ getPlatformSetting!("postRunEnvironments", "addPostRunEnvironments")(dst, platform);
getPlatformSetting!("buildRequirements", "addRequirements")(dst, platform);
getPlatformSetting!("buildOptions", "addOptions")(dst, platform);
}
diff --git a/source/dub/recipe/sdl.d b/source/dub/recipe/sdl.d
index dd3cbb9..177eeb9 100644
--- a/source/dub/recipe/sdl.d
+++ b/source/dub/recipe/sdl.d
@@ -167,6 +167,15 @@
case "postBuildCommands": setting.parsePlatformStringArray(bs.postBuildCommands); break;
case "preRunCommands": setting.parsePlatformStringArray(bs.preRunCommands); break;
case "postRunCommands": setting.parsePlatformStringArray(bs.postRunCommands); break;
+ case "environments": setting.parsePlatformStringAA(bs.environments); break;
+ case "buildEnvironments": setting.parsePlatformStringAA(bs.buildEnvironments); break;
+ case "runEnvironments": setting.parsePlatformStringAA(bs.runEnvironments); break;
+ case "preGenerateEnvironments": setting.parsePlatformStringAA(bs.preGenerateEnvironments); break;
+ case "postGenerateEnvironments": setting.parsePlatformStringAA(bs.postGenerateEnvironments); break;
+ case "preBuildEnvironments": setting.parsePlatformStringAA(bs.preBuildEnvironments); break;
+ case "postBuildEnvironments": setting.parsePlatformStringAA(bs.postBuildEnvironments); break;
+ case "preRunEnvironments": setting.parsePlatformStringAA(bs.preRunEnvironments); break;
+ case "postRunEnvironments": setting.parsePlatformStringAA(bs.postRunEnvironments); break;
case "buildRequirements": setting.parsePlatformEnumArray!BuildRequirement(bs.buildRequirements); break;
case "buildOptions": setting.parsePlatformEnumArray!BuildOption(bs.buildOptions); break;
}
@@ -237,6 +246,12 @@
ret ~= new Tag(namespace, name, values[].map!(v => Value(v)).array,
suffix.length ? [new Attribute(null, "platform", Value(suffix[1 .. $]))] : null);
}
+ void addaa(string name, string suffix, in string[string] values, string namespace = null) {
+ foreach (k, v; values) {
+ ret ~= new Tag(namespace, name, [Value(k), Value(v)],
+ suffix.length ? [new Attribute(null, "platform", Value(suffix[1 .. $]))] : null);
+ }
+ }
string[] toNameArray(T, U)(U bits) if(is(T == enum)) {
string[] ret;
@@ -284,6 +299,15 @@
foreach (suffix, arr; bs.postBuildCommands) adda("postBuildCommands", suffix, arr);
foreach (suffix, arr; bs.preRunCommands) adda("preRunCommands", suffix, arr);
foreach (suffix, arr; bs.postRunCommands) adda("postRunCommands", suffix, arr);
+ foreach (suffix, aa; bs.environments) addaa("environments", suffix, aa);
+ foreach (suffix, aa; bs.buildEnvironments) addaa("buildEnvironments", suffix, aa);
+ foreach (suffix, aa; bs.runEnvironments) addaa("runEnvironments", suffix, aa);
+ foreach (suffix, aa; bs.preGenerateEnvironments) addaa("preGenerateEnvironments", suffix, aa);
+ foreach (suffix, aa; bs.postGenerateEnvironments) addaa("postGenerateEnvironments", suffix, aa);
+ foreach (suffix, aa; bs.preBuildEnvironments) addaa("preBuildEnvironments", suffix, aa);
+ foreach (suffix, aa; bs.postBuildEnvironments) addaa("postBuildEnvironments", suffix, aa);
+ foreach (suffix, aa; bs.preRunEnvironments) addaa("preRunEnvironments", suffix, aa);
+ foreach (suffix, aa; bs.postRunEnvironments) addaa("postRunEnvironments", suffix, aa);
foreach (suffix, bits; bs.buildRequirements) adda("buildRequirements", suffix, toNameArray!BuildRequirement(bits));
foreach (suffix, bits; bs.buildOptions) adda("buildOptions", suffix, toNameArray!BuildOption(bits));
return ret;
@@ -350,6 +374,17 @@
platform = "-" ~ t.attributes["platform"][0].value.get!string;
dst[platform] ~= t.values.map!(v => v.get!string).array;
}
+private void parsePlatformStringAA(Tag t, ref string[string][string] dst)
+{
+ import std.string : format;
+ string platform;
+ if ("platform" in t.attributes)
+ platform = "-" ~ t.attributes["platform"][0].value.get!string;
+ enforceSDL(t.values.length == 2, format("Values for '%s' must be 2 required.", t.fullName), t);
+ enforceSDL(t.values[0].peek!string !is null, format("Values for '%s' must be strings.", t.fullName), t);
+ enforceSDL(t.values[1].peek!string !is null, format("Values for '%s' must be strings.", t.fullName), t);
+ dst[platform][t.values[0].get!string] = t.values[1].get!string;
+}
private void parsePlatformEnumArray(E, Es)(Tag t, ref Es[string] dst)
{
@@ -459,6 +494,15 @@
preRunCommands "prer3"
postRunCommands "postr1" "postr2"
postRunCommands "postr3"
+environments "Var1" "env"
+buildEnvironments "Var2" "buildEnv"
+runEnvironments "Var3" "runEnv"
+preGenerateEnvironments "Var4" "preGenEnv"
+postGenerateEnvironments "Var5" "postGenEnv"
+preBuildEnvironments "Var6" "preBuildEnv"
+postBuildEnvironments "Var7" "postBuildEnv"
+preRunEnvironments "Var8" "preRunEnv"
+postRunEnvironments "Var9" "postRunEnv"
dflags "df1" "df2"
dflags "df3"
lflags "lf1" "lf2"
@@ -536,6 +580,15 @@
assert(rec.buildSettings.postBuildCommands == ["": ["postb1", "postb2", "postb3"]]);
assert(rec.buildSettings.preRunCommands == ["": ["prer1", "prer2", "prer3"]]);
assert(rec.buildSettings.postRunCommands == ["": ["postr1", "postr2", "postr3"]]);
+ assert(rec.buildSettings.environments == ["": ["Var1": "env"]]);
+ assert(rec.buildSettings.buildEnvironments == ["": ["Var2": "buildEnv"]]);
+ assert(rec.buildSettings.runEnvironments == ["": ["Var3": "runEnv"]]);
+ assert(rec.buildSettings.preGenerateEnvironments == ["": ["Var4": "preGenEnv"]]);
+ assert(rec.buildSettings.postGenerateEnvironments == ["": ["Var5": "postGenEnv"]]);
+ assert(rec.buildSettings.preBuildEnvironments == ["": ["Var6": "preBuildEnv"]]);
+ assert(rec.buildSettings.postBuildEnvironments == ["": ["Var7": "postBuildEnv"]]);
+ assert(rec.buildSettings.preRunEnvironments == ["": ["Var8": "preRunEnv"]]);
+ assert(rec.buildSettings.postRunEnvironments == ["": ["Var9": "postRunEnv"]]);
assert(rec.buildSettings.dflags == ["": ["df1", "df2", "df3"]]);
assert(rec.buildSettings.lflags == ["": ["lf1", "lf2", "lf3"]]);
}
diff --git a/test/environment-variables.script.d b/test/environment-variables.script.d
new file mode 100644
index 0000000..c96c2c4
--- /dev/null
+++ b/test/environment-variables.script.d
@@ -0,0 +1,88 @@
+/+ dub.json: {
+ "name": "environment_variables"
+} +/
+module environment_variables;
+import std;
+
+void main()
+{
+ auto currDir = environment.get("CURR_DIR", __FILE_FULL_PATH__.dirName());
+ // preGenerateCommands uses system.environments < settings.environments < deppkg.environments < root.environments < deppkg.preGenerateEnvironments < root.preGenerateEnvironments
+ // preBuildCommands uses system.environments < settings.environments < deppkg.environments < root.environments < deppkg.buildEnvironments < root.buildEnvironments < deppkg.preBuildEnvironments < root.preBuildEnvironments
+ // Build tools uses system.environments < settings.environments < deppkg.environments < root.environments < deppkg.buildEnvironments < root.buildEnvironments
+ // postBuildCommands uses system.environments < settings.environments < deppkg.environments < root.environments < deppkg.buildEnvironments < root.buildEnvironments < deppkg.postBuildEnvironments < root.postBuildEnvironments
+ // postGenerateCommands uses system.environments < settings.environments < deppkg.environments < root.environments < deppkg.postGenerateEnvironments < root.postGenerateEnvironments
+ // preRunCommands uses system.environments < settings.environments < deppkg.environments < root.environments < deppkg.runEnvironments < root.runEnvironments < deppkg.preRunEnvironments < root.preRunEnvironments
+ // User application uses system.environments < settings.environments < deppkg.environments < root.environments < deppkg.runEnvironments < root.runEnvironments
+ // postRunCommands uses system.environments < settings.environments < deppkg.environments < root.environments < deppkg.runEnvironments < root.runEnvironments < deppkg.postRunEnvironments < root.postRunEnvironments
+
+ // Test cases covers:
+ // preGenerateCommands [in root]
+ // priority check: system.environments < settings.environments
+ // priority check: settings.environments < deppkg.environments
+ // priority check: deppkg.environments < root.environments
+ // priority check: root.environments < deppkg.preGenerateEnvironments
+ // priority check: deppkg.preGenerateEnvironments < root.preGenerateEnvironments
+ // postGenerateCommands [in root]
+ // expantion check: deppkg.VAR4
+ // preBuildCommands [in deppkg]
+ // root.environments < deppkg.buildEnvironments
+ // deppkg.buildEnvironments < root.buildEnvironments
+ // root.buildEnvironments < deppkg.postBuildEnvironments
+ // deppkg.preBuildEnvironments < root.preBuildEnvironments
+ // postBuildCommands [in deppkg]
+ // expantion check: deppkg.VAR4
+ // preRunCommands [in deppkg][in root]
+ // expantion check: deppkg.VAR4
+ // Application run
+ // expantion check: root.VAR1
+ // expantion check: settings.VAR2
+ // expantion check: root.VAR3
+ // expantion check: deppkg.VAR4
+ // expantion check: system.VAR5
+ // expantion check: system.SYSENVVAREXPCHECK
+ // postRunCommands [in deppkg][in root]
+ // expantion check: deppkg.VAR4
+ auto res = execute([environment.get("DUB", "dub"), "run", "-f"], [
+ "PRIORITYCHECK_SYS_SET": "system.PRIORITYCHECK_SYS_SET",
+ "SYSENVVAREXPCHECK": "system.SYSENVVAREXPCHECK",
+ "VAR5": "system.VAR5"
+ ], Config.none, size_t.max, currDir.buildPath("environment-variables"));
+ scope (failure)
+ writeln("environment-variables test failed... Testing stdout is:\n-----\n", res.output);
+
+ // preGenerateCommands [in root]
+ assert(res.output.canFind("root.preGenerate: setting.PRIORITYCHECK_SYS_SET"), "preGenerate environment variables priority check is failed.");
+ assert(res.output.canFind("root.preGenerate: deppkg.PRIORITYCHECK_SET_DEP"), "preGenerate environment variables priority check is failed.");
+ assert(res.output.canFind("root.preGenerate: deppkg.PRIORITYCHECK_DEP_ROOT"), "preGenerate environment variables priority check is failed.");
+ assert(res.output.canFind("root.preGenerate: deppkg.PRIORITYCHECK_ROOT_DEPSPEC"), "preGenerate environment variables priority check is failed.");
+ assert(res.output.canFind("root.preGenerate: root.PRIORITYCHECK_DEPSPEC_ROOTSPEC"), "preGenerate environment variables priority check is failed.");
+
+ // postGenerateCommands [in root]
+ assert(res.output.canFind("root.postGenerate: deppkg.VAR4", "postGenerate environment variables expantion check is failed."));
+
+ // preBuildCommands [in deppkg]
+ assert(res.output.canFind("deppkg.preBuild: deppkg.PRIORITYCHECK_ROOT_DEPBLDSPEC"), "preBuild environment variables priority check is failed.");
+ assert(res.output.canFind("deppkg.preBuild: root.PRIORITYCHECK_DEPBLDSPEC_ROOTBLDSPEC"), "preBuild environment variables priority check is failed.");
+ assert(res.output.canFind("deppkg.preBuild: deppkg.PRIORITYCHECK_ROOTBLDSPEC_DEPSPEC"), "preBuild environment variables priority check is failed.");
+ assert(res.output.canFind("deppkg.preBuild: root.PRIORITYCHECK_DEPSPEC_ROOTSPEC"), "preBuild environment variables priority check is failed.");
+
+ // postBuildCommands [in deppkg]
+ assert(res.output.canFind("deppkg.postBuild: deppkg.VAR4"), "postBuild environment variables expantion check is failed.");
+
+ // preRunCommands [in deppkg][in root]
+ assert(!res.output.canFind("deppkg.preRun: deppkg.VAR4"), "preRun that is defined dependent library does not call.");
+ assert(res.output.canFind("root.preRun: deppkg.VAR4"), "preRun environment variables expantion check is failed.");
+
+ // Application run
+ assert(res.output.canFind("app.run: root.VAR1"), "run environment variables expantion check is failed.");
+ assert(res.output.canFind("app.run: settings.VAR2"), "run environment variables expantion check is failed.");
+ assert(res.output.canFind("app.run: root.VAR3"), "run environment variables expantion check is failed.");
+ assert(res.output.canFind("app.run: deppkg.VAR4"), "run environment variables expantion check is failed.");
+ assert(res.output.canFind("app.run: system.VAR5"), "run environment variables expantion check is failed.");
+ assert(res.output.canFind("app.run: system.SYSENVVAREXPCHECK"), "run environment variables expantion check is failed.");
+
+ // postRunCommands [in deppkg][in root]
+ assert(!res.output.canFind("deppkg.postRun: deppkg.VAR4"), "postRunCommands that is defined dependent library does not call.");
+ assert(res.output.canFind("root.postRun: deppkg.VAR4"), "postRun environment variables expantion check is failed.");
+}
diff --git a/test/environment-variables/.gitignore b/test/environment-variables/.gitignore
new file mode 100644
index 0000000..58891a2
--- /dev/null
+++ b/test/environment-variables/.gitignore
@@ -0,0 +1,12 @@
+*
+!.no_build
+!.no_test
+!.no_run
+!dub.json
+!dub.settings.json
+!source
+!source/app.d
+!deppkg
+!deppkg/dub.json
+!deppkg/source/deppkg/foo.d
+
diff --git a/test/environment-variables/.no_build b/test/environment-variables/.no_build
new file mode 100644
index 0000000..d3f5a12
--- /dev/null
+++ b/test/environment-variables/.no_build
@@ -0,0 +1 @@
+
diff --git a/test/environment-variables/.no_run b/test/environment-variables/.no_run
new file mode 100644
index 0000000..d3f5a12
--- /dev/null
+++ b/test/environment-variables/.no_run
@@ -0,0 +1 @@
+
diff --git a/test/environment-variables/.no_test b/test/environment-variables/.no_test
new file mode 100644
index 0000000..d3f5a12
--- /dev/null
+++ b/test/environment-variables/.no_test
@@ -0,0 +1 @@
+
diff --git a/test/environment-variables/deppkg/dub.json b/test/environment-variables/deppkg/dub.json
new file mode 100644
index 0000000..10e9fc8
--- /dev/null
+++ b/test/environment-variables/deppkg/dub.json
@@ -0,0 +1,33 @@
+{
+ "name": "deppkg",
+ "targetType": "library",
+
+ "environments": {
+ "VAR1": "deppkg.VAR1",
+ "VAR3": "deppkg.VAR3",
+ "VAR4": "deppkg.VAR4",
+ "PRIORITYCHECK_SET_DEP": "deppkg.PRIORITYCHECK_SET_DEP"
+ },
+ "buildEnvironments": {
+ "PRIORITYCHECK_ROOT_DEPBLDSPEC": "deppkg.PRIORITYCHECK_ROOT_DEPBLDSPEC",
+ "PRIORITYCHECK_DEPBLDSPEC_ROOTBLDSPEC": "deppkg.PRIORITYCHECK_DEPBLDSPEC_ROOTBLDSPEC"
+ },
+ "preGenerateEnvironments": {
+ "PRIORITYCHECK_DEP_ROOT": "deppkg.PRIORITYCHECK_DEP_ROOT",
+ "PRIORITYCHECK_ROOT_DEPSPEC": "deppkg.PRIORITYCHECK_ROOT_DEPSPEC",
+ "PRIORITYCHECK_DEPSPEC_ROOTSPEC": "deppkg.PRIORITYCHECK_DEPSPEC_ROOTSPEC"
+ },
+ "preBuildEnvironments": {
+ "PRIORITYCHECK_ROOTBLDSPEC_DEPSPEC": "deppkg.PRIORITYCHECK_ROOTBLDSPEC_DEPSPEC",
+ "PRIORITYCHECK_DEPSPEC_ROOTSPEC": "deppkg.PRIORITYCHECK_DEPSPEC_ROOTSPEC"
+ },
+
+ "preBuildCommands": [
+ "echo deppkg.preBuild: $PRIORITYCHECK_ROOT_DEPBLDSPEC",
+ "echo deppkg.preBuild: $PRIORITYCHECK_DEPBLDSPEC_ROOTBLDSPEC",
+ "echo deppkg.preBuild: $PRIORITYCHECK_ROOTBLDSPEC_DEPSPEC",
+ "echo deppkg.preBuild: $PRIORITYCHECK_DEPSPEC_ROOTSPEC"
+ ],
+ "postBuildCommands": ["echo deppkg.postBuild: $VAR4"],
+ "preRunCommands": ["echo deppkg.preRun: $VAR4"]
+}
diff --git a/test/environment-variables/deppkg/source/deppkg/foo.d b/test/environment-variables/deppkg/source/deppkg/foo.d
new file mode 100644
index 0000000..df670cf
--- /dev/null
+++ b/test/environment-variables/deppkg/source/deppkg/foo.d
@@ -0,0 +1,7 @@
+module deppkg.foo;
+
+import std.stdio;
+
+void foo()
+{
+}
diff --git a/test/environment-variables/dub.json b/test/environment-variables/dub.json
new file mode 100644
index 0000000..ceab672
--- /dev/null
+++ b/test/environment-variables/dub.json
@@ -0,0 +1,56 @@
+{
+ "name": "environment-variables",
+ "dependencies": {
+ "deppkg": {"path": "deppkg"}
+ },
+
+ "environments": {
+ "ENVIRONMENTS": "root.environments",
+ "VAR1": "root.VAR1",
+ "VAR3": "root.VAR3",
+ "PRIORITYCHECK_DEP_ROOT": "root.PRIORITYCHECK_DEP_ROOT",
+ "PRIORITYCHECK_ROOT_DEPSPEC": "root.PRIORITYCHECK_ROOT_DEPSPEC",
+ "PRIORITYCHECK_ROOT_DEPBLDSPEC": "root.PRIORITYCHECK_ROOT_DEPBLDSPEC"
+ },
+ "buildEnvironments": {
+ "BUILD_ENVIRONMENTS": "root.buildEnvironments",
+ "PRIORITYCHECK_ROOTBLDSPEC_DEPSPEC": "root.PRIORITYCHECK_ROOTBLDSPEC_DEPSPEC"
+ },
+ "runEnvironments": {
+ "RUN_ENVIRONMENTS": "root.runEnvironments"
+ },
+ "preGenerateEnvironments": {
+ "PRE_GENERATE_ENVIRONMENTS": "root.preGenerateEnvironments",
+ "PRIORITYCHECK_DEPSPEC_ROOTSPEC": "root.PRIORITYCHECK_DEPSPEC_ROOTSPEC"
+ },
+ "postGenerateEnvironments": {
+ "POST_GENERATE_ENVIRONMENTS": "root.postGenerateEnvironments"
+ },
+ "preBuildEnvironments": {
+ "PRE_BUILD_ENVIRONMENTS": "root.preBuildEnvironments",
+ "PRIORITYCHECK_DEPBLDSPEC_ROOTBLDSPEC": "root.PRIORITYCHECK_DEPBLDSPEC_ROOTBLDSPEC",
+ "PRIORITYCHECK_DEPSPEC_ROOTSPEC": "root.PRIORITYCHECK_DEPSPEC_ROOTSPEC"
+ },
+ "postBuildEnvironments": {
+ "POST_BUILD_ENVIRONMENTS": "root.postBuildEnvironments"
+ },
+ "preRunEnvironments": {
+ "PRE_RUN_ENVIRONMENTS": "root.preRunEnvironments"
+ },
+ "postRunEnvironments": {
+ "POST_RUN_ENVIRONMENTS": "root.postRunEnvironments"
+ },
+
+ "preGenerateCommands": [
+ "echo root.preGenerate: $PRIORITYCHECK_SYS_SET",
+ "echo root.preGenerate: $PRIORITYCHECK_SET_DEP",
+ "echo root.preGenerate: $PRIORITYCHECK_DEP_ROOT",
+ "echo root.preGenerate: $PRIORITYCHECK_ROOT_DEPSPEC",
+ "echo root.preGenerate: $PRIORITYCHECK_DEPSPEC_ROOTSPEC"
+ ],
+ "postGenerateCommands": ["echo root.postGenerate: $VAR4"],
+ "preBuildCommands": ["echo root.preBuild: $VAR4"],
+ "postBuildCommands": ["echo root.postBuild: $VAR4"],
+ "preRunCommands": ["echo root.preRun: $VAR4"],
+ "postRunCommands": ["echo root.postRun: $VAR4"]
+}
diff --git a/test/environment-variables/dub.settings.json b/test/environment-variables/dub.settings.json
new file mode 100644
index 0000000..40348df
--- /dev/null
+++ b/test/environment-variables/dub.settings.json
@@ -0,0 +1,7 @@
+{
+ "defaultEnvironments": {
+ "VAR2": "settings.VAR2",
+ "PRIORITYCHECK_SYS_SET": "setting.PRIORITYCHECK_SYS_SET",
+ "PRIORITYCHECK_SET_DEP": "setting.PRIORITYCHECK_SET_DEP"
+ }
+}
diff --git a/test/environment-variables/source/app.d b/test/environment-variables/source/app.d
new file mode 100644
index 0000000..037672a
--- /dev/null
+++ b/test/environment-variables/source/app.d
@@ -0,0 +1,12 @@
+import std.stdio;
+import std.process;
+
+void main()
+{
+ writeln("app.run: ", environment.get("VAR1", ""));
+ writeln("app.run: ", environment.get("VAR2", ""));
+ writeln("app.run: ", environment.get("VAR3", ""));
+ writeln("app.run: ", environment.get("VAR4", ""));
+ writeln("app.run: ", environment.get("VAR5", ""));
+ writeln("app.run: ", environment.get("SYSENVVAREXPCHECK", ""));
+}
diff --git a/test/issue1477-subpackage-visuald-paths.sh b/test/issue1477-subpackage-visuald-paths.sh
new file mode 100755
index 0000000..7f55bcf
--- /dev/null
+++ b/test/issue1477-subpackage-visuald-paths.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+. $(dirname "${BASH_SOURCE[0]}")/common.sh
+# Check project files generated from project "root"
+cd ${CURR_DIR}/issue1477-subpackage-visuald-paths
+rm -rf .dub
+${DUB} generate visuald :subpackage_a
+if ! grep "