diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 401b6c6..17dac3f 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -542,6 +542,7 @@ string m_compilerName; string m_arch; string[] m_debugVersions; + string[] m_overrideConfigs; Compiler m_compiler; BuildPlatform m_buildPlatform; BuildSettings m_buildSettings; @@ -561,6 +562,10 @@ args.getopt("c|config", &m_buildConfig, [ "Builds the specified configuration. Configurations can be defined in dub.json" ]); + args.getopt("override-config", &m_overrideConfigs, [ + "Uses the specified configuration for a certain dependency. Can be specified multiple times.", + "Format: --override-config=/" + ]); args.getopt("compiler", &m_compilerName, [ "Specifies the compiler binary to use (can be a path).", "Arbitrary pre- and suffixes to the identifiers below are recognized (e.g. ldc2 or dmd-2.063) and matched to the proper compiler type:", @@ -629,6 +634,12 @@ } dub.project.validate(); + + foreach (sc; m_overrideConfigs) { + auto idx = sc.indexOf('/'); + enforceUsage(idx >= 0, "Expected \"/\" as argument to --override-config."); + dub.project.overrideConfiguration(sc[0 .. idx], sc[idx+1 .. $]); + } } private bool loadSpecificPackage(Dub dub, string package_name) diff --git a/source/dub/project.d b/source/dub/project.d index 5eadb2e..7ce41a8 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -51,6 +51,7 @@ Package[][Package] m_dependees; SelectedVersions m_selections; bool m_hasAllDependencies; + string[string] m_overriddenConfigs; } /** Loads a project. @@ -208,6 +209,27 @@ return cfgs[m_rootPackage.name]; } + /** Overrides the configuration chosen for a particular package in the + dependency graph. + + Setting a certain configuration here is equivalent to removing all + but one configuration from the package. + + Params: + package_ = The package for which to force selecting a certain + dependency + config = Name of the configuration to force + */ + void overrideConfiguration(string package_, string config) + { + auto p = getDependency(package_, true); + enforce(p !is null, + format("Package '%s', marked for configuration override, is not present in dependency graph.", package_)); + enforce(p.configurations.canFind(config), + format("Package '%s' does not have a configuration named '%s'.", package_, config)); + m_overriddenConfigs[package_] = config; + } + /** Performs basic validation of various aspects of the package. This will emit warnings to `stderr` if any discouraged names or @@ -382,6 +404,7 @@ foreach (i, v; configs) if (v.pack == pack && v.config == config) return i; + assert(pack !in m_overriddenConfigs || config == m_overriddenConfigs[pack]); logDebug("Add config %s %s", pack, config); configs ~= Vertex(pack, config); return configs.length-1; @@ -430,6 +453,39 @@ } string[] allconfigs_path; + + void determineDependencyConfigs(in Package p, string c) + { + string[][string] depconfigs; + foreach (d; p.getAllDependencies()) { + auto dp = getDependency(d.name, true); + if (!dp) continue; + + string[] cfgs; + if (auto pc = dp.name in m_overriddenConfigs) cfgs = [*pc]; + else { + auto subconf = p.getSubConfiguration(c, dp, platform); + if (!subconf.empty) cfgs = [subconf]; + else cfgs = dp.getPlatformConfigurations(platform); + } + cfgs = cfgs.filter!(c => haveConfig(d.name, c)).array; + + // if no valid configuration was found for a dependency, don't include the + // current configuration + if (!cfgs.length) { + logDebug("Skip %s %s (missing configuration for %s)", p.name, c, dp.name); + return; + } + depconfigs[d.name] = cfgs; + } + + // add this configuration to the graph + size_t cidx = createConfig(p.name, c); + foreach (d; p.getAllDependencies()) + foreach (sc; depconfigs.get(d.name, null)) + createEdge(cidx, createConfig(d.name, sc)); + } + // create a graph of all possible package configurations (package, config) -> (subpackage, subconfig) void determineAllConfigs(in Package p) { @@ -446,33 +502,11 @@ } // for each configuration, determine the configurations usable for the dependencies - outer: foreach (c; p.getPlatformConfigurations(platform, p is m_rootPackage && allow_non_library)) { - string[][string] depconfigs; - foreach (d; p.getAllDependencies()) { - auto dp = getDependency(d.name, true); - if (!dp) continue; - - string[] cfgs; - auto subconf = p.getSubConfiguration(c, dp, platform); - if (!subconf.empty) cfgs = [subconf]; - else cfgs = dp.getPlatformConfigurations(platform); - cfgs = cfgs.filter!(c => haveConfig(d.name, c)).array; - - // if no valid configuration was found for a dependency, don't include the - // current configuration - if (!cfgs.length) { - logDebug("Skip %s %s (missing configuration for %s)", p.name, c, dp.name); - continue outer; - } - depconfigs[d.name] = cfgs; - } - - // add this configuration to the graph - size_t cidx = createConfig(p.name, c); - foreach (d; p.getAllDependencies()) - foreach (sc; depconfigs.get(d.name, null)) - createEdge(cidx, createConfig(d.name, sc)); - } + if (auto pc = p.name in m_overriddenConfigs) + determineDependencyConfigs(p, *pc); + else + foreach (c; p.getPlatformConfigurations(platform, p is m_rootPackage && allow_non_library)) + determineDependencyConfigs(p, c); } if (config.length) createConfig(m_rootPackage.name, config); determineAllConfigs(m_rootPackage); diff --git a/test/issue1004-override-config.sh b/test/issue1004-override-config.sh new file mode 100755 index 0000000..7bcd443 --- /dev/null +++ b/test/issue1004-override-config.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd ${CURR_DIR}/issue1004-override-config +${DUB} build --bare main --override-config a/success || exit 1 diff --git a/test/issue1004-override-config/.no_build b/test/issue1004-override-config/.no_build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1004-override-config/.no_build diff --git a/test/issue1004-override-config/a/a.d b/test/issue1004-override-config/a/a.d new file mode 100644 index 0000000..af17f99 --- /dev/null +++ b/test/issue1004-override-config/a/a.d @@ -0,0 +1,5 @@ +module a; + +void test() +{ +} diff --git a/test/issue1004-override-config/a/dub.sdl b/test/issue1004-override-config/a/dub.sdl new file mode 100644 index 0000000..9c01efd --- /dev/null +++ b/test/issue1004-override-config/a/dub.sdl @@ -0,0 +1,9 @@ +name "a" + +configuration "fail" { +} + +configuration "success" { + sourceFiles "a.d" + importPaths "." +} diff --git a/test/issue1004-override-config/main/dub.sdl b/test/issue1004-override-config/main/dub.sdl new file mode 100644 index 0000000..b2287f0 --- /dev/null +++ b/test/issue1004-override-config/main/dub.sdl @@ -0,0 +1,2 @@ +name "main" +dependency "a" version="*" diff --git a/test/issue1004-override-config/main/source/main.d b/test/issue1004-override-config/main/source/main.d new file mode 100644 index 0000000..b248b89 --- /dev/null +++ b/test/issue1004-override-config/main/source/main.d @@ -0,0 +1,6 @@ +import a; + +void main() +{ + test(); +}