diff --git a/changelog/version-identifier-filter.dd b/changelog/version-identifier-filter.dd new file mode 100644 index 0000000..57b8269 --- /dev/null +++ b/changelog/version-identifier-filter.dd @@ -0,0 +1,54 @@ +Added experimental feature to improve build cache efficiency + +Using version identifiers to configure certain features can often lead to +unnecessary rebuilds of dependencies that don't use those version +identifiers. In order to improve the build cache efficiency, dub gained a new +experimental `--filter-versions` switch. + +When `--filter-versions` is passed to any build, test, or generate command, dub +will grep for all the version identifiers packages actually use and only apply +those during building. This allows for example to reuse a cached build for a +library between two applications using different version identifiers when the +library isn't using any of those itself. + +The following regular expressions used to grep for version identifiers. +--- +enum verRE = ctRegex!`(?:^|\s)version\s*\(\s*([^\s]*?)\s*\)`; +enum debVerRE = ctRegex!`(?:^|\s)debug\s*\(\s*([^\s]*?)\s*\)`; +--- + +For packages that use version identifiers in mixins or auto-generated sources, +the list of applicable version identifiers can be specified explicitly in the +package file. + +dub.json: +--- +"-versionFilters": ["Have_vibe_d"] +"-versionFilters-posix": ["UseUnixSockets", "UseMMap"] +"-debugVersionFilters": ["ValidateRequests"] +--- +dub.sdl: +--- +x:versionFilters "Have_vibe_d" +x:versionFilters "UseUnixSockets" "UseMMap" platform="posix" +x:debugVersionFilters "ValidateRequests" +--- + +Note that the inferred version identifiers are cached and grepping is generally +very fast, so explicitly specifying version identifiers should only be used if +necessary. + +Also note that specifying either of versionFilters or debugVersionFilters will +disable inference for both of them. + +The reservered version identifier none can be used for packages that don't use +any version identifiers or debug version identifiers at all. + +dub.json: +---- +"-versionFilters": ["none"] +---- +dub.sdl: +---- +x:debugVersionFilters "none" +---- diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 7b556d0..7a2a742 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -613,6 +613,7 @@ bool m_nodeps; bool m_forceRemove = false; bool m_single; + bool m_filterVersions = true; } override void prepare(scope CommandArgs args) @@ -653,6 +654,9 @@ args.getopt("force-remove", &m_forceRemove, [ "Deprecated option that does nothing." ]); + args.getopt("filter-versions", &m_filterVersions, [ + "[Experimental] Filter version identifiers and debug version identifiers to improve build cache efficiency." + ]); } protected void setupPackage(Dub dub, string package_name, string default_build_type = "debug") @@ -818,6 +822,7 @@ gensettings.compiler = m_compiler; gensettings.buildSettings = m_buildSettings; gensettings.combined = m_combined; + gensettings.filterVersions = m_filterVersions; gensettings.run = m_run; gensettings.runArgs = app_args; gensettings.force = m_force; @@ -963,6 +968,7 @@ settings.buildMode = m_buildMode; settings.buildSettings = m_buildSettings; settings.combined = m_combined; + settings.filterVersions = m_filterVersions; settings.parallelBuild = m_parallel; settings.force = m_force; settings.tempBuild = m_single; @@ -1079,6 +1085,7 @@ settings.config = config; settings.buildType = m_buildType; settings.compiler = m_compiler; + settings.filterVersions = m_filterVersions; if (m_importPaths) { m_data = ["import-paths"]; m_dataList = true; } else if (m_stringImportPaths) { m_data = ["string-import-paths"]; m_dataList = true; } @@ -1779,6 +1786,7 @@ gensettings.compiler = m_compiler; gensettings.buildSettings = m_buildSettings; gensettings.combined = m_combined; + gensettings.filterVersions = m_filterVersions; gensettings.run = m_programStatusCode != int.min || m_programRegex.length; gensettings.runArgs = app_args; gensettings.force = true; diff --git a/source/dub/compilers/buildsettings.d b/source/dub/compilers/buildsettings.d index 0ed9aae..87a4f1a 100644 --- a/source/dub/compilers/buildsettings.d +++ b/source/dub/compilers/buildsettings.d @@ -33,6 +33,8 @@ string[] copyFiles; string[] versions; string[] debugVersions; + string[] versionFilters; + string[] debugVersionFilters; string[] importPaths; string[] stringImportPaths; string[] importFiles; @@ -71,6 +73,8 @@ addCopyFiles(bs.copyFiles); addVersions(bs.versions); addDebugVersions(bs.debugVersions); + addVersionFilters(bs.versionFilters); + addDebugVersionFilters(bs.debugVersionFilters); addImportPaths(bs.importPaths); addStringImportPaths(bs.stringImportPaths); addImportFiles(bs.importFiles); @@ -95,6 +99,8 @@ void addCopyFiles(in string[] value...) { add(copyFiles, value); } void addVersions(in string[] value...) { add(versions, value); } void addDebugVersions(in string[] value...) { add(debugVersions, value); } + void addVersionFilters(in string[] value...) { add(versionFilters, value); } + void addDebugVersionFilters(in string[] value...) { add(debugVersionFilters, value); } void addImportPaths(in string[] value...) { add(importPaths, value); } void addStringImportPaths(in string[] value...) { add(stringImportPaths, value); } void prependStringImportPaths(in string[] value...) { prepend(stringImportPaths, value); } @@ -177,9 +183,9 @@ static bool pathMatch(string path, string pattern) { import std.functional : memoize; - + alias nativePath = memoize!((string stringPath) => NativePath(stringPath)); - + return nativePath(path) == nativePath(pattern) || globMatch(path, pattern); } diff --git a/source/dub/dub.d b/source/dub/dub.d index 9362c58..f6e3682 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -783,6 +783,7 @@ if (existsFile(path ~ ".dub/build")) rmdirRecurse((path ~ ".dub/build").toNativeString()); if (existsFile(path ~ ".dub/obj")) rmdirRecurse((path ~ ".dub/obj").toNativeString()); + if (existsFile(path ~ ".dub/metadata_cache.json")) std.file.remove((path ~ ".dub/metadata_cache.json").toNativeString()); auto p = Package.load(path); if (p.getBuildSettings().targetType == TargetType.none) { diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 896c8bb..ddbbc33 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -102,20 +102,19 @@ prepareGeneration(pack, m_project, settings, buildSettings); } - string[] mainfiles = configurePackages(m_project.rootPackage, targets, settings); + configurePackages(m_project.rootPackage, targets, settings); addBuildTypeSettings(targets, settings); foreach (ref t; targets.byValue) enforceBuildRequirements(t.buildSettings); - auto bs = &targets[m_project.rootPackage.name].buildSettings; - if (bs.targetType == TargetType.executable) bs.addSourceFiles(mainfiles); generateTargets(settings, targets); - auto targetPath = (m_tempTargetExecutablePath.empty) ? NativePath(bs.targetPath) : m_tempTargetExecutablePath; foreach (pack; m_project.getTopologicalPackageList(true, null, configs)) { BuildSettings buildsettings; buildsettings.processVars(m_project, pack, pack.getBuildSettings(settings.platform, configs[pack.name]), settings, true); bool generate_binary = !(buildsettings.options & BuildOption.syntaxOnly); + auto bs = &targets[m_project.rootPackage.name].buildSettings; + auto targetPath = (m_tempTargetExecutablePath.empty) ? NativePath(bs.targetPath) : m_tempTargetExecutablePath; finalizeGeneration(pack, m_project, settings, buildsettings, targetPath, generate_binary); } @@ -160,13 +159,17 @@ compatible. This also transports all Have_dependency_xyz version identifiers to `rootPackage`. + 4. Filter unused versions and debugVersions from all targets. The + filters have previously been upwards inherited (3.) so that versions + used in a dependency are also applied to all dependents. + Note: The upwards inheritance is done at last so that siblings do not influence each other, also see https://github.com/dlang/dub/pull/1128. Note: Targets without output are integrated into their dependents and removed from `targets`. */ - private string[] configurePackages(Package rootPackage, TargetInfo[string] targets, GeneratorSettings genSettings) + private void configurePackages(Package rootPackage, TargetInfo[string] targets, GeneratorSettings genSettings) { import std.algorithm : remove, sort; import std.range : repeat; @@ -229,6 +232,16 @@ hasOutput[ti.pack.name] = generatesBinary || ti.pack is rootPackage; } + // add main source files to root executable + { + auto bs = &targets[rootPackage.name].buildSettings; + if (bs.targetType == TargetType.executable) bs.addSourceFiles(mainSourceFiles); + } + + if (genSettings.filterVersions) + foreach (ref ti; targets.byValue) + inferVersionFilters(ti); + // mark packages as visited (only used during upwards propagation) void[0][Package] visited; @@ -323,7 +336,7 @@ bs.addVersions(pkgnames.map!(pn => "Have_" ~ stripDlangSpecialChars(pn)).array); } - // 3. upwards inherit full build configurations (import paths, versions, debugVersions, ...) + // 3. upwards inherit full build configurations (import paths, versions, debugVersions, versionFilters, importPaths, ...) void configureDependents(ref TargetInfo ti, TargetInfo[string] targets, size_t level = 0) { // use `visited` here as pkgs cannot depend on themselves @@ -350,7 +363,26 @@ else destroy(visited); - // 4. override string import files in dependencies + // 4. Filter applicable version and debug version identifiers + if (genSettings.filterVersions) + { + foreach (name, ref ti; targets) + { + import std.algorithm.sorting : partition; + + auto bs = &ti.buildSettings; + + auto filtered = bs.versions.partition!(v => bs.versionFilters.canFind(v)); + logDebug("Filtering out unused versions for %s: %s", name, filtered); + bs.versions = bs.versions[0 .. $ - filtered.length]; + + filtered = bs.debugVersions.partition!(v => bs.debugVersionFilters.canFind(v)); + logDebug("Filtering out unused debug versions for %s: %s", name, filtered); + bs.debugVersions = bs.debugVersions[0 .. $ - filtered.length]; + } + } + + // 5. override string import files in dependencies static void overrideStringImports(ref TargetInfo ti, TargetInfo[string] targets, string[] overrides) { // do not use visited here as string imports can be overridden by *any* parent @@ -388,8 +420,96 @@ if (!hasOutput[name]) targets.remove(name); } + } - return mainSourceFiles; + // infer applicable version identifiers + private static void inferVersionFilters(ref TargetInfo ti) + { + import std.algorithm.searching : any; + import std.file : timeLastModified; + import std.path : extension; + import std.range : chain; + import std.regex : ctRegex, matchAll; + import std.stdio : File; + import std.datetime : Clock, SysTime, UTC; + import dub.compilers.utils : isLinkerFile; + import dub.internal.vibecompat.data.json : Json, JSONException; + + auto bs = &ti.buildSettings; + + // only infer if neither version filters are specified explicitly + if (bs.versionFilters.length || bs.debugVersionFilters.length) + { + logDebug("Using specified versionFilters for %s: %s %s", ti.pack.name, + bs.versionFilters, bs.debugVersionFilters); + return; + } + + // check all existing source files for version identifiers + static immutable dexts = [".d", ".di"]; + auto srcs = chain(bs.sourceFiles, bs.importFiles, bs.stringImportFiles) + .filter!(f => dexts.canFind(f.extension)).filter!exists; + // try to load cached filters first + auto cache = ti.pack.metadataCache; + try + { + auto cachedFilters = cache["versionFilters"]; + if (cachedFilters.type != Json.Type.undefined) + cachedFilters = cachedFilters[ti.config]; + if (cachedFilters.type != Json.Type.undefined) + { + immutable mtime = SysTime.fromISOExtString(cachedFilters["mtime"].get!string); + if (!srcs.any!(src => src.timeLastModified > mtime)) + { + auto versionFilters = cachedFilters["versions"][].map!(j => j.get!string).array; + auto debugVersionFilters = cachedFilters["debugVersions"][].map!(j => j.get!string).array; + logDebug("Using cached versionFilters for %s: %s %s", ti.pack.name, + versionFilters, debugVersionFilters); + bs.addVersionFilters(versionFilters); + bs.addDebugVersionFilters(debugVersionFilters); + return; + } + } + } + catch (JSONException e) + { + logWarn("Exception during loading invalid package cache %s.\n%s", + ti.pack.path ~ ".dub/metadata_cache.json", e); + } + + // use ctRegex for performance reasons, only small compile time increase + enum verRE = ctRegex!`(?:^|\s)version\s*\(\s*([^\s]*?)\s*\)`; + enum debVerRE = ctRegex!`(?:^|\s)debug\s*\(\s*([^\s]*?)\s*\)`; + + auto versionFilters = appender!(string[]); + auto debugVersionFilters = appender!(string[]); + + foreach (file; srcs) + { + foreach (line; File(file).byLine) + { + foreach (m; line.matchAll(verRE)) + if (!versionFilters.data.canFind(m[1])) + versionFilters.put(m[1].idup); + foreach (m; line.matchAll(debVerRE)) + if (!debugVersionFilters.data.canFind(m[1])) + debugVersionFilters.put(m[1].idup); + } + } + logDebug("Using inferred versionFilters for %s: %s %s", ti.pack.name, + versionFilters.data, debugVersionFilters.data); + bs.addVersionFilters(versionFilters.data); + bs.addDebugVersionFilters(debugVersionFilters.data); + + auto cachedFilters = cache["versionFilters"]; + if (cachedFilters.type == Json.Type.undefined) + cachedFilters = cache["versionFilters"] = [ti.config: Json.emptyObject]; + cachedFilters[ti.config] = [ + "mtime": Json(Clock.currTime(UTC()).toISOExtString), + "versions": Json(versionFilters.data.map!Json.array), + "debugVersions": Json(debugVersionFilters.data.map!Json.array), + ]; + ti.pack.metadataCache = cache; } private static void mergeFromDependent(in ref BuildSettings parent, ref BuildSettings child) @@ -406,6 +526,8 @@ parent.addDFlags(child.dflags); parent.addVersions(child.versions); parent.addDebugVersions(child.debugVersions); + parent.addVersionFilters(child.versionFilters); + parent.addDebugVersionFilters(child.debugVersionFilters); parent.addImportPaths(child.importPaths); parent.addStringImportPaths(child.stringImportPaths); // linking of static libraries is done by parent @@ -444,6 +566,7 @@ int targetExitStatus; bool combined; // compile all in one go instead of each dependency separately + bool filterVersions; // only used for generator "build" bool run, force, direct, rdmd, tempBuild, parallelBuild; diff --git a/source/dub/package_.d b/source/dub/package_.d index bac7020..5da9201 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -274,6 +274,22 @@ dstFile.writePrettyJsonString(m_info.toJson()); } + /// Get the metadata cache for this package + @property Json metadataCache() + { + enum silent_fail = true; + return jsonFromFile(m_path ~ ".dub/metadata_cache.json", silent_fail); + } + + /// Write metadata cache for this package + @property void metadataCache(Json json) + { + enum create_if_missing = true; + if (isWritableDir(m_path ~ ".dub", create_if_missing)) + writeJsonFile(m_path ~ ".dub/metadata_cache.json", json); + // TODO: store elsewhere + } + /** Returns the package recipe of a non-path-based sub package. For sub packages that are declared within the package recipe of the diff --git a/source/dub/project.d b/source/dub/project.d index 46c1ade..5171433 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -1155,6 +1155,8 @@ dst.addCopyFiles(processVars(project, pack, gsettings, settings.copyFiles, 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)); diff --git a/source/dub/recipe/json.d b/source/dub/recipe/json.d index 1078945..418f827 100644 --- a/source/dub/recipe/json.d +++ b/source/dub/recipe/json.d @@ -214,6 +214,8 @@ case "copyFiles": bs.copyFiles[suffix] = deserializeJson!(string[])(value); break; case "versions": bs.versions[suffix] = deserializeJson!(string[])(value); break; case "debugVersions": bs.debugVersions[suffix] = deserializeJson!(string[])(value); break; + case "-versionFilters": bs.versionFilters[suffix] = deserializeJson!(string[])(value); break; + case "-debugVersionFilters": bs.debugVersionFilters[suffix] = deserializeJson!(string[])(value); break; case "importPaths": bs.importPaths[suffix] = deserializeJson!(string[])(value); break; case "stringImportPaths": bs.stringImportPaths[suffix] = deserializeJson!(string[])(value); break; case "preGenerateCommands": bs.preGenerateCommands[suffix] = deserializeJson!(string[])(value); break; @@ -263,6 +265,8 @@ foreach (suffix, arr; bs.copyFiles) ret["copyFiles"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.versions) ret["versions"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.debugVersions) ret["debugVersions"~suffix] = serializeToJson(arr); + foreach (suffix, arr; bs.versionFilters) ret["-versionFilters"~suffix] = serializeToJson(arr); + foreach (suffix, arr; bs.debugVersionFilters) ret["-debugVersionFilters"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.importPaths) ret["importPaths"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.stringImportPaths) ret["stringImportPaths"~suffix] = serializeToJson(arr); foreach (suffix, arr; bs.preGenerateCommands) ret["preGenerateCommands"~suffix] = serializeToJson(arr); diff --git a/source/dub/recipe/packagerecipe.d b/source/dub/recipe/packagerecipe.d index 4fd1991..d4382b2 100644 --- a/source/dub/recipe/packagerecipe.d +++ b/source/dub/recipe/packagerecipe.d @@ -152,6 +152,8 @@ string[][string] copyFiles; string[][string] versions; string[][string] debugVersions; + string[][string] versionFilters; + string[][string] debugVersionFilters; string[][string] importPaths; string[][string] stringImportPaths; string[][string] preGenerateCommands; @@ -237,6 +239,8 @@ getPlatformSetting!("copyFiles", "addCopyFiles")(dst, platform); getPlatformSetting!("versions", "addVersions")(dst, platform); getPlatformSetting!("debugVersions", "addDebugVersions")(dst, platform); + getPlatformSetting!("versionFilters", "addVersionFilters")(dst, platform); + getPlatformSetting!("debugVersionFilters", "addDebugVersionFilters")(dst, platform); getPlatformSetting!("importPaths", "addImportPaths")(dst, platform); getPlatformSetting!("stringImportPaths", "addStringImportPaths")(dst, platform); getPlatformSetting!("preGenerateCommands", "addPreGenerateCommands")(dst, platform); diff --git a/source/dub/recipe/sdl.d b/source/dub/recipe/sdl.d index 8d606ce..cecca7c 100644 --- a/source/dub/recipe/sdl.d +++ b/source/dub/recipe/sdl.d @@ -121,7 +121,7 @@ private void parseBuildSettings(Tag settings, ref BuildSettingsTemplate bs, string package_name) { - foreach (setting; settings.tags) + foreach (setting; settings.all.tags) parseBuildSetting(setting, bs, package_name); } @@ -150,6 +150,8 @@ case "copyFiles": setting.parsePlatformStringArray(bs.copyFiles); break; case "versions": setting.parsePlatformStringArray(bs.versions); break; case "debugVersions": setting.parsePlatformStringArray(bs.debugVersions); break; + case "x:versionFilters": setting.parsePlatformStringArray(bs.versionFilters); break; + case "x:debugVersionFilters": setting.parsePlatformStringArray(bs.debugVersionFilters); break; case "importPaths": setting.parsePlatformStringArray(bs.importPaths); break; case "stringImportPaths": setting.parsePlatformStringArray(bs.stringImportPaths); break; case "preGenerateCommands": setting.parsePlatformStringArray(bs.preGenerateCommands); break; @@ -216,9 +218,9 @@ private Tag[] toSDL(in ref BuildSettingsTemplate bs) { Tag[] ret; - void add(string name, string value) { ret ~= new Tag(null, name, [Value(value)]); } - void adda(string name, string suffix, in string[] values) { - ret ~= new Tag(null, name, values[].map!(v => Value(v)).array, + void add(string name, string value, string namespace = null) { ret ~= new Tag(namespace, name, [Value(value)]); } + void adda(string name, string suffix, in string[] values, string namespace = null) { + ret ~= new Tag(namespace, name, values[].map!(v => Value(v)).array, suffix.length ? [new Attribute(null, "platform", Value(suffix[1 .. $]))] : null); } @@ -253,6 +255,8 @@ foreach (suffix, arr; bs.copyFiles) adda("copyFiles", suffix, arr); foreach (suffix, arr; bs.versions) adda("versions", suffix, arr); foreach (suffix, arr; bs.debugVersions) adda("debugVersions", suffix, arr); + foreach (suffix, arr; bs.versionFilters) adda("versionFilters", suffix, arr, "x"); + foreach (suffix, arr; bs.debugVersionFilters) adda("debugVersionFilters", suffix, arr, "x"); foreach (suffix, arr; bs.importPaths) adda("importPaths", suffix, arr); foreach (suffix, arr; bs.stringImportPaths) adda("stringImportPaths", suffix, arr); foreach (suffix, arr; bs.preGenerateCommands) adda("preGenerateCommands", suffix, arr); @@ -392,6 +396,12 @@ versions "version3" debugVersions "debug1" "debug2" debugVersions "debug3" +x:versionFilters "version1" "version2" +x:versionFilters "version3" +x:versionFilters +x:debugVersionFilters "debug1" "debug2" +x:debugVersionFilters "debug3" +x:debugVersionFilters importPaths "import1" "import2" importPaths "import3" stringImportPaths "string1" "string2" @@ -468,6 +478,8 @@ assert(rec.buildSettings.copyFiles == ["": ["copy1", "copy2", "copy3"]]); assert(rec.buildSettings.versions == ["": ["version1", "version2", "version3"]]); assert(rec.buildSettings.debugVersions == ["": ["debug1", "debug2", "debug3"]]); + assert(rec.buildSettings.versionFilters == ["": ["version1", "version2", "version3"]]); + assert(rec.buildSettings.debugVersionFilters == ["": ["debug1", "debug2", "debug3"]]); assert(rec.buildSettings.importPaths == ["": ["import1", "import2", "import3"]]); assert(rec.buildSettings.stringImportPaths == ["": ["string1", "string2", "string3"]]); assert(rec.buildSettings.preGenerateCommands == ["": ["preg1", "preg2", "preg3"]]); diff --git a/test/4-describe-data-1-list.sh b/test/4-describe-data-1-list.sh index def3899..630b609 100755 --- a/test/4-describe-data-1-list.sh +++ b/test/4-describe-data-1-list.sh @@ -12,7 +12,8 @@ trap cleanup EXIT -if ! $DUB describe --compiler=$DC --data-list \ +if ! $DUB describe --compiler=$DC --filter-versions \ + --data-list \ '--data= target-type , target-path , target-name ' \ '--data= working-directory ' \ --data=main-source-file \ @@ -77,11 +78,8 @@ echo >> "$expected_file" # --data=versions echo "someVerIdent" >> "$expected_file" -echo "Have_describe_project" >> "$expected_file" -echo "Have_describe_dependency_1" >> "$expected_file" -echo "Have_describe_dependency_2" >> "$expected_file" -echo "Have_describe_dependency_3" >> "$expected_file" echo "anotherVerIdent" >> "$expected_file" +echo "Have_describe_dependency_3" >> "$expected_file" echo >> "$expected_file" # --data=debug-versions echo "someDebugVerIdent" >> "$expected_file" diff --git a/test/4-describe-data-2-dmd.sh b/test/4-describe-data-2-dmd.sh index 225537a..5120f1b 100755 --- a/test/4-describe-data-2-dmd.sh +++ b/test/4-describe-data-2-dmd.sh @@ -54,11 +54,8 @@ echo -n "'$CURR_DIR/describe-dependency-1/source/dummy.d' " >> "$expected_file" # --data=versions echo -n "-version=someVerIdent " >> "$expected_file" -echo -n "-version=Have_describe_project " >> "$expected_file" -echo -n "-version=Have_describe_dependency_1 " >> "$expected_file" -echo -n "-version=Have_describe_dependency_2 " >> "$expected_file" -echo -n "-version=Have_describe_dependency_3 " >> "$expected_file" echo -n "-version=anotherVerIdent " >> "$expected_file" +echo -n "-version=Have_describe_dependency_3 " >> "$expected_file" # --data=debug-versions echo -n "-debug=someDebugVerIdent " >> "$expected_file" echo -n "-debug=anotherDebugVerIdent " >> "$expected_file" diff --git a/test/describe-dependency-1/source/dummy.d b/test/describe-dependency-1/source/dummy.d index 8b13789..3c1514d 100644 --- a/test/describe-dependency-1/source/dummy.d +++ b/test/describe-dependency-1/source/dummy.d @@ -1 +1,2 @@ - +version (anotherVerIdent) {} +debug (anotherDebugVerIdent) {} diff --git a/test/describe-project/src/dummy.d b/test/describe-project/src/dummy.d index 8b13789..733017c 100644 --- a/test/describe-project/src/dummy.d +++ b/test/describe-project/src/dummy.d @@ -1 +1,3 @@ - +version (Have_describe_dependency_3) {} +version (someVerIdent) {} +debug (someDebugVerIdent) {} diff --git a/test/version-filters-diamond/.gitignore b/test/version-filters-diamond/.gitignore new file mode 100644 index 0000000..c09a597 --- /dev/null +++ b/test/version-filters-diamond/.gitignore @@ -0,0 +1,15 @@ +.dub +docs.json +__dummy.html +docs/ +issue1262-version-inheritance-diamond +issue1262-version-inheritance-diamond.so +issue1262-version-inheritance-diamond.dylib +issue1262-version-inheritance-diamond.dll +issue1262-version-inheritance-diamond.a +issue1262-version-inheritance-diamond.lib +issue1262-version-inheritance-diamond-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/version-filters-diamond/.no_build b/test/version-filters-diamond/.no_build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters-diamond/.no_build diff --git a/test/version-filters-diamond/.no_run b/test/version-filters-diamond/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters-diamond/.no_run diff --git a/test/version-filters-diamond/.no_test b/test/version-filters-diamond/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters-diamond/.no_test diff --git a/test/version-filters-diamond/daughter/.gitignore b/test/version-filters-diamond/daughter/.gitignore new file mode 100644 index 0000000..f190acb --- /dev/null +++ b/test/version-filters-diamond/daughter/.gitignore @@ -0,0 +1,14 @@ +.dub +docs.json +__dummy.html +docs/ +daughter.so +daughter.dylib +daughter.dll +daughter.a +daughter.lib +daughter-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/version-filters-diamond/daughter/dub.sdl b/test/version-filters-diamond/daughter/dub.sdl new file mode 100644 index 0000000..9562cc5 --- /dev/null +++ b/test/version-filters-diamond/daughter/dub.sdl @@ -0,0 +1,6 @@ +name "daughter" +versions "Daughter" +debugVersions "dDaughter" +x:versionFilters "Daughter" "Parent" +x:debugVersionFilters "dDaughter" "dParent" +dependency "diamond" path="../diamond" diff --git a/test/version-filters-diamond/daughter/source/dummy.d b/test/version-filters-diamond/daughter/source/dummy.d new file mode 100644 index 0000000..4006f06 --- /dev/null +++ b/test/version-filters-diamond/daughter/source/dummy.d @@ -0,0 +1,15 @@ +module daughter.dummy; + +version (Parent) {} else static assert(0, "Expected Parent to be set"); // via dependency +version (Daughter) {} else static assert(0, "Expected Daughter to be set"); // local +version (Son) static assert(0, "Expected Son to not be set"); +version (Diamond) static assert(0, "Expected Diamond to not be set"); + +debug (dParent) {} else static assert(0, "Expected dParent to be set"); // via dependency +debug (dDaughter) {} else static assert(0, "Expected dDaughter to be set"); // local +debug (dSon) {} else static assert(0, "Expected dSon to be set"); // via diamond dependency +debug (dDiamond) static assert(0, "Expected dDiamond to not be set"); + +version (Have_daughter) static assert(0, "Expected Have_daughter to not be set"); +version (Have_son) static assert(0, "Expected Have_son to not be set"); +version (Have_diamond) static assert(0, "Expected Have_diamond to not be set"); diff --git a/test/version-filters-diamond/diamond/.gitignore b/test/version-filters-diamond/diamond/.gitignore new file mode 100644 index 0000000..c359a73 --- /dev/null +++ b/test/version-filters-diamond/diamond/.gitignore @@ -0,0 +1,14 @@ +.dub +docs.json +__dummy.html +docs/ +diamond.so +diamond.dylib +diamond.dll +diamond.a +diamond.lib +diamond-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/version-filters-diamond/diamond/dub.sdl b/test/version-filters-diamond/diamond/dub.sdl new file mode 100644 index 0000000..afdb272 --- /dev/null +++ b/test/version-filters-diamond/diamond/dub.sdl @@ -0,0 +1,3 @@ +name "diamond" +versions "Diamond" +debugVersions "dDiamond" diff --git a/test/version-filters-diamond/diamond/source/dummy.d b/test/version-filters-diamond/diamond/source/dummy.d new file mode 100644 index 0000000..3c1fca5 --- /dev/null +++ b/test/version-filters-diamond/diamond/source/dummy.d @@ -0,0 +1,26 @@ +module diamond.dummy; + +template hasVersion(string v) +{ + mixin("version ("~v~") enum hasVersion = true; else enum hasVersion = false;"); +} + +template hasDebugVersion(string v) +{ + mixin("debug ("~v~") enum hasDebugVersion = true; else enum hasDebugVersion = false;"); +} + +// checking inference here +version (Parent) {} else static assert(0, "Expected Parent to be set"); +version (Daughter) {} else static assert(0, "Expected Daughter to be set"); +static assert(!hasVersion!"Son"); +static assert(!hasVersion!"Diamond"); + +debug (dParent) {} else static assert(0, "Expected dParent to be set"); +static assert(!hasDebugVersion!"dDaughter"); +debug (dSon) {} else static assert(0, "Expected dSon to be set"); +static assert(!hasDebugVersion!"dDiamond"); + +static assert(!hasVersion!"Have_daughter"); +static assert(!hasVersion!"Have_son"); +static assert(!hasVersion!"Have_diamond"); diff --git a/test/version-filters-diamond/dub.sdl b/test/version-filters-diamond/dub.sdl new file mode 100644 index 0000000..51295fd --- /dev/null +++ b/test/version-filters-diamond/dub.sdl @@ -0,0 +1,7 @@ +name "version-filters-diamond" +versions "Parent" +debugVersions "dParent" +x:versionFilters "Parent" +x:debugVersionFilters "dParent" +dependency "daughter" path="daughter" +dependency "son" path="son" diff --git a/test/version-filters-diamond/son/.gitignore b/test/version-filters-diamond/son/.gitignore new file mode 100644 index 0000000..601a33b --- /dev/null +++ b/test/version-filters-diamond/son/.gitignore @@ -0,0 +1,14 @@ +.dub +docs.json +__dummy.html +docs/ +son.so +son.dylib +son.dll +son.a +son.lib +son-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/version-filters-diamond/son/dub.sdl b/test/version-filters-diamond/son/dub.sdl new file mode 100644 index 0000000..3e0a630 --- /dev/null +++ b/test/version-filters-diamond/son/dub.sdl @@ -0,0 +1,6 @@ +name "son" +versions "Son" +debugVersions "dSon" +x:versionFilters "Son" +x:debugVersionFilters "dSon" +dependency "diamond" path="../diamond" diff --git a/test/version-filters-diamond/son/source/dummy.d b/test/version-filters-diamond/son/source/dummy.d new file mode 100644 index 0000000..7e56da0 --- /dev/null +++ b/test/version-filters-diamond/son/source/dummy.d @@ -0,0 +1,15 @@ +module son.dummy; + +version (Parent) {} else static assert(0, "Expected Parent to be set"); // via dependency +version (Daughter) {} else static assert(0, "Expected Daughter to not be set"); // via diamond dependency +version (Son) {} else static assert(0, "Expected Son to be set"); // local +version (Diamond) static assert(0, "Expected Diamond to not be set"); + +debug (dParent) {} else static assert(0, "Expected dParent to be set"); // via dependency +debug (dDaughter) static assert(0, "Expected dDaughter to not be set"); // via diamond dependency +debug (dSon) {} else static assert(0, "Expected dSon to be set"); // local +debug (dDiamond) static assert(0, "Expected dDiamond to not be set"); + +version (Have_daughter) static assert(0, "Expected Have_daughter to not be set"); +version (Have_son) static assert(0, "Expected Have_son to not be set"); +version (Have_diamond) static assert(0, "Expected Have_diamond to not be set"); diff --git a/test/version-filters-diamond/source/app.d b/test/version-filters-diamond/source/app.d new file mode 100644 index 0000000..2f19e5c --- /dev/null +++ b/test/version-filters-diamond/source/app.d @@ -0,0 +1,17 @@ +version (Parent) {} else static assert(0, "Expected Parent to be set"); // local +version (Daughter) {} else static assert(0, "Expected Daughter to not be set"); // via dependency +version (Son) {} else static assert(0, "Expected Son to not be set"); // via dependency +version (Diamond) static assert(0, "Expected Diamond to not be set"); // unused by dependencies + +debug (dParent) {} else static assert(0, "Expected dParent to be set"); // local +debug (dDaughter) {} else static assert(0, "Expected dDaughter to be set"); // via dependency +debug (dSon) {} else static assert(0, "Expected dSon to not be set"); // via dependency +debug (dDiamond) static assert(0, "Expected dDiamond to not be set"); // unused by dependencies + +version (Have_daugther) static assert(0, "Expected Have_daugther to not be set"); +version (Have_son) static assert(0, "Expected Have_son to not be set"); +version (Have_diamond) static assert(0, "Expected Have_diamond to not be set"); + +void main() +{ +} diff --git a/test/version-filters-none/.gitignore b/test/version-filters-none/.gitignore new file mode 100644 index 0000000..c09a597 --- /dev/null +++ b/test/version-filters-none/.gitignore @@ -0,0 +1,15 @@ +.dub +docs.json +__dummy.html +docs/ +issue1262-version-inheritance-diamond +issue1262-version-inheritance-diamond.so +issue1262-version-inheritance-diamond.dylib +issue1262-version-inheritance-diamond.dll +issue1262-version-inheritance-diamond.a +issue1262-version-inheritance-diamond.lib +issue1262-version-inheritance-diamond-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/version-filters-none/.no_build b/test/version-filters-none/.no_build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters-none/.no_build diff --git a/test/version-filters-none/.no_run b/test/version-filters-none/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters-none/.no_run diff --git a/test/version-filters-none/.no_test b/test/version-filters-none/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters-none/.no_test diff --git a/test/version-filters-none/dub.sdl b/test/version-filters-none/dub.sdl new file mode 100644 index 0000000..5ad696c --- /dev/null +++ b/test/version-filters-none/dub.sdl @@ -0,0 +1,4 @@ +name "version-filters-none" +versions "Parent" +debugVersions "dParent" +x:versionFilters "none" diff --git a/test/version-filters-none/source/app.d b/test/version-filters-none/source/app.d new file mode 100644 index 0000000..cafe4cf --- /dev/null +++ b/test/version-filters-none/source/app.d @@ -0,0 +1,6 @@ +version (Parent) static assert(0, "Expected Parent to not be set"); +debug (dParent) static assert(0, "Expected dParent to not be set"); + +void main() +{ +} diff --git a/test/version-filters-source-dep/.gitignore b/test/version-filters-source-dep/.gitignore new file mode 100644 index 0000000..c09a597 --- /dev/null +++ b/test/version-filters-source-dep/.gitignore @@ -0,0 +1,15 @@ +.dub +docs.json +__dummy.html +docs/ +issue1262-version-inheritance-diamond +issue1262-version-inheritance-diamond.so +issue1262-version-inheritance-diamond.dylib +issue1262-version-inheritance-diamond.dll +issue1262-version-inheritance-diamond.a +issue1262-version-inheritance-diamond.lib +issue1262-version-inheritance-diamond-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/version-filters-source-dep/.no_build b/test/version-filters-source-dep/.no_build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters-source-dep/.no_build diff --git a/test/version-filters-source-dep/.no_run b/test/version-filters-source-dep/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters-source-dep/.no_run diff --git a/test/version-filters-source-dep/.no_test b/test/version-filters-source-dep/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters-source-dep/.no_test diff --git a/test/version-filters-source-dep/dub.sdl b/test/version-filters-source-dep/dub.sdl new file mode 100644 index 0000000..73d4834 --- /dev/null +++ b/test/version-filters-source-dep/dub.sdl @@ -0,0 +1,5 @@ +name "version-filters-source-dep" +versions "Parent" +debugVersions "dParent" +x:versionFilters "none" +dependency "source-dep" path="source-dep" diff --git a/test/version-filters-source-dep/source-dep/dub.sdl b/test/version-filters-source-dep/source-dep/dub.sdl new file mode 100644 index 0000000..d9b7c63 --- /dev/null +++ b/test/version-filters-source-dep/source-dep/dub.sdl @@ -0,0 +1,7 @@ +name "source-dep" +versions "SourceDep" +debugVersions "dSourceDep" +# filter of sourceOnly libs are merged with dependents +x:versionFilters "SourceDep" +x:debugVersionFilters "dSourceDep" +targetType "sourceLibrary" diff --git a/test/version-filters-source-dep/source-dep/source/dummy.d b/test/version-filters-source-dep/source-dep/source/dummy.d new file mode 100644 index 0000000..daee233 --- /dev/null +++ b/test/version-filters-source-dep/source-dep/source/dummy.d @@ -0,0 +1,7 @@ +module sourcedep.dummy; + +version (Parent) static assert(0, "Expected Parent to not be set"); +version (SourceDep) {} else static assert(0, "Expected SourceDep to be set"); + +debug (dParent) static assert(0, "Expected dParent to not be set"); +debug (dSourceDep) {} else static assert(0, "Expected dSourceDep to be set"); diff --git a/test/version-filters-source-dep/source/app.d b/test/version-filters-source-dep/source/app.d new file mode 100644 index 0000000..13de8f5 --- /dev/null +++ b/test/version-filters-source-dep/source/app.d @@ -0,0 +1,9 @@ +version (Parent) static assert(0, "Expected Parent to not be set"); +version (SourceDep) {} else static assert(0, "Expected SourceDep to be set"); + +debug (dParent) static assert(0, "Expected dParent to not be set"); +debug (dSourceDep) {} else static assert(0, "Expected dSourceDep to be set"); + +void main() +{ +} diff --git a/test/version-filters.sh b/test/version-filters.sh new file mode 100755 index 0000000..e92f3fa --- /dev/null +++ b/test/version-filters.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +. $(dirname "${BASH_SOURCE[0]}")/common.sh + +$DUB build --root="$CURR_DIR/version-filters" --filter-versions +$DUB build --root="$CURR_DIR/version-filters-diamond" --filter-versions +$DUB build --root="$CURR_DIR/version-filters-source-dep" --filter-versions +$DUB build --root="$CURR_DIR/version-filters-none" --filter-versions diff --git a/test/version-filters/.gitignore b/test/version-filters/.gitignore new file mode 100644 index 0000000..c09a597 --- /dev/null +++ b/test/version-filters/.gitignore @@ -0,0 +1,15 @@ +.dub +docs.json +__dummy.html +docs/ +issue1262-version-inheritance-diamond +issue1262-version-inheritance-diamond.so +issue1262-version-inheritance-diamond.dylib +issue1262-version-inheritance-diamond.dll +issue1262-version-inheritance-diamond.a +issue1262-version-inheritance-diamond.lib +issue1262-version-inheritance-diamond-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/version-filters/.no_build b/test/version-filters/.no_build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters/.no_build diff --git a/test/version-filters/.no_run b/test/version-filters/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters/.no_run diff --git a/test/version-filters/.no_test b/test/version-filters/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/version-filters/.no_test diff --git a/test/version-filters/daughter/.gitignore b/test/version-filters/daughter/.gitignore new file mode 100644 index 0000000..f190acb --- /dev/null +++ b/test/version-filters/daughter/.gitignore @@ -0,0 +1,14 @@ +.dub +docs.json +__dummy.html +docs/ +daughter.so +daughter.dylib +daughter.dll +daughter.a +daughter.lib +daughter-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/version-filters/daughter/dub.sdl b/test/version-filters/daughter/dub.sdl new file mode 100644 index 0000000..7eb94da --- /dev/null +++ b/test/version-filters/daughter/dub.sdl @@ -0,0 +1,5 @@ +name "daughter" +versions "Daughter" +debugVersions "dDaughter" +x:versionFilters "Daughter" "Parent" +x:debugVersionFilters "dDaughter" "dParent" diff --git a/test/version-filters/daughter/source/dummy.d b/test/version-filters/daughter/source/dummy.d new file mode 100644 index 0000000..7295801 --- /dev/null +++ b/test/version-filters/daughter/source/dummy.d @@ -0,0 +1,12 @@ +module daughter.dummy; + +version (Parent) {} else static assert(0, "Expected Parent to be set"); +version (Daughter) {} else static assert(0, "Expected Daughter to be set"); +version (Son) static assert(0, "Expected Son to not be set"); + +debug (dParent) {} else static assert(0, "Expected dParent to be set"); +debug (dDaughter) {} else static assert(0, "Expected dDaughter to be set"); +debug (dSon) static assert(0, "Expected dSon to not be set"); + +version (Have_daughter) static assert(0, "Expected Have_daughter to not be set"); +version (Have_son) static assert(0, "Expected Have_son to not be set"); diff --git a/test/version-filters/dub.sdl b/test/version-filters/dub.sdl new file mode 100644 index 0000000..9f79da4 --- /dev/null +++ b/test/version-filters/dub.sdl @@ -0,0 +1,7 @@ +name "version-filters" +versions "Parent" +debugVersions "dParent" +x:versionFilters "Parent" +x:debugVersionFilters "dParent" +dependency "daughter" path="daughter" +dependency "son" path="son" diff --git a/test/version-filters/son/.gitignore b/test/version-filters/son/.gitignore new file mode 100644 index 0000000..601a33b --- /dev/null +++ b/test/version-filters/son/.gitignore @@ -0,0 +1,14 @@ +.dub +docs.json +__dummy.html +docs/ +son.so +son.dylib +son.dll +son.a +son.lib +son-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/version-filters/son/dub.sdl b/test/version-filters/son/dub.sdl new file mode 100644 index 0000000..e851dd6 --- /dev/null +++ b/test/version-filters/son/dub.sdl @@ -0,0 +1,5 @@ +name "son" +versions "Son" +debugVersions "dSon" +x:versionFilters "Son" +x:debugVersionFilters "dSon" diff --git a/test/version-filters/son/source/dummy.d b/test/version-filters/son/source/dummy.d new file mode 100644 index 0000000..0cfbcd3 --- /dev/null +++ b/test/version-filters/son/source/dummy.d @@ -0,0 +1,12 @@ +module son.dummy; + +version (Parent) static assert(0, "Expected Parent to not be set"); +version (Daughter) static assert(0, "Expected Daughter to not be set"); +version (Son) {} else static assert(0, "Expected Son to be set"); + +debug (dParent) static assert(0, "Expected dParent to not be set"); +debug (dDaughter) static assert(0, "Expected dDaughter to not be set"); +debug (dSon) {} else static assert(0, "Expected dSon to be set"); + +version (Have_daughter) static assert(0, "Expected Have_daughter to not be set"); +version (Have_son) static assert(0, "Expected Have_son to not be set"); diff --git a/test/version-filters/source/app.d b/test/version-filters/source/app.d new file mode 100644 index 0000000..e674170 --- /dev/null +++ b/test/version-filters/source/app.d @@ -0,0 +1,14 @@ +version (Parent) {} else static assert(0, "Expected Parent to be set"); // local +version (Daughter) {} else static assert(0, "Expected Daughter to be set"); // via dependency +version (Son) {} else static assert(0, "Expected Son to be set"); // via dependency + +debug (dParent) {} else static assert(0, "Expected dParent to be set"); // local +debug (dDaughter) {} else static assert(0, "Expected dDaughter to be set"); // via dependency +debug (dSon) {} else static assert(0, "Expected dSon to be set"); // via dependency + +version (Have_daugther) static assert(0, "Expected Have_daugther to not be set"); +version (Have_son) static assert(0, "Expected Have_son to not be set"); + +void main() +{ +}