diff --git a/changelog/add_env.dd b/changelog/add_env.dd new file mode 100644 index 000000000..c75ef7a60 --- /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 7a799d2f5..5b62fe62a 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -999,6 +999,15 @@ abstract class PackageBuildCommand : Command { 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 49965e781..7fcf28981 100644 --- a/source/dub/compilers/buildsettings.d +++ b/source/dub/compilers/buildsettings.d @@ -46,17 +46,33 @@ struct BuildSettings { 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); @@ -115,6 +131,24 @@ struct BuildSettings { 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 +171,21 @@ private: 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 80331c5c0..72e0aeb9c 100644 --- a/source/dub/compilers/compiler.d +++ b/source/dub/compilers/compiler.d @@ -95,17 +95,17 @@ interface Compiler { 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 add030835..1263f13cd 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -318,7 +318,11 @@ config /etc/dmd.conf 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 @@ config /etc/dmd.conf 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 f615cbbce..4f2afcd84 100644 --- a/source/dub/compilers/gdc.d +++ b/source/dub/compilers/gdc.d @@ -206,7 +206,11 @@ class GDCCompiler : Compiler { 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 @@ class GDCCompiler : Compiler { 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 080fa523d..a171de379 100644 --- a/source/dub/compilers/ldc.d +++ b/source/dub/compilers/ldc.d @@ -237,7 +237,11 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu) 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 @@ config /etc/ldc2.conf (x86_64-pc-linux-gnu) 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 77587513c..29531071d 100644 --- a/source/dub/description.d +++ b/source/dub/description.d @@ -96,6 +96,15 @@ struct PackageDescription { 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 3bfb04268..53f5d2662 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -133,6 +133,16 @@ class Dub { 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 @@ class Dub { 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 @@ class Dub { 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 @@ class Dub { 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."); @@ -779,6 +809,15 @@ class Dub { 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 @@ class Dub { 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 @@ class Dub { 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; @@ -1857,4 +1914,76 @@ private class DubConfig { 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 3f13ddb3c..5a7daf2b1 100644 --- a/source/dub/generators/build.d +++ b/source/dub/generators/build.d @@ -175,7 +175,8 @@ class BuildGenerator : ProjectGenerator { // 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 @@ class BuildGenerator : ProjectGenerator { 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 @@ class BuildGenerator : ProjectGenerator { 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 @@ class BuildGenerator : ProjectGenerator { 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 @@ class BuildGenerator : ProjectGenerator { { 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 @@ class BuildGenerator : ProjectGenerator { { 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 db21e516a..cba8f0993 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -71,6 +71,51 @@ class ProjectGenerator 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 @@ class ProjectGenerator 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; + 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); + } + } + } + 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; + } - prepareGeneration(pack, m_project, settings, buildSettings); + 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 (buildSettings.preGenerateCommands.length) { - buildSettings = BuildSettings.init; - buildSettings.processVars(m_project, pack, pack.getBuildSettings(settings.platform, config), settings, true); - } - targets[pack.name] = TargetInfo(pack, [pack], config, buildSettings); + 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 @@ class ProjectGenerator 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 @@ private void prepareGeneration(in Package pack, in Project proj, in GeneratorSet { 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 @@ private void finalizeGeneration(in Package pack, in Project proj, in GeneratorSe { 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 @@ private void finalizeGeneration(in Package pack, in Project proj, in GeneratorSe 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 @@ void runBuildCommands(in string[] commands, in Package pack, in Project proj, 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/package_.d b/source/dub/package_.d index bbcf973fd..45efe6ee2 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -606,6 +606,15 @@ class Package { 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/project.d b/source/dub/project.d index 1c5b4a2a5..0d2ee1959 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -667,9 +667,9 @@ class Project { 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 @@ class Project { 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 @@ class Project { 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 @@ class Project { 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 @@ enum PlacementLocation { 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 @@ private string processVars(Project, Package)(string var, in Project project, in 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 @@ package(dub) immutable buildSettingsVars = [ "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 @@ private string getVariable(Project, Package)(string name, in Project project, in 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 60e76261d..0c5597bf0 100644 --- a/source/dub/recipe/json.d +++ b/source/dub/recipe/json.d @@ -235,6 +235,15 @@ private void parseJson(ref BuildSettingsTemplate bs, Json json, string package_n 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 @@ private Json toJson(const scope ref BuildSettingsTemplate bs) 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 @@ private Json toJson(const scope ref ToolchainRequirements tr) 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 a7a3522c8..f924c2a5d 100644 --- a/source/dub/recipe/packagerecipe.d +++ b/source/dub/recipe/packagerecipe.d @@ -204,6 +204,15 @@ struct BuildSettingsTemplate { 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 @@ struct BuildSettingsTemplate { 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 dd3cbb953..177eeb9c3 100644 --- a/source/dub/recipe/sdl.d +++ b/source/dub/recipe/sdl.d @@ -167,6 +167,15 @@ private void parseBuildSetting(Tag setting, ref BuildSettingsTemplate bs, string 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 @@ private Tag[] toSDL(const scope ref BuildSettingsTemplate bs) 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 @@ private Tag[] toSDL(const scope ref BuildSettingsTemplate bs) 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 @@ private void parsePlatformStringArray(Tag t, ref string[][string] dst) 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 "prer1" "prer2" 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 @@ lflags "lf3" 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 000000000..c96c2c4bb --- /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 000000000..58891a280 --- /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 000000000..d3f5a12fa --- /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 000000000..d3f5a12fa --- /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 000000000..d3f5a12fa --- /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 000000000..10e9fc843 --- /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 000000000..df670cf07 --- /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 000000000..ceab672d3 --- /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 000000000..40348dffa --- /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 000000000..037672a0b --- /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", "")); +}