diff --git a/.codecov.yml b/.codecov.yml index e2ed4ad..b012da1 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,14 +1,34 @@ # Documentation: https://docs.codecov.io/docs/codecov-yaml +# Validate with: `curl --data-binary @.codecov.yml https://codecov.io/validate` + +codecov: + notify: + # We don't want to wait for the CodeCov report + # See https://github.com/codecov/support/issues/312 + require_ci_to_pass: false + after_n_builds: 1 # send notifications after the first upload + wait_for_ci: false + + bot: dlang-bot + + # At Travis, the PR is merged into `master` before the testsuite is run. + # This allows CodeCov to adjust the resulting coverage diff, s.t. it matches + # with the GitHub diff. + # https://github.com/codecov/support/issues/363 + # https://docs.codecov.io/v4.3.6/docs/comparing-commits + allow_coverage_offsets: true coverage: precision: 3 round: down range: "80...100" + # Learn more at https://docs.codecov.io/docs/commit-status status: - # Learn more at https://docs.codecov.io/docs/commit-status - project: true - patch: true - changes: true + project: off + changes: off + patch: + default: + threshold: 5 comment: false diff --git a/.gitignore b/.gitignore index 75e23c8..275a4b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.o *.obj +*~ .dub .directory @@ -13,6 +14,8 @@ /bin/__test__library-nonet__ /bin/__test__library__ /bin/dub-test-library +/bin/libdub.a +/bin/dub-* # Ignore files or directories created by the test suite. /test/custom-source-main-bug487/custom-source-main-bug487 @@ -26,6 +29,13 @@ /test/expected-issue616-output /test/describe-project/dummy.dat /test/describe-project/dummy-dep1.dat +/test/*/main/main +/test/*/*test-library +/test/*/*test-application +/test/*/exec-simple # Ignore coverage files cov/ + +# Ignore auto-generated docs +/docs diff --git a/.travis.yml b/.travis.yml index 86f505a..8ff60e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,16 +2,25 @@ dist: trusty sudo: false -matrix: +addons: + apt: + packages: + - libevent-dev + +script: + - ./travis-ci.sh + +jobs: + allow_failures: + - d: gdc include: - - d: dmd-nightly + - stage: test + d: dmd-2.078.0 + env: [FRONTEND=2.078] + - d: dmd-2.077.1 + env: [FRONTEND=2.077, COVERAGE=true] + - d: dmd-2.076.1 env: [FRONTEND=2.076] - - d: dmd-beta - env: [FRONTEND=2.076] - - d: dmd - env: - - [FRONTEND=2.075] - - [COVERAGE=true] - d: dmd-2.075.1 env: [FRONTEND=2.075] - d: dmd-2.074.1 @@ -28,12 +37,14 @@ env: [FRONTEND=2.069] - d: dmd-2.068.2 env: [FRONTEND=2.068] - - d: dmd-2.067.1 - env: [FRONTEND=2.067] - - d: ldc-beta - env: [FRONTEND=2.073] - - d: ldc - env: [FRONTEND=2.073] + - d: ldc-1.7.0 + env: [FRONTEND=2.077] + - d: ldc-1.6.0 + env: [FRONTEND=2.076] + - d: ldc-1.5.0 + env: [FRONTEND=2.075] + - d: ldc-1.4.0 + env: [FRONTEND=2.074] - d: ldc-1.3.0 env: [FRONTEND=2.073] - d: ldc-1.2.0 @@ -42,21 +53,61 @@ env: [FRONTEND=2.071] - d: ldc-1.0.0 env: [FRONTEND=2.070] - - d: ldc-0.17.2 - env: [FRONTEND=2.068] - d: gdc env: [FRONTEND=2.068] - d: gdc-4.8.5 env: [FRONTEND=2.068] - - allow_failures: - - d: gdc - -addons: - apt: - packages: - - libevent-dev - -script: - - deactivate # deactivate host compiler - - ./travis-ci.sh + - stage: deploy + d: dmd + os: osx + script: echo "Deploying to GitHub releases ..." && ./release.sh + deploy: + - provider: releases + file_glob: true + file: bin/dub-*.tar.gz + skip_cleanup: true + api_key: $GH_REPO_TOKEN + on: + tags: true + - d: dmd + script: echo "Deploying to GitHub releases ..." && ./release.sh + env: [ARCH=32] + addons: + apt: + packages: + - g++-multilib + - libcurl4-openssl-dev:i386 + deploy: + - provider: releases + file_glob: true + file: bin/dub-*.tar.gz + skip_cleanup: true + api_key: $GH_REPO_TOKEN + on: + tags: true + - d: dmd + script: echo "Deploying to GitHub releases ..." && ./release.sh + deploy: + - provider: releases + file_glob: true + file: bin/dub-*.tar.gz + skip_cleanup: true + api_key: $GH_REPO_TOKEN + on: + tags: true + - stage: update-latest + script: echo "Deploying to GitHub pages ..." && mkdir -p docs && git describe --abbrev=0 --tags > docs/LATEST + deploy: + - provider: pages + skip_cleanup: true + local_dir: docs + github_token: $GH_REPO_TOKEN + on: + tags: true +stages: + - name: test + if: type = pull_request or (type = push and branch = master) + - name: deploy + if: type = push and tag =~ ^v + - name: update-latest + if: type = push and tag =~ ^v diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..6c520e4 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,26 @@ +## Architecture + +![architecture](architecture.png) + +## Terminology + +
+
Package
+
A locally available version of a dub package, consisting of sources, binaries, and described by it's dub.sdl/json file.
+
PackageSupplier
+
A source to search and fetch package versions (zip bundles) from.
+
PackageManager
+
Responsible to manage packages (fetched or add-local packages), and overrides.
+
PackageRecipe
+
Abstract description of package sources, targets, configurations, and build settings.
+
Generator
+
Responsible for generating a build recipe (e.g. CMakeLists.txt, VS .sln) for a package, config, and build type. Direct builds (dmd, rdmd) are also implemented as generators. +
PackageDependency
+
Unresolved, abstract specification of a dependency, e.g. dependency "vibe-d" version="~>0.8.1".
+
DependencyResolver
+
Algorithm to resolve package dependencies to specific package versions (dub.selections.json), searching available package versions in package suppliers.
+
Target
+
A build output like a static library or executable.
+
BuildCache
+
Caches targets for a specific build id.
+
diff --git a/appveyor.yml b/appveyor.yml index 5a05c13..143d03a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,13 +26,10 @@ DVersion: stable arch: x86 - DC: ldc - DVersion: beta - arch: x64 - - DC: ldc DVersion: stable arch: x64 - DC: ldc - DVersion: 1.2.0 + DVersion: 1.7.0 arch: x64 skip_tags: false @@ -62,17 +59,18 @@ - ps: function ResolveLatestLDC { $version = $env:DVersion; + $arch = $env:arch; if($version -eq "stable") { $latest = (Invoke-WebRequest "https://ldc-developers.github.io/LATEST").toString().replace("`n","").replace("`r",""); - $url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-win64-msvc.zip"; + $url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-windows-$($arch).7z"; }elseif($version -eq "beta") { $latest = (Invoke-WebRequest "https://ldc-developers.github.io/LATEST_BETA").toString().replace("`n","").replace("`r",""); - $url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-win64-msvc.zip"; + $url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-windows-$($arch).7z"; } else { $latest = $version; - $url = "https://github.com/ldc-developers/ldc/releases/download/v$($version)/ldc2-$($version)-win64-msvc.zip"; + $url = "https://github.com/ldc-developers/ldc/releases/download/v$($version)/ldc2-$($version)-windows-$($arch).7z"; } - $env:PATH += ";C:\ldc2-$($latest)-win64-msvc\bin"; + $env:PATH += ";C:\ldc2-$($latest)-windows-$($arch)\bin"; $env:DC = "ldc2"; return $url; } diff --git a/architecture.graphmlz b/architecture.graphmlz new file mode 100644 index 0000000..73716a1 --- /dev/null +++ b/architecture.graphmlz Binary files differ diff --git a/architecture.png b/architecture.png new file mode 100644 index 0000000..a66bff5 --- /dev/null +++ b/architecture.png Binary files differ diff --git a/build-gdc.sh b/build-gdc.sh index 1924b08..203f8c9 100755 --- a/build-gdc.sh +++ b/build-gdc.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash set -e if [ "$GDC" = "" ]; then diff --git a/dub.selections.json b/dub.selections.json index dd9a304..52e7c92 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -4,14 +4,15 @@ "botan": "1.12.9", "botan-math": "1.0.3", "diet-ng": "1.4.3", - "eventcore": "0.8.26", + "eventcore": "0.8.27", "libasync": "0.8.3", "libev": "5.0.0+4.04", "libevent": "2.0.2+2.0.16", "memutils": "0.4.9", "openssl": "1.1.6+1.0.1g", + "stdx-allocator": "2.77.0", "taggedalgebraic": "0.10.8", - "vibe-core": "1.3.0", - "vibe-d": "0.8.3-alpha.1" + "vibe-core": "1.4.0-alpha.1", + "vibe-d": "0.8.3-alpha.3" } } diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..e889a30 --- /dev/null +++ b/release.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -v -e -o pipefail + +VERSION=$(git describe --abbrev=0 --tags) +ARCH="${ARCH:-64}" + +unameOut="$(uname -s)" +case "$unameOut" in + Linux*) OS=linux; ;; + Darwin*) OS=osx; ;; + *) echo "Unknown OS: $unameOut"; exit 1 +esac + +case "$ARCH" in + 64) ARCH_SUFFIX="x86_64";; + 32) ARCH_SUFFIX="x86";; + *) echo "Unknown ARCH: $ARCH"; exit 1 +esac + +archiveName="dub-$VERSION-$OS-$ARCH_SUFFIX.tar.gz" + +echo "Building $archiveName" +DFLAGS="-release -m$ARCH" DMD="$(command -v $DMD)" ./build.sh +tar cvfz "bin/$archiveName" -C bin dub diff --git a/scripts/man/.gitignore b/scripts/man/.gitignore new file mode 100644 index 0000000..2c2a370 --- /dev/null +++ b/scripts/man/.gitignore @@ -0,0 +1,2 @@ +*.1 +/gen_man diff --git a/scripts/man/README.md b/scripts/man/README.md new file mode 100644 index 0000000..1b7484a --- /dev/null +++ b/scripts/man/README.md @@ -0,0 +1,13 @@ +1) Build +-------- + +```shell +./gen_man.d +``` + +2) Preview +---------- + +```shell +man -l dub.1 +``` diff --git a/scripts/man/gen_man.d b/scripts/man/gen_man.d new file mode 100755 index 0000000..1524ea1 --- /dev/null +++ b/scripts/man/gen_man.d @@ -0,0 +1,187 @@ +#!/usr/bin/env dub +/+dub.sdl: +dependency "dub" path="../.." ++/ + +import std.algorithm, std.conv, std.format, std.path, std.range, std.stdio; +import dub.commandline; + +string italic(string w) +{ + return `\fI` ~ w ~ `\fR`; +} + +string bold(string w) +{ + return `\fB` ~ w ~ `\fR`; +} + +string header(string heading) +{ + return ".SH " ~ heading; +} + +string br(string s) +{ + return ".BR " ~ s; +} + +struct Config +{ + import std.datetime; + SysTime date; + + static Config init(){ + import std.process : environment; + Config config; + config.date = Clock.currTime; + auto diffable = environment.get("DIFFABLE", "0"); + if (diffable == "1") + config.date = SysTime(DateTime(2018, 01, 01)); + + config.cwd = __FILE_FULL_PATH__.dirName; + return config; + } + string cwd; +} + +void writeHeader(ref File manFile, string manName, const Config config) +{ + static immutable manHeader = +`.TH %s 1 "%s" "The D Language Foundation" "The D Language Foundation" +.SH NAME`; + manFile.writefln(manHeader, manName, config.date.toISOExtString.take(10)); +} + +void writeFooter(ref File manFile, string seeAlso, const Config config) +{ + static immutable manFooter = +`.SH FILES +\fIdub\&.sdl\fR, \fIdub\&.json\fR +.SH AUTHOR +Copyright (c) 1999-%s by The D Language Foundation +.SH "ONLINE DOCUMENTATION" +.UR http://code.dlang.org/docs/commandline +.UE http://code.dlang.org/docs/commandline +.SH "SEE ALSO" +%s`; + manFile.writefln(manFooter, config.date.year, seeAlso); +} + +void writeMainManFile(CommandArgs args, CommandGroup[] commands, + string fileName, const Config config) +{ + auto manFile = File(config.cwd.buildPath(fileName), "w"); + manFile.writeHeader("DUB", config); + auto seeAlso = ["dmd(1)".br, "rdmd(1)"].joiner("\n").to!string; + scope(exit) manFile.writeFooter(seeAlso, config); + + alias writeln = (m) => manFile.writeln(m); + writeln(`dub \- Package and build management system for D`); + writeln("SYNOPSIS".header); + writeln(`.B dub +[\-\-version] +[\fICOMMAND\fR] +[\fIOPTIONS\&.\&.\&.\fR] +[\-\- [\fIAPPLICATION ARGUMENTS\&.\&.\&.\fR]]`); + + writeln("DESCRIPTION".header); + writeln(`Manages the DUB project in the current directory\&. DUB can serve as a build +system and a package manager, automatically keeping track of project's +dependencies \- both downloading them and linking them into the application.`); + + writeln(".SH COMMANDS"); + foreach (grp; commands) { + foreach (cmd; grp.commands) { + writeln(".TP"); + writeln(cmd.name.bold); + writeln(cmd.helpText.joiner("\n")); + } + } + + writeln("COMMON OPTIONS".header); + args.writeArgs(manFile); +} + +string highlightArguments(string args) +{ + import std.regex : regex, replaceAll; + static immutable re = regex("<([^>]*)>"); + static immutable reReplacement = "<%s>".format(`$1`.italic); + return args.replaceAll(re, reReplacement); +} + +void writeArgs(CommandArgs args, ref File manFile) +{ + alias write = (m) => manFile.write(m); + foreach (arg; args.recognizedArgs) + { + auto names = arg.names.split("|"); + assert(names.length == 1 || names.length == 2); + string sarg = names[0].length == 1 ? names[0] : null; + string larg = names[0].length > 1 ? names[0] : names.length > 1 ? names[1] : null; + write(".IP "); + if (sarg !is null) { + write("-%s".format(sarg)); + if (larg !is null) + write(", "); + } + if (larg !is null) { + write("--%s".format(larg)); + if (!arg.defaultValue.peek!bool) + write("=VALUE"); + } + manFile.writeln; + manFile.writeln(arg.helpText.join("\n")); + } +} + +void writeManFile(Command command, const Config config) +{ + import std.uni : toUpper; + + auto args = new CommandArgs(null); + command.prepare(args); + string fileName = format("dub-%s.1", command.name); + auto manFile = File(config.cwd.buildPath(fileName), "w"); + auto manName = format("DUB-%s", command.name).toUpper; + manFile.writeHeader(manName, config); + static immutable seeAlso = ["dmd(1)".br, "dub(1)"].joiner("\n").to!string; + scope(exit) manFile.writeFooter(seeAlso, config); + + alias writeln = (m) => manFile.writeln(m); + writeln(`dub \- Package and build management system for D`); + + writeln("SYNOPSIS".header); + writeln("dub %s".format(command.name).bold); + writeln(command.argumentsPattern.highlightArguments); + writeln(`OPTIONS\&.\&.\&.`.italic); + if (command.acceptsAppArgs) + { + writeln("[-- <%s>]".format("application arguments...".italic)); + } + + writeln("DESCRIPTION".header); + writeln(command.helpText.joiner("\n\n")); + writeln("OPTIONS".header); + args.writeArgs(manFile); +} + +void main() +{ + Config config = Config.init; + auto commands = getCommands(); + + // main dub.1 + { + CommonOptions options; + auto args = new CommandArgs(null); + options.prepare(args); + args.writeMainManFile(commands, "dub.1", config); + } + + // options for each specific command + foreach (cmd; commands.map!(a => a.commands).joiner) { + cmd.writeManFile(config); + } +} diff --git a/scripts/rpm-package/make_installer.sh b/scripts/rpm-package/make_installer.sh index eb2ab86..097e9c4 100755 --- a/scripts/rpm-package/make_installer.sh +++ b/scripts/rpm-package/make_installer.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash set -e cd ../../ DUB_PATH=`pwd` diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 9c6702c..91b0b32 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -134,6 +134,7 @@ else if (options.verbose) loglevel = LogLevel.diagnostic; else if (options.vquiet) loglevel = LogLevel.none; else if (options.quiet) loglevel = LogLevel.warn; + else if (options.verror) loglevel = LogLevel.error; setLogLevel(loglevel); } catch (Throwable e) { logError("Error processing arguments: %s", e.msg); @@ -267,7 +268,7 @@ /** Contains and parses options common to all commands. */ struct CommonOptions { - bool verbose, vverbose, quiet, vquiet; + bool verbose, vverbose, quiet, vquiet, verror; bool help, annotate, bare; string[] registry_urls; string root_path; @@ -292,6 +293,7 @@ args.getopt("v|verbose", &verbose, ["Print diagnostic output"]); args.getopt("vverbose", &vverbose, ["Print debug output"]); args.getopt("q|quiet", &quiet, ["Only print warnings and errors"]); + args.getopt("verror", &verror, ["Only print errors"]); args.getopt("vquiet", &vquiet, ["Print no messages"]); args.getopt("cache", &placementLocation, ["Puts any fetched packages in the specified location [local|system|user]."]); } @@ -631,6 +633,7 @@ protected void setupPackage(Dub dub, string package_name, string default_build_type = "debug") { if (!m_compilerName.length) m_compilerName = dub.defaultCompiler; + if (!m_arch.length) m_arch = dub.defaultArchitecture; 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 9f54140..28b98be 100644 --- a/source/dub/compilers/buildsettings.d +++ b/source/dub/compilers/buildsettings.d @@ -10,7 +10,7 @@ import dub.internal.vibecompat.inet.path; import std.array : array; -import std.algorithm : filter; +import std.algorithm : filter, any; import std.path : globMatch; import std.typecons : BitFlags; @@ -108,23 +108,17 @@ void removeOptions(in BuildOptions value) { this.options &= ~value; } private: - // Adds vals to arr without adding duplicates. - static void add(ref string[] arr, in string[] vals, bool no_duplicates = true) + static auto filterDuplicates(T)(ref string[] arr, in T vals, bool noDuplicates = true) { - if (!no_duplicates) { - arr ~= vals; - return; - } + return noDuplicates + ? vals.filter!(filtered => !arr.any!(item => item == filtered)).array + : vals; + } - foreach (v; vals) { - bool found = false; - foreach (i; 0 .. arr.length) - if (arr[i] == v) { - found = true; - break; - } - if (!found) arr ~= v; - } + // Append vals to arr without adding duplicates. + static void add(ref string[] arr, in string[] vals, bool noDuplicates = true) + { + arr ~= filterDuplicates(arr, vals, noDuplicates); } unittest @@ -136,22 +130,10 @@ assert(ary == ["-dip1000", "-vgc", "-dip1001", "-vgc"]); } - static void prepend(ref string[] arr, in string[] vals, bool no_duplicates = true) + // Prepend arr by vals without adding duplicates. + static void prepend(ref string[] arr, in string[] vals, bool noDuplicates = true) { - if (!no_duplicates) { - arr = vals ~ arr; - return; - } - - foreach_reverse (v; vals) { - bool found = false; - foreach (i; 0 .. arr.length) - if (arr[i] == v) { - found = true; - break; - } - if (!found) arr = v ~ arr; - } + arr = filterDuplicates(arr, vals, noDuplicates) ~ arr; } unittest @@ -186,16 +168,27 @@ assert(ary == ["path/foo.txt", "path2/foo2.txt"]); } - static void removePaths(ref string[] arr, in string[] vals) + 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); + } + + static void removeValuesFromArray(alias Match)(ref string[] arr, in string[] vals) { bool matches(string s) { - foreach (p; vals) - if (NativePath(s) == NativePath(p) || globMatch(s, p)) - return true; - return false; + return vals.any!(item => Match(s, item)); } - arr = arr.filter!(s => !matches(s))().array(); + arr = arr.filter!(s => !matches(s)).array; + } + + static void removePaths(ref string[] arr, in string[] vals) + { + removeValuesFromArray!(pathMatch)(arr, vals); } unittest @@ -211,14 +204,7 @@ static void remove(ref string[] arr, in string[] vals) { - bool matches(string s) - { - foreach (p; vals) - if (s == p) - return true; - return false; - } - arr = arr.filter!(s => !matches(s))().array(); + removeValuesFromArray!((a, b) => a == b)(arr, vals); } unittest diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d index f70556d..e5864b4 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -28,7 +28,7 @@ tuple(BuildOption.releaseMode, ["-release"]), tuple(BuildOption.coverage, ["-cov"]), tuple(BuildOption.debugInfo, ["-g"]), - tuple(BuildOption.debugInfoC, ["-gc"]), + tuple(BuildOption.debugInfoC, ["-g"]), tuple(BuildOption.alwaysStackFrame, ["-gs"]), tuple(BuildOption.stackStomping, ["-gx"]), tuple(BuildOption.inline, ["-inline"]), diff --git a/source/dub/dependencyresolver.d b/source/dub/dependencyresolver.d index f5e9dcb..1662cd3 100644 --- a/source/dub/dependencyresolver.d +++ b/source/dub/dependencyresolver.d @@ -11,7 +11,7 @@ import dub.internal.vibecompat.core.log; import std.algorithm : all, canFind, filter, map, sort; -import std.array : appender, array; +import std.array : appender, array, join; import std.conv : to; import std.exception : enforce; import std.typecons : Nullable; @@ -54,6 +54,25 @@ } } + private static struct PackageConfigs + { + static struct Depender + { + TreeNode origin; + TreeNodes dependency; + } + + // all possible configurations to test for this package + CONFIG[] allConfigs; + + // determines whether this package has any dependencies, may be + // different from allConfigs.length > 0 after certain configurations + // have been filtered out + bool anyConfig; + + Depender[] origins; + } + CONFIG[string] resolve(TreeNode root, bool throw_on_failure = true) { auto root_base_pack = basePackage(root.pack); @@ -61,8 +80,7 @@ // find all possible configurations of each possible dependency size_t[string] package_indices; string[size_t] package_names; - CONFIG[][] all_configs; - bool[] any_config; + PackageConfigs[] configs; bool[string] maybe_optional_deps; bool[TreeNode] visited; @@ -73,38 +91,40 @@ foreach (ch; getChildren(parent)) { auto basepack = basePackage(ch.pack); - auto pidx = all_configs.length; + auto pidx = configs.length; if (ch.depType != DependencyType.required) maybe_optional_deps[ch.pack] = true; - CONFIG[] configs; + PackageConfigs config; if (auto pi = basepack in package_indices) { pidx = *pi; - configs = all_configs[*pi]; + config = configs[*pi]; } else { - if (basepack == root_base_pack) configs = [root.config]; - else configs = getAllConfigs(basepack); - all_configs ~= configs; + if (basepack == root_base_pack) config.allConfigs = [root.config]; + else config.allConfigs = getAllConfigs(basepack); + configs ~= config; package_indices[basepack] = pidx; package_names[pidx] = basepack; } foreach (c; getSpecificConfigs(basepack, ch)) - if (!configs.canFind(c)) - configs = c ~ configs; + if (!config.allConfigs.canFind(c)) + config.allConfigs = c ~ config.allConfigs; - if (any_config.length <= pidx) any_config.length = pidx+1; - if (configs.length > 0) - any_config[pidx] = true; + if (config.allConfigs.length > 0) + config.anyConfig = true; + + // store package depending on this for better error messages + config.origins ~= PackageConfigs.Depender(parent, ch); // eliminate configurations from which we know that they can't satisfy // the uniquely defined root dependencies (==version or ~branch style dependencies) - if (parent_unique) configs = configs.filter!(c => matches(ch.configs, c)).array; + if (parent_unique) config.allConfigs = config.allConfigs.filter!(c => matches(ch.configs, c)).array; - all_configs[pidx] = configs; + configs[pidx] = config; - foreach (v; configs) - findConfigsRec(TreeNode(ch.pack, v), parent_unique && configs.length == 1); + foreach (v; config.allConfigs) + findConfigsRec(TreeNode(ch.pack, v), parent_unique && config.allConfigs.length == 1); } } findConfigsRec(root, true); @@ -113,14 +133,14 @@ // this is used to properly support optional dependencies (when // getChildren() returns no configurations for an optional dependency, // but getAllConfigs() has already provided an existing list of configs) - foreach (i, ref cfgs; all_configs) - if (cfgs.length == 0 || package_names[i] in maybe_optional_deps) - cfgs = cfgs ~ CONFIG.invalid; + foreach (i, ref cfgs; configs) + if (cfgs.allConfigs.length == 0 || package_names[i] in maybe_optional_deps) + cfgs.allConfigs = cfgs.allConfigs ~ CONFIG.invalid; logDebug("Configurations used for dependency resolution:"); - foreach (n, i; package_indices) logDebug(" %s (%s%s): %s", n, i, n in maybe_optional_deps ? ", maybe optional" : ", required", all_configs[i]); + foreach (n, i; package_indices) logDebug(" %s (%s%s): %s", n, i, n in maybe_optional_deps ? ", maybe optional" : ", required", configs[i]); - auto config_indices = new size_t[all_configs.length]; + auto config_indices = new size_t[configs.length]; config_indices[] = 0; visited = null; @@ -142,7 +162,9 @@ // get the current config/version of the current dependency sizediff_t childidx = package_indices[basepack]; - if (all_configs[childidx].length == 1 && all_configs[childidx][0] == CONFIG.invalid) { + auto child = configs[childidx]; + + if (child.allConfigs.length == 1 && child.allConfigs[0] == CONFIG.invalid) { // ignore invalid optional dependencies if (ch.depType != DependencyType.required) continue; @@ -154,8 +176,10 @@ logError("Dependency \"%s\" of %s contains upper case letters, but must be lower case.", ch.pack, parent.pack); if (getAllConfigs(lp).length) logError("Did you mean \"%s\"?", lp); } - if (any_config[childidx]) - throw new Exception(format("Root package %s reference %s %s cannot be satisfied.", parent.pack, ch.pack, ch.configs)); + if (child.anyConfig) + throw new Exception(format("Root package %s reference %s %s cannot be satisfied.\nPackages causing the conflict:\n\t%s", + parent.pack, ch.pack, ch.configs, + child.origins.map!(a => a.origin.pack ~ " depends on " ~ a.dependency.configs.to!string).join("\n\t"))); else throw new Exception(format("Root package %s references unknown package %s", parent.pack, ch.pack)); } @@ -166,7 +190,7 @@ maxcpi = parentidx; } } else { - auto config = all_configs[childidx][config_indices[childidx]]; + auto config = child.allConfigs[config_indices[childidx]]; auto chnode = TreeNode(ch.pack, config); if (config == CONFIG.invalid || !matches(ch.configs, config)) { @@ -221,10 +245,10 @@ // print out current iteration state logDebug("Interation (ci=%s) %s", conflict_index, { import std.array : join; - auto cs = new string[all_configs.length]; + auto cs = new string[configs.length]; foreach (p, i; package_indices) { - if (all_configs[i].length) - cs[i] = p~" "~all_configs[i][config_indices[i]].to!string~(i >= 0 && i >= conflict_index ? " (C)" : ""); + if (configs[i].allConfigs.length) + cs[i] = p~" "~configs[i].allConfigs[config_indices[i]].to!string~(i >= 0 && i >= conflict_index ? " (C)" : ""); else cs[i] = p ~ " [no config]"; } return cs.join(", "); @@ -233,8 +257,8 @@ if (conflict_index < 0) { CONFIG[string] ret; foreach (p, i; package_indices) - if (all_configs[i].length) { - auto cfg = all_configs[i][config_indices[i]]; + if (configs[i].allConfigs.length) { + auto cfg = configs[i].allConfigs[config_indices[i]]; if (cfg != CONFIG.invalid) ret[p] = cfg; } logDebug("Resolved dependencies before optional-purge: %s", ret.byKey.map!(k => k~" "~ret[k].to!string)); @@ -246,7 +270,7 @@ // find the next combination of configurations foreach_reverse (pi, ref i; config_indices) { if (pi > conflict_index) i = 0; - else if (++i >= all_configs[pi].length) i = 0; + else if (++i >= configs[pi].allConfigs.length) i = 0; else break; } if (config_indices.all!"a==0") { diff --git a/source/dub/dub.d b/source/dub/dub.d index 5b36338..47bf48b 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -106,6 +106,7 @@ Project m_project; NativePath m_overrideSearchPath; string m_defaultCompiler; + string m_defaultArchitecture; } /** The default placement location of fetched packages. @@ -159,7 +160,7 @@ ps ~= defaultPackageSuppliers(); m_packageSuppliers = ps; - m_packageManager = new PackageManager(m_dirs.userSettings, m_dirs.systemSettings); + m_packageManager = new PackageManager(m_dirs.localRepository, m_dirs.systemSettings); updatePackageSearchPath(); } @@ -198,12 +199,18 @@ import std.file : tempDir; version(Windows) { m_dirs.systemSettings = NativePath(environment.get("ProgramData")) ~ "dub/"; - m_dirs.userSettings = NativePath(environment.get("APPDATA")) ~ "dub/"; + immutable appDataDir = environment.get("APPDATA"); + m_dirs.userSettings = NativePath(appDataDir) ~ "dub/"; + m_dirs.localRepository = NativePath(environment.get("LOCALAPPDATA", appDataDir)) ~ "dub"; + + migrateRepositoryFromRoaming(m_dirs.userSettings ~"\\packages", m_dirs.localRepository ~ "\\packages"); + } else version(Posix){ m_dirs.systemSettings = NativePath("/var/lib/dub/"); m_dirs.userSettings = NativePath(environment.get("HOME")) ~ ".dub/"; if (!m_dirs.userSettings.absolute) m_dirs.userSettings = NativePath(getcwd()) ~ m_dirs.userSettings; + m_dirs.localRepository = m_dirs.userSettings; } m_dirs.temp = NativePath(tempDir); @@ -213,8 +220,28 @@ m_config = new DubConfig(jsonFromFile(m_dirs.userSettings ~ "settings.json", true), m_config); determineDefaultCompiler(); + + m_defaultArchitecture = m_config.defaultArchitecture; } + version(Windows) + private void migrateRepositoryFromRoaming(NativePath roamingDir, NativePath localDir) + { + immutable roamingDirPath = roamingDir.toNativeString(); + if (!existsDirectory(roamingDir)) return; + + immutable localDirPath = localDir.toNativeString(); + logInfo("Detected a package cache in " ~ roamingDirPath ~ ". This will be migrated to " ~ localDirPath ~ ". Please wait..."); + if (!existsDirectory(localDir)) + { + mkdirRecurse(localDirPath); + } + + runCommand("xcopy /s /e /y " ~ roamingDirPath ~ " " ~ localDirPath ~ " > NUL"); + rmdirRecurse(roamingDirPath); + } + + @property void dryRun(bool v) { m_dryRun = v; } /** Returns the root path (usually the current working directory). @@ -250,6 +277,13 @@ */ @property string defaultCompiler() const { return m_defaultCompiler; } + /** Returns the default architecture to use for building D code. + + If set, the "defaultArchitecture" field of the DUB user or system + configuration file will be used. Otherwise null will be returned. + */ + @property string defaultArchitecture() const { return m_defaultArchitecture; } + /** Loads the package that resides within the configured `rootPath`. */ void loadPackage() @@ -699,7 +733,7 @@ NativePath placement; final switch (location) { case PlacementLocation.local: placement = m_rootPath; break; - case PlacementLocation.user: placement = m_dirs.userSettings ~ "packages/"; break; + case PlacementLocation.user: placement = m_dirs.localRepository ~ "packages/"; break; case PlacementLocation.system: placement = m_dirs.systemSettings ~ "packages/"; break; } @@ -1568,6 +1602,7 @@ NativePath temp; NativePath userSettings; NativePath systemSettings; + NativePath localRepository; } private class DubConfig { @@ -1598,4 +1633,12 @@ if (m_parentConfig) return m_parentConfig.defaultCompiler; return null; } + + @property string defaultArchitecture() + const { + if(auto pv = "defaultArchitecture" in m_data) + return (*pv).get!string; + if (m_parentConfig) return m_parentConfig.defaultArchitecture; + return null; + } } diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index dfb0670..144276d 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -89,18 +89,20 @@ if (!settings.config.length) settings.config = m_project.getDefaultConfiguration(settings.platform); - TargetInfo[string] targets; string[string] configs = m_project.getPackageConfigs(settings.platform, settings.config); + TargetInfo[string] targets; foreach (pack; m_project.getTopologicalPackageList(true, null, configs)) { - BuildSettings buildsettings; - buildsettings.processVars(m_project, pack, pack.getBuildSettings(settings.platform, configs[pack.name]), true); - prepareGeneration(pack, m_project, settings, buildsettings); + BuildSettings buildSettings; + auto config = configs[pack.name]; + buildSettings.processVars(m_project, pack, pack.getBuildSettings(settings.platform, config), true); + targets[pack.name] = TargetInfo(pack, [pack], config, buildSettings); + + prepareGeneration(pack, m_project, settings, buildSettings); } - string[] mainfiles; - collect(settings, m_project.rootPackage, targets, configs, mainfiles, null); - downwardsInheritSettings(m_project.rootPackage.name, targets, targets[m_project.rootPackage.name].buildSettings); + string[] mainfiles = 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; @@ -143,144 +145,284 @@ */ protected void performPostGenerateActions(GeneratorSettings settings, in TargetInfo[string] targets) {} - private BuildSettings collect(GeneratorSettings settings, Package pack, ref TargetInfo[string] targets, in string[string] configs, ref string[] main_files, string bin_pack) + /** Configure `rootPackage` and all of it's dependencies. + + 1. Merge versions, debugVersions, and inheritable build + settings from dependents to their dependencies. + + 2. Define version identifiers Have_dependency_xyz for all + direct dependencies of all packages. + + 3. Merge versions, debugVersions, and inheritable build settings from + dependencies to their dependents, so that importer and importee are ABI + compatible. This also transports all Have_dependency_xyz version + identifiers to `rootPackage`. + + 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) { - import std.algorithm : sort; + import std.algorithm : remove, sort; + import std.range : repeat; + + // 0. do shallow configuration (not including dependencies) of all packages + TargetType determineTargetType(const ref TargetInfo ti) + { + TargetType tt = ti.buildSettings.targetType; + if (ti.pack is rootPackage) { + if (tt == TargetType.autodetect || tt == TargetType.library) tt = TargetType.staticLibrary; + } else { + if (tt == TargetType.autodetect || tt == TargetType.library) tt = genSettings.combined ? TargetType.sourceLibrary : TargetType.staticLibrary; + else if (tt == TargetType.dynamicLibrary) { + logWarn("Dynamic libraries are not yet supported as dependencies - building as static library."); + tt = TargetType.staticLibrary; + } + } + if (tt != TargetType.none && tt != TargetType.sourceLibrary && ti.buildSettings.sourceFiles.empty) { + logWarn(`Configuration '%s' of package %s contains no source files. Please add {"targetType": "none"} to its package description to avoid building it.`, + ti.config, ti.pack.name); + tt = TargetType.none; + } + return tt; + } + + string[] mainSourceFiles; + bool[string] hasOutput; + + foreach (ref ti; targets.byValue) + { + auto bs = &ti.buildSettings; + // determine the actual target type + bs.targetType = determineTargetType(ti); + + switch (bs.targetType) + { + case TargetType.none: + // ignore any build settings for targetType none (only dependencies will be processed) + *bs = BuildSettings.init; + bs.targetType = TargetType.none; + break; + + case TargetType.executable: + break; + + case TargetType.dynamicLibrary: + // set -fPIC for dynamic library builds + ti.buildSettings.addOptions(BuildOption.pic); + goto default; + + default: + // remove any mainSourceFile from non-executable builds + if (bs.mainSourceFile.length) { + bs.sourceFiles = bs.sourceFiles.remove!(f => f == bs.mainSourceFile); + mainSourceFiles ~= bs.mainSourceFile; + } + break; + } + bool generatesBinary = bs.targetType != TargetType.sourceLibrary && bs.targetType != TargetType.none; + hasOutput[ti.pack.name] = generatesBinary || ti.pack is rootPackage; + } + + // mark packages as visited (only used during upwards propagation) + void[0][Package] visited; + + // collect all dependencies + void collectDependencies(Package pack, ref TargetInfo ti, TargetInfo[string] targets, size_t level = 0) + { + // use `visited` here as pkgs cannot depend on themselves + if (pack in visited) + return; + // transitive dependencies must be visited multiple times, see #1350 + immutable transitive = !hasOutput[pack.name]; + if (!transitive) + visited[pack] = typeof(visited[pack]).init; + + auto bs = &ti.buildSettings; + if (hasOutput[pack.name]) + logDebug("%sConfiguring target %s (%s %s %s)", ' '.repeat(2 * level), pack.name, bs.targetType, bs.targetPath, bs.targetName); + else + logDebug("%sConfiguring target without output %s", ' '.repeat(2 * level), pack.name); + + // get specified dependencies, e.g. vibe-d ~0.8.1 + auto deps = pack.getDependencies(targets[pack.name].config); + logDebug("deps: %s -> %(%s, %)", pack.name, deps.byKey); + foreach (depname; deps.keys.sort()) + { + auto depspec = deps[depname]; + // get selected package for that dependency, e.g. vibe-d 0.8.2-beta.2 + auto deppack = m_project.getDependency(depname, depspec.optional); + if (deppack is null) continue; // optional and not selected + + // if dependency has no output + if (!hasOutput[depname]) { + // add itself + ti.packages ~= deppack; + // and it's transitive dependencies to current target + collectDependencies(deppack, ti, targets, level + 1); + continue; + } + auto depti = &targets[depname]; + const depbs = &depti.buildSettings; + if (depbs.targetType == TargetType.executable) + continue; + // add to (link) dependencies + ti.dependencies ~= depname; + ti.linkDependencies ~= depname; + + // recurse + collectDependencies(deppack, *depti, targets, level + 1); + + // also recursively add all link dependencies of static libraries + // preserve topological sorting of dependencies for correct link order + if (depbs.targetType == TargetType.staticLibrary) + ti.linkDependencies = ti.linkDependencies.filter!(d => !depti.linkDependencies.canFind(d)).array ~ depti.linkDependencies; + } + } + + collectDependencies(rootPackage, targets[rootPackage.name], targets); + static if (__VERSION__ > 2070) + visited.clear(); + else + destroy(visited); + + // 1. downwards inherits versions, debugVersions, and inheritable build settings + static void configureDependencies(in ref TargetInfo ti, TargetInfo[string] targets, size_t level = 0) + { + // do not use `visited` here as dependencies must inherit + // configurations from *all* of their parents + logDebug("%sConfigure dependencies of %s, deps:%(%s, %)", ' '.repeat(2 * level), ti.pack.name, ti.dependencies); + foreach (depname; ti.dependencies) + { + auto pti = &targets[depname]; + mergeFromDependent(ti.buildSettings, pti.buildSettings); + configureDependencies(*pti, targets, level + 1); + } + } + + configureDependencies(targets[rootPackage.name], targets); + + // 2. add Have_dependency_xyz for all direct dependencies of a target + // (includes incorporated non-target dependencies and their dependencies) + foreach (ref ti; targets.byValue) + { + import std.range : chain; + import dub.internal.utils : stripDlangSpecialChars; + + auto bs = &ti.buildSettings; + auto pkgnames = ti.packages.map!(p => p.name).chain(ti.dependencies); + bs.addVersions(pkgnames.map!(pn => "Have_" ~ stripDlangSpecialChars(pn)).array); + } + + // 3. upwards inherit full build configurations (import paths, versions, debugVersions, ...) + void configureDependents(ref TargetInfo ti, TargetInfo[string] targets, size_t level = 0) + { + // use `visited` here as pkgs cannot depend on themselves + if (ti.pack in visited) + return; + visited[ti.pack] = typeof(visited[ti.pack]).init; + + logDiagnostic("%sConfiguring dependent %s, deps:%(%s, %)", ' '.repeat(2 * level), ti.pack.name, ti.dependencies); + // embedded non-binary dependencies + foreach (deppack; ti.packages[1 .. $]) + ti.buildSettings.add(targets[deppack.name].buildSettings); + // binary dependencies + foreach (depname; ti.dependencies) + { + auto pdepti = &targets[depname]; + configureDependents(*pdepti, targets, level + 1); + mergeFromDependency(pdepti.buildSettings, ti.buildSettings); + } + } + + configureDependents(targets[rootPackage.name], targets); + static if (__VERSION__ > 2070) + visited.clear(); + else + destroy(visited); + + // 4. 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 + // + // special support for overriding string imports in parent packages + // this is a candidate for deprecation, once an alternative approach + // has been found + if (ti.buildSettings.stringImportPaths.length) { + // override string import files (used for up to date checking) + foreach (ref f; ti.buildSettings.stringImportFiles) + { + foreach (o; overrides) + { + NativePath op; + if (f != o && NativePath(f).head == (op = NativePath(o)).head) { + logDebug("string import %s overridden by %s", f, o); + f = o; + ti.buildSettings.prependStringImportPaths(op.parentPath.toNativeString); + } + } + } + } + // add to overrides for recursion + overrides ~= ti.buildSettings.stringImportFiles; + // override dependencies + foreach (depname; ti.dependencies) + overrideStringImports(targets[depname], targets, overrides); + } + + overrideStringImports(targets[rootPackage.name], targets, null); + + // remove targets without output + foreach (name; targets.keys) + { + if (!hasOutput[name]) + targets.remove(name); + } + + return mainSourceFiles; + } + + private static void mergeFromDependent(in ref BuildSettings parent, ref BuildSettings child) + { + child.addVersions(parent.versions); + child.addDebugVersions(parent.debugVersions); + child.addOptions(BuildOptions(cast(BuildOptions)parent.options & inheritedBuildOptions)); + } + + private static void mergeFromDependency(in ref BuildSettings child, ref BuildSettings parent) + { import dub.compilers.utils : isLinkerFile; - if (auto pt = pack.name in targets) return pt.buildSettings; - - // determine the actual target type - auto shallowbs = pack.getBuildSettings(settings.platform, configs[pack.name]); - TargetType tt = shallowbs.targetType; - if (pack is m_project.rootPackage) { - if (tt == TargetType.autodetect || tt == TargetType.library) tt = TargetType.staticLibrary; - } else { - if (tt == TargetType.autodetect || tt == TargetType.library) tt = settings.combined ? TargetType.sourceLibrary : TargetType.staticLibrary; - else if (tt == TargetType.dynamicLibrary) { - logWarn("Dynamic libraries are not yet supported as dependencies - building as static library."); - tt = TargetType.staticLibrary; - } + parent.addDFlags(child.dflags); + parent.addVersions(child.versions); + parent.addDebugVersions(child.debugVersions); + parent.addImportPaths(child.importPaths); + parent.addStringImportPaths(child.stringImportPaths); + // linking of static libraries is done by parent + if (child.targetType == TargetType.staticLibrary) { + parent.addLinkerFiles(child.sourceFiles.filter!isLinkerFile.array); + parent.addLibs(child.libs); + parent.addLFlags(child.lflags); } - if (tt != TargetType.none && tt != TargetType.sourceLibrary && shallowbs.sourceFiles.empty) { - logWarn(`Configuration '%s' of package %s contains no source files. Please add {"targetType": "none"} to its package description to avoid building it.`, - configs[pack.name], pack.name); - tt = TargetType.none; - } - - shallowbs.targetType = tt; - bool generates_binary = tt != TargetType.sourceLibrary && tt != TargetType.none; - bool is_target = generates_binary || pack is m_project.rootPackage; - - if (tt == TargetType.none) { - // ignore any build settings for targetType none (only dependencies will be processed) - shallowbs = BuildSettings.init; - shallowbs.targetType = TargetType.none; - } - - // start to build up the build settings - BuildSettings buildsettings; - processVars(buildsettings, m_project, pack, shallowbs, true); - - // remove any mainSourceFile from library builds - if (buildsettings.targetType != TargetType.executable && buildsettings.mainSourceFile.length) { - buildsettings.sourceFiles = buildsettings.sourceFiles.filter!(f => f != buildsettings.mainSourceFile)().array; - main_files ~= buildsettings.mainSourceFile; - } - - // set pic for dynamic library builds. - if (buildsettings.targetType == TargetType.dynamicLibrary) - buildsettings.addOptions(BuildOption.pic); - - logDiagnostic("Generate target %s (%s %s %s)", pack.name, buildsettings.targetType, buildsettings.targetPath, buildsettings.targetName); - if (is_target) - targets[pack.name] = TargetInfo(pack, [pack], configs[pack.name], buildsettings, null); - - auto deps = pack.getDependencies(configs[pack.name]); - foreach (depname; deps.keys.sort()) { - auto depspec = deps[depname]; - auto dep = m_project.getDependency(depname, depspec.optional); - if (!dep) continue; - - auto depbs = collect(settings, dep, targets, configs, main_files, is_target ? pack.name : bin_pack); - - if (depbs.targetType != TargetType.sourceLibrary && depbs.targetType != TargetType.none) { - // add a reference to the target binary and remove all source files in the dependency build settings - depbs.sourceFiles = depbs.sourceFiles.filter!(f => f.isLinkerFile()).array; - depbs.importFiles = null; - } - - buildsettings.add(depbs); - - if (depbs.targetType == TargetType.executable) - continue; - - auto pt = (is_target ? pack.name : bin_pack) in targets; - assert(pt !is null); - if (auto pdt = depname in targets) { - pt.dependencies ~= depname; - pt.linkDependencies ~= depname; - if (depbs.targetType == TargetType.staticLibrary) - pt.linkDependencies = pt.linkDependencies.filter!(d => !pdt.linkDependencies.canFind(d)).array ~ pdt.linkDependencies; - } else pt.packages ~= dep; - } - - if (is_target) targets[pack.name].buildSettings = buildsettings.dup; - - return buildsettings; } - private string[] downwardsInheritSettings(string target, TargetInfo[string] targets, in BuildSettings root_settings) - { - import dub.internal.utils : stripDlangSpecialChars; - - auto ti = &targets[target]; - ti.buildSettings.addVersions(root_settings.versions); - ti.buildSettings.addDebugVersions(root_settings.debugVersions); - ti.buildSettings.addOptions(BuildOptions(cast(BuildOptions)root_settings.options & inheritedBuildOptions)); - - // special support for overriding string imports in parent packages - // this is a candidate for deprecation, once an alternative approach - // has been found - if (ti.buildSettings.stringImportPaths.length) { - // override string import files (used for up to date checking) - foreach (ref f; ti.buildSettings.stringImportFiles) - foreach (fi; root_settings.stringImportFiles) - if (f != fi && NativePath(f).head == NativePath(fi).head) { - f = fi; - } - - // add the string import paths (used by the compiler to find the overridden files) - ti.buildSettings.prependStringImportPaths(root_settings.stringImportPaths); - } - - string[] packs = ti.packages.map!(p => p.name).array; - foreach (d; ti.dependencies) - packs ~= downwardsInheritSettings(d, targets, root_settings); - - logDebug("%s: %s", target, packs); - - // Add Have_* versions *after* downwards inheritance, so that dependencies - // are build independently of the parent packages w.r.t the other parent - // dependencies. This enables sharing of the same package build for - // multiple dependees. - ti.buildSettings.addVersions(packs.map!(pn => "Have_" ~ stripDlangSpecialChars(pn)).array); - - return packs; - } - + // configure targets for build types such as release, or unittest-cov private void addBuildTypeSettings(TargetInfo[string] targets, GeneratorSettings settings) { - foreach (ref t; targets) { - t.buildSettings.add(settings.buildSettings); + foreach (ref ti; targets.byValue) { + ti.buildSettings.add(settings.buildSettings); // add build type settings and convert plain DFLAGS to build options - m_project.addBuildTypeSettings(t.buildSettings, settings.platform, settings.buildType, t.pack is m_project.rootPackage); - settings.compiler.extractBuildOptions(t.buildSettings); + m_project.addBuildTypeSettings(ti.buildSettings, settings.platform, settings.buildType, ti.pack is m_project.rootPackage); + settings.compiler.extractBuildOptions(ti.buildSettings); - auto tt = t.buildSettings.targetType; - bool generates_binary = tt != TargetType.sourceLibrary && tt != TargetType.none; - enforce (generates_binary || t.pack !is m_project.rootPackage || (t.buildSettings.options & BuildOption.syntaxOnly), + auto tt = ti.buildSettings.targetType; + bool generatesBinary = tt != TargetType.sourceLibrary && tt != TargetType.none; + enforce (generatesBinary || ti.pack !is m_project.rootPackage || (ti.buildSettings.options & BuildOption.syntaxOnly), format("Main package must have a binary target type, not %s. Cannot build.", tt)); } } diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d index bd1fd95..87c8e51 100644 --- a/source/dub/generators/visuald.d +++ b/source/dub/generators/visuald.d @@ -349,6 +349,7 @@ ret.put(" 0\n"); ret.put(" 0\n"); ret.put(" 0\n"); + ret.put(" 0\n"); ret.put(" 0\n"); ret.put(" 0\n"); ret.put(" 0\n"); diff --git a/source/dub/init.d b/source/dub/init.d index a1caaf2..23873bc 100644 --- a/source/dub/init.d +++ b/source/dub/init.d @@ -69,7 +69,7 @@ foreach (fil; packageInfoFiles) enforceDoesNotExist(fil.filename); - auto files = ["source/", "views/", "public/", "dub.json", ".gitignore"]; + auto files = ["source/", "views/", "public/", "dub.json"]; foreach (fil; files) enforceDoesNotExist(fil); @@ -87,7 +87,7 @@ } writePackageRecipe(root_path ~ ("dub."~format.to!string), p); - writeGitignore(root_path, p); + writeGitignore(root_path, p.name); } alias RecipeCallback = void delegate(ref PackageRecipe, ref PackageFormat); @@ -111,7 +111,7 @@ private void initVibeDPackage(NativePath root_path, ref PackageRecipe p, scope void delegate() pre_write_callback) { if ("vibe-d" !in p.buildSettings.dependencies) - p.buildSettings.dependencies["vibe-d"] = Dependency("~>0.7.30"); + p.buildSettings.dependencies["vibe-d"] = Dependency("~>0.8.2"); p.description = "A simple vibe.d server application."; pre_write_callback(); @@ -153,9 +153,29 @@ createDirectory(root_path ~ "deimos"); } -private void writeGitignore(NativePath root_path, PackageRecipe p) +/** + * Write the `.gitignore` file to the directory, if it does not already exists + * + * As `dub` is often used with `git`, adding a `.gitignore` is a nice touch for + * most users. However, this file is not mandatory for `dub` to do its job, + * so we do not depend on the content. + * One important use case we need to support is people running `dub init` on + * a Github-initialized repository. Those might already contain a `.gitignore` + * (and a README and a LICENSE), thus we should not bail out if the file already + * exists, just ignore it. + * + * Params: + * root_path = The path to the directory hosting the project + * pkg_name = Name of the package, to generate a list of binaries to ignore + */ +private void writeGitignore(NativePath root_path, const(char)[] pkg_name) { - write((root_path ~ ".gitignore").toNativeString(), + auto full_path = (root_path ~ ".gitignore").toNativeString(); + + if (existsFile(full_path)) + return; + + write(full_path, q"{.dub docs.json __dummy.html @@ -170,7 +190,7 @@ *.o *.obj *.lst -}".format(p.name)); +}".format(pkg_name)); } private string getUserName() diff --git a/test/4-describe-data-1-list.sh b/test/4-describe-data-1-list.sh index 3cfe5dc..def3899 100755 --- a/test/4-describe-data-1-list.sh +++ b/test/4-describe-data-1-list.sh @@ -77,11 +77,11 @@ echo >> "$expected_file" # --data=versions echo "someVerIdent" >> "$expected_file" -echo "anotherVerIdent" >> "$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 >> "$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 d323bc5..225537a 100755 --- a/test/4-describe-data-2-dmd.sh +++ b/test/4-describe-data-2-dmd.sh @@ -54,11 +54,11 @@ echo -n "'$CURR_DIR/describe-dependency-1/source/dummy.d' " >> "$expected_file" # --data=versions echo -n "-version=someVerIdent " >> "$expected_file" -echo -n "-version=anotherVerIdent " >> "$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" # --data=debug-versions echo -n "-debug=someDebugVerIdent " >> "$expected_file" echo -n "-debug=anotherDebugVerIdent " >> "$expected_file" diff --git a/test/describe-dependency-1/dependency-postGenerateCommands.sh b/test/describe-dependency-1/dependency-postGenerateCommands.sh index 1a24852..f1f641a 100755 --- a/test/describe-dependency-1/dependency-postGenerateCommands.sh +++ b/test/describe-dependency-1/dependency-postGenerateCommands.sh @@ -1 +1 @@ -#!/bin/sh +#!/usr/bin/env bash diff --git a/test/describe-dependency-1/dependency-preGenerateCommands.sh b/test/describe-dependency-1/dependency-preGenerateCommands.sh index 1a24852..f1f641a 100755 --- a/test/describe-dependency-1/dependency-preGenerateCommands.sh +++ b/test/describe-dependency-1/dependency-preGenerateCommands.sh @@ -1 +1 @@ -#!/bin/sh +#!/usr/bin/env bash diff --git a/test/describe-project/do-postGenerateCommands.sh b/test/describe-project/do-postGenerateCommands.sh index 1a24852..f1f641a 100755 --- a/test/describe-project/do-postGenerateCommands.sh +++ b/test/describe-project/do-postGenerateCommands.sh @@ -1 +1 @@ -#!/bin/sh +#!/usr/bin/env bash diff --git a/test/describe-project/do-preGenerateCommands.sh b/test/describe-project/do-preGenerateCommands.sh index 1a24852..f1f641a 100755 --- a/test/describe-project/do-preGenerateCommands.sh +++ b/test/describe-project/do-preGenerateCommands.sh @@ -1 +1 @@ -#!/bin/sh +#!/usr/bin/env bash diff --git a/test/expected-issue1037-output b/test/expected-issue1037-output new file mode 100644 index 0000000..a5d7c55 --- /dev/null +++ b/test/expected-issue1037-output @@ -0,0 +1,4 @@ +Root package issue1037-better-dependency-messages reference gitcompatibledubpackage 1.0.1 cannot be satisfied. +Packages causing the conflict: + issue1037-better-dependency-messages depends on 1.0.1 + b depends on ~>1.0.2 diff --git a/test/feat663-search.sh b/test/feat663-search.sh index ab127cb..435c8d8 100755 --- a/test/feat663-search.sh +++ b/test/feat663-search.sh @@ -7,6 +7,9 @@ if ${DUB} search nonexistent123456789package 2>/dev/null; then die $LINENO '`dub search nonexistent123456789package` succeeded' fi -if ! OUTPUT=$(${DUB} search dub -v 2>&1) || ! { echo "$OUTPUT" | grep -q '^dub (.*)\s'; } then +if ! OUTPUT=$(${DUB} search dub -v 2>&1); then die $LINENO '`dub search dub` failed' "$OUTPUT" fi +if ! grep -q '^dub (.*)\s'<<<"$OUTPUT"; then + die $LINENO '`grep -q '"'"'^dub (.*)\s'"'"'` failed' "$OUTPUT" +fi diff --git a/test/fetchzip.sh b/test/fetchzip.sh index b0d34d2..ce03723 100755 --- a/test/fetchzip.sh +++ b/test/fetchzip.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash DIR=$(dirname "${BASH_SOURCE[0]}") . "$DIR"/common.sh diff --git a/test/interactive-remove.sh b/test/interactive-remove.sh index f689fdd..3608a2b 100755 --- a/test/interactive-remove.sh +++ b/test/interactive-remove.sh @@ -7,7 +7,7 @@ if $DUB remove dub --non-interactive 2>/dev/null; then die $LINENO 'Non-interactive remove should fail' fi -echo 1 | $DUB remove dub | tr --delete '\n' | grep --ignore-case 'select.*0\.9\.20.*0\.9\.21.*' +echo 1 | $DUB remove dub | tr -d '\n' | grep --ignore-case 'select.*0\.9\.20.*0\.9\.21.*' if [ -d $HOME/.dub/packages/dub-0.9.20/dub ]; then die $LINENO 'Failed to remove dub-0.9.20' fi diff --git a/test/issue1037-better-dependency-messages.sh b/test/issue1037-better-dependency-messages.sh new file mode 100755 index 0000000..2fe3b9f --- /dev/null +++ b/test/issue1037-better-dependency-messages.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e -o pipefail + +cd ${CURR_DIR}/issue1037-better-dependency-messages + +temp_file=$(mktemp $(basename $0).XXXXXX) +expected_file="$CURR_DIR/expected-issue1037-output" + +function cleanup { + rm $temp_file +} + +trap cleanup EXIT + +$DUB upgrade 2>$temp_file && exit 1 # dub upgrade should fail + +if ! diff "$expected_file" "$temp_file"; then + die 'output not containing conflict information' +fi + +exit 0 \ No newline at end of file diff --git a/test/issue1037-better-dependency-messages/.no_build b/test/issue1037-better-dependency-messages/.no_build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1037-better-dependency-messages/.no_build diff --git a/test/issue1037-better-dependency-messages/.no_run b/test/issue1037-better-dependency-messages/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1037-better-dependency-messages/.no_run diff --git a/test/issue1037-better-dependency-messages/.no_test b/test/issue1037-better-dependency-messages/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1037-better-dependency-messages/.no_test diff --git a/test/issue1037-better-dependency-messages/b/dub.json b/test/issue1037-better-dependency-messages/b/dub.json new file mode 100644 index 0000000..92443ac --- /dev/null +++ b/test/issue1037-better-dependency-messages/b/dub.json @@ -0,0 +1,6 @@ +{ + "name": "b", + "dependencies": { + "gitcompatibledubpackage": "~>1.0.2" + } +} \ No newline at end of file diff --git a/test/issue1037-better-dependency-messages/dub.json b/test/issue1037-better-dependency-messages/dub.json new file mode 100644 index 0000000..abb7d17 --- /dev/null +++ b/test/issue1037-better-dependency-messages/dub.json @@ -0,0 +1,10 @@ +{ + "name": "issue1037-better-dependency-messages", + "dependencies": { + "gitcompatibledubpackage": "1.0.1", + "b": { + "path": "b", + "version": "*" + } + } +} \ No newline at end of file diff --git a/test/issue1262-version-inheritance-diamond/.gitignore b/test/issue1262-version-inheritance-diamond/.gitignore new file mode 100644 index 0000000..c09a597 --- /dev/null +++ b/test/issue1262-version-inheritance-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/issue1262-version-inheritance-diamond/.no_run b/test/issue1262-version-inheritance-diamond/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/.no_run diff --git a/test/issue1262-version-inheritance-diamond/.no_test b/test/issue1262-version-inheritance-diamond/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/.no_test diff --git a/test/issue1262-version-inheritance-diamond/daughter/.gitignore b/test/issue1262-version-inheritance-diamond/daughter/.gitignore new file mode 100644 index 0000000..f190acb --- /dev/null +++ b/test/issue1262-version-inheritance-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/issue1262-version-inheritance-diamond/daughter/dub.sdl b/test/issue1262-version-inheritance-diamond/daughter/dub.sdl new file mode 100644 index 0000000..3a0eee7 --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/daughter/dub.sdl @@ -0,0 +1,3 @@ +name "daughter" +versions "Daughter" +dependency "diamond" path="../diamond" diff --git a/test/issue1262-version-inheritance-diamond/daughter/source/dummy.d b/test/issue1262-version-inheritance-diamond/daughter/source/dummy.d new file mode 100644 index 0000000..89139c3 --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/daughter/source/dummy.d @@ -0,0 +1,6 @@ +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) {} else static assert(0, "Expected Son to be set"); +version (Diamond) {} else static assert(0, "Expected Diamond to be set"); diff --git a/test/issue1262-version-inheritance-diamond/diamond/.gitignore b/test/issue1262-version-inheritance-diamond/diamond/.gitignore new file mode 100644 index 0000000..c359a73 --- /dev/null +++ b/test/issue1262-version-inheritance-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/issue1262-version-inheritance-diamond/diamond/dub.sdl b/test/issue1262-version-inheritance-diamond/diamond/dub.sdl new file mode 100644 index 0000000..85cb8a1 --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/diamond/dub.sdl @@ -0,0 +1,2 @@ +name "diamond" +versions "Diamond" diff --git a/test/issue1262-version-inheritance-diamond/diamond/source/dummy.d b/test/issue1262-version-inheritance-diamond/diamond/source/dummy.d new file mode 100644 index 0000000..fb1499e --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/diamond/source/dummy.d @@ -0,0 +1,6 @@ +module diamond.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) {} else static assert(0, "Expected Son to be set"); +version (Diamond) {} else static assert(0, "Expected Diamond to be set"); diff --git a/test/issue1262-version-inheritance-diamond/dub.sdl b/test/issue1262-version-inheritance-diamond/dub.sdl new file mode 100644 index 0000000..588adb8 --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/dub.sdl @@ -0,0 +1,4 @@ +name "issue1262-version-inheritance-diamond" +versions "Parent" +dependency "daughter" path="daughter" +dependency "son" path="son" diff --git a/test/issue1262-version-inheritance-diamond/son/.gitignore b/test/issue1262-version-inheritance-diamond/son/.gitignore new file mode 100644 index 0000000..601a33b --- /dev/null +++ b/test/issue1262-version-inheritance-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/issue1262-version-inheritance-diamond/son/dub.sdl b/test/issue1262-version-inheritance-diamond/son/dub.sdl new file mode 100644 index 0000000..41dc1be --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/son/dub.sdl @@ -0,0 +1,3 @@ +name "son" +versions "Son" +dependency "diamond" path="../diamond" diff --git a/test/issue1262-version-inheritance-diamond/son/source/dummy.d b/test/issue1262-version-inheritance-diamond/son/source/dummy.d new file mode 100644 index 0000000..85841ad --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/son/source/dummy.d @@ -0,0 +1,6 @@ +module son.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) {} else static assert(0, "Expected Son to be set"); +version (Diamond) {} else static assert(0, "Expected Diamond to be set"); diff --git a/test/issue1262-version-inheritance-diamond/source/app.d b/test/issue1262-version-inheritance-diamond/source/app.d new file mode 100644 index 0000000..10f0ae6 --- /dev/null +++ b/test/issue1262-version-inheritance-diamond/source/app.d @@ -0,0 +1,8 @@ +version (Parent) {} else static assert(0, "Expected Parent to be set"); +version (Daughter) {} else static assert(0, "Expected Daughter to be set"); +version (Son) {} else static assert(0, "Expected Son to be set"); +version (Diamond) {} else static assert(0, "Expected Diamond to be set"); + +void main() +{ +} diff --git a/test/issue1262-version-inheritance/.gitignore b/test/issue1262-version-inheritance/.gitignore new file mode 100644 index 0000000..84dca77 --- /dev/null +++ b/test/issue1262-version-inheritance/.gitignore @@ -0,0 +1,15 @@ +.dub +docs.json +__dummy.html +docs/ +issue1262-version-inheritance +issue1262-version-inheritance.so +issue1262-version-inheritance.dylib +issue1262-version-inheritance.dll +issue1262-version-inheritance.a +issue1262-version-inheritance.lib +issue1262-version-inheritance-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/issue1262-version-inheritance/.no_run b/test/issue1262-version-inheritance/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1262-version-inheritance/.no_run diff --git a/test/issue1262-version-inheritance/.no_test b/test/issue1262-version-inheritance/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1262-version-inheritance/.no_test diff --git a/test/issue1262-version-inheritance/daughter/.gitignore b/test/issue1262-version-inheritance/daughter/.gitignore new file mode 100644 index 0000000..f190acb --- /dev/null +++ b/test/issue1262-version-inheritance/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/issue1262-version-inheritance/daughter/dub.sdl b/test/issue1262-version-inheritance/daughter/dub.sdl new file mode 100644 index 0000000..baa3295 --- /dev/null +++ b/test/issue1262-version-inheritance/daughter/dub.sdl @@ -0,0 +1,3 @@ +name "daughter" +versions "Daughter" + diff --git a/test/issue1262-version-inheritance/daughter/source/dummy.d b/test/issue1262-version-inheritance/daughter/source/dummy.d new file mode 100644 index 0000000..aad7fc8 --- /dev/null +++ b/test/issue1262-version-inheritance/daughter/source/dummy.d @@ -0,0 +1,5 @@ +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 no be set"); diff --git a/test/issue1262-version-inheritance/dub.sdl b/test/issue1262-version-inheritance/dub.sdl new file mode 100644 index 0000000..46568fb --- /dev/null +++ b/test/issue1262-version-inheritance/dub.sdl @@ -0,0 +1,4 @@ +name "issue1262-version-inheritance" +versions "Parent" +dependency "daughter" path="daughter" +dependency "son" path="son" diff --git a/test/issue1262-version-inheritance/son/.gitignore b/test/issue1262-version-inheritance/son/.gitignore new file mode 100644 index 0000000..601a33b --- /dev/null +++ b/test/issue1262-version-inheritance/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/issue1262-version-inheritance/son/dub.sdl b/test/issue1262-version-inheritance/son/dub.sdl new file mode 100644 index 0000000..5882548 --- /dev/null +++ b/test/issue1262-version-inheritance/son/dub.sdl @@ -0,0 +1,2 @@ +name "son" +versions "Son" diff --git a/test/issue1262-version-inheritance/son/source/dummy.d b/test/issue1262-version-inheritance/son/source/dummy.d new file mode 100644 index 0000000..63995a1 --- /dev/null +++ b/test/issue1262-version-inheritance/son/source/dummy.d @@ -0,0 +1,5 @@ +module son.dummy; + +version (Parent) {} else static assert(0, "Expected Parent to be set"); +version (Daughter) static assert(0, "Expected Daughter to not be set"); +version (Son) {} else static assert(0, "Expected Son to be set"); diff --git a/test/issue1262-version-inheritance/source/app.d b/test/issue1262-version-inheritance/source/app.d new file mode 100644 index 0000000..b6bb4be --- /dev/null +++ b/test/issue1262-version-inheritance/source/app.d @@ -0,0 +1,7 @@ +version (Parent) {} else static assert(0, "Expected Parent to be set"); +version (Daughter) {} else static assert(0, "Expected Daughter to be set"); +version (Son) {} else static assert(0, "Expected Son to be set"); + +void main() +{ +} diff --git a/test/issue1350-transitive-none-deps/.gitignore b/test/issue1350-transitive-none-deps/.gitignore new file mode 100644 index 0000000..4571d26 --- /dev/null +++ b/test/issue1350-transitive-none-deps/.gitignore @@ -0,0 +1,15 @@ +.dub +docs.json +__dummy.html +docs/ +test +test.so +test.dylib +test.dll +test.a +test.lib +test-test-* +*.exe +*.o +*.obj +*.lst diff --git a/test/issue1350-transitive-none-deps/.no_run b/test/issue1350-transitive-none-deps/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1350-transitive-none-deps/.no_run diff --git a/test/issue1350-transitive-none-deps/.no_test b/test/issue1350-transitive-none-deps/.no_test new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1350-transitive-none-deps/.no_test diff --git a/test/issue1350-transitive-none-deps/common-dep/common.d b/test/issue1350-transitive-none-deps/common-dep/common.d new file mode 100644 index 0000000..23cc13c --- /dev/null +++ b/test/issue1350-transitive-none-deps/common-dep/common.d @@ -0,0 +1 @@ +module common; diff --git a/test/issue1350-transitive-none-deps/common-dep/dub.sdl b/test/issue1350-transitive-none-deps/common-dep/dub.sdl new file mode 100644 index 0000000..e4d29b2 --- /dev/null +++ b/test/issue1350-transitive-none-deps/common-dep/dub.sdl @@ -0,0 +1,4 @@ +name "common-dep" +targetType "library" +importPaths "." +sourceFiles "common.d" diff --git a/test/issue1350-transitive-none-deps/common-none/dub.sdl b/test/issue1350-transitive-none-deps/common-none/dub.sdl new file mode 100644 index 0000000..79986cc --- /dev/null +++ b/test/issue1350-transitive-none-deps/common-none/dub.sdl @@ -0,0 +1,3 @@ +name "common-none" +targetType "none" +dependency "common-dep" path="../common-dep" diff --git a/test/issue1350-transitive-none-deps/dep1/dep1.d b/test/issue1350-transitive-none-deps/dep1/dep1.d new file mode 100644 index 0000000..6b47d60 --- /dev/null +++ b/test/issue1350-transitive-none-deps/dep1/dep1.d @@ -0,0 +1,2 @@ +module dep1; +import common; diff --git a/test/issue1350-transitive-none-deps/dep1/dub.sdl b/test/issue1350-transitive-none-deps/dep1/dub.sdl new file mode 100644 index 0000000..432097a --- /dev/null +++ b/test/issue1350-transitive-none-deps/dep1/dub.sdl @@ -0,0 +1,4 @@ +name "dep1" +importPaths "." +sourceFiles "dep1.d" +dependency "common-none" path="../common-none" diff --git a/test/issue1350-transitive-none-deps/dep2/dep2.d b/test/issue1350-transitive-none-deps/dep2/dep2.d new file mode 100644 index 0000000..fbfed0d --- /dev/null +++ b/test/issue1350-transitive-none-deps/dep2/dep2.d @@ -0,0 +1,2 @@ +module dep2; +import common; diff --git a/test/issue1350-transitive-none-deps/dep2/dub.sdl b/test/issue1350-transitive-none-deps/dep2/dub.sdl new file mode 100644 index 0000000..3157e08 --- /dev/null +++ b/test/issue1350-transitive-none-deps/dep2/dub.sdl @@ -0,0 +1,4 @@ +name "dep2" +importPaths "." +sourceFiles "dep2.d" +dependency "common-none" path="../common-none" diff --git a/test/issue1350-transitive-none-deps/dub.sdl b/test/issue1350-transitive-none-deps/dub.sdl new file mode 100644 index 0000000..5bcd940 --- /dev/null +++ b/test/issue1350-transitive-none-deps/dub.sdl @@ -0,0 +1,5 @@ +name "test" +targetType "executable" +sourceFiles "test.d" +dependency "dep1" path="dep1" +dependency "dep2" path="dep2" diff --git a/test/issue1350-transitive-none-deps/test.d b/test/issue1350-transitive-none-deps/test.d new file mode 100644 index 0000000..4390778 --- /dev/null +++ b/test/issue1350-transitive-none-deps/test.d @@ -0,0 +1,5 @@ +module test; + +import dep1, dep2, common; + +void main() {} diff --git a/test/issue616-describe-vs-generate-commands/do-preGenerateCommands.sh b/test/issue616-describe-vs-generate-commands/do-preGenerateCommands.sh index 84468cd..6342d76 100755 --- a/test/issue616-describe-vs-generate-commands/do-preGenerateCommands.sh +++ b/test/issue616-describe-vs-generate-commands/do-preGenerateCommands.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash if [ -n "${dub_issue616}" ]; then echo 'Fail! preGenerateCommands recursion detected!' >&2 exit 0 # Don't return a non-zero error code here. This way the test gives a better diagnostic. diff --git a/test/issue616-subpack/dub.json b/test/issue616-subpack/dub.json index 552ddcd..31c525a 100644 --- a/test/issue616-subpack/dub.json +++ b/test/issue616-subpack/dub.json @@ -1,6 +1,6 @@ { "name": "issue616-subpack", - "targetType": "executable", + "targetType": "library", "dependencies": { "issue616-subsubpack": { "version": "1.0", diff --git a/test/issue616-subsubpack/dub.json b/test/issue616-subsubpack/dub.json index e4e4b5b..207761f 100644 --- a/test/issue616-subsubpack/dub.json +++ b/test/issue616-subsubpack/dub.json @@ -1,4 +1,4 @@ { "name": "issue616-subsubpack", - "targetType": "executable" + "targetType": "library" } diff --git a/test/issue884-init-defer-file-creation.sh b/test/issue884-init-defer-file-creation.sh index 013842c..7ffab21 100755 --- a/test/issue884-init-defer-file-creation.sh +++ b/test/issue884-init-defer-file-creation.sh @@ -9,8 +9,11 @@ cd ${TMPDIR} # kill dub init during interactive mode -${DUB} init <(while :; do sleep 1; done) & +mkfifo in +${DUB} init < in & +sleep 1 kill $! +rm in # ensure that no files are left behind NFILES_PLUS_ONE=`ls -la | wc -l` diff --git a/test/run-unittest.sh b/test/run-unittest.sh index 9cf7292..8d14e33 100755 --- a/test/run-unittest.sh +++ b/test/run-unittest.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -ueo pipefail . $(dirname "${BASH_SOURCE[0]}")/common.sh @@ -30,10 +31,11 @@ DC_BIN=$(basename "$DC") CURR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +FRONTEND="${FRONTEND:-}" for script in $(ls $CURR_DIR/*.sh); do if [ "$script" = "$(readlink -f ${BASH_SOURCE[0]})" ] || [ "$(basename $script)" = "common.sh" ]; then continue; fi - if [ -e $script.min_frontend ] && [ ! -z ${FRONTEND:-} -a ${FRONTEND:-} \< $(cat $script.min_frontend) ]; then continue; fi + if [ -e $script.min_frontend ] && [ ! -z "$FRONTEND" ] && [ ${FRONTEND} \< $(cat $script.min_frontend) ]; then continue; fi log "Running $script..." DUB=$DUB DC=$DC CURR_DIR="$CURR_DIR" $script || logError "Script failure." done diff --git a/test/single-file-sdl-default-name.sh b/test/single-file-sdl-default-name.sh index 1c61540..ab2ba8b 100755 --- a/test/single-file-sdl-default-name.sh +++ b/test/single-file-sdl-default-name.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash set -e cd ${CURR_DIR} rm -f single-file-sdl-default-name diff --git a/travis-ci.sh b/travis-ci.sh index 8436dcb..c7782f2 100755 --- a/travis-ci.sh +++ b/travis-ci.sh @@ -4,7 +4,7 @@ source ~/dlang/*/activate # activate host compiler -if [ -z "$FRONTEND" -o "$FRONTEND" \> 2.071.z ]; then +if [ -z "$FRONTEND" -o "$FRONTEND" \> 2.072.z ]; then vibe_ver=$(jq -r '.versions | .["vibe-d"]' < dub.selections.json) dub fetch vibe-d --version=$vibe_ver # get optional dependency dub test --compiler=${DC} -c library-nonet @@ -27,6 +27,7 @@ export FRONTEND=2.068 source $(~/dlang/install.sh gdc-4.8.5 --activate) DUB=`pwd`/bin/dub DC=${DC} test/run-unittest.sh + deactivate else ./build.sh DUB=`pwd`/bin/dub DC=${DC} test/run-unittest.sh @@ -41,3 +42,9 @@ if [ "$COVERAGE" = true ]; then find . -type f -name '*.d' -exec grep -Hn "[[:blank:]]$" {} \; fi + +# check that the man page generation still works (only once) +if [ "$COVERAGE" = true ]; then + source $(~/dlang/install.sh dmd --activate) + dub --single -v scripts/man/gen_man.d +fi