diff --git a/.codecov.yml b/.codecov.yml index a52495b..e2ed4ad 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,17 +1,14 @@ # Documentation: https://docs.codecov.io/docs/codecov-yaml -codecov: - bot: dlang-bot - coverage: precision: 3 - # round: down - # range: "70...100" + round: down + range: "80...100" status: # Learn more at https://docs.codecov.io/docs/commit-status project: true patch: true - changes: false + changes: true comment: false diff --git a/.travis.yml b/.travis.yml index f131df0..175b072 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,21 @@ language: d +dist: trusty sudo: false matrix: include: - d: dmd-nightly - env: [FRONTEND=2.074] + env: [FRONTEND=2.075] - d: dmd-beta - env: [FRONTEND=2.074] + env: [FRONTEND=2.075] - d: dmd - env: [FRONTEND=2.074] - - d: dmd-2.074.0 - env: [FRONTEND=2.074] - - d: dmd-2.073.0 env: - - [FRONTEND=2.073] + - [FRONTEND=2.074] - [COVERAGE=true] + - d: dmd-2.074.1 + env: [FRONTEND=2.074] + - d: dmd-2.073.2 + env: [FRONTEND=2.073] - d: dmd-2.072.2 env: [FRONTEND=2.072] - d: dmd-2.071.2 @@ -29,8 +30,6 @@ env: [FRONTEND=2.067] - d: dmd-2.066.1 env: [FRONTEND=2.066] - - d: dmd-2.065.0 - env: [FRONTEND=2.065] - d: ldc-beta env: [FRONTEND=2.073] - d: ldc @@ -49,11 +48,15 @@ env: [FRONTEND=2.066] - d: gdc-4.9.2 env: [FRONTEND=2.066] - - d: gdc-4.9.0 - env: [FRONTEND=2.065] allow_failures: - d: gdc +addons: + apt: + packages: + - libevent-dev + script: + - deactivate # deactivate host compiler - ./travis-ci.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bda4cf..b76c46e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Changelog ========= +v1.5.0 - 2017- +------------------- + +- Read additional registry URLs (semicolon separated) from DUB_REGISTRY env var - [pull #1173][issue1173] + +[issue1173]: https://github.com/dlang/dub/issues/1173 + v1.4.1 - 2017-08-10 ------------------- diff --git a/build.sh b/build.sh index d5d8f55..7cd478e 100755 --- a/build.sh +++ b/build.sh @@ -56,7 +56,7 @@ MACOSX_DEPLOYMENT_TARGET=10.7 echo Running $DMD... -$DMD -ofbin/dub -w -version=DubUseCurl -Isource $* $LIBS @build-files.txt +$DMD -ofbin/dub -g -O -w -version=DubUseCurl -Isource $* $LIBS @build-files.txt bin/dub --version echo DUB has been built as bin/dub. echo diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 3fec92f..71e66c3 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -126,7 +126,6 @@ // parse general options CommonOptions options; LogLevel loglevel = LogLevel.info; - options.root_path = getcwd(); auto common_args = new CommandArgs(args); try { @@ -144,6 +143,15 @@ return 1; } + if (options.root_path.empty) + options.root_path = getcwd(); + else + { + import std.path : absolutePath, buildNormalizedPath; + + options.root_path = options.root_path.absolutePath.buildNormalizedPath; + } + // create the list of all supported commands CommandGroup[] commands = getCommands(); @@ -496,7 +504,7 @@ while (true) { // Tries getting the name until a valid one is given. import std.regex; - auto nameRegex = regex(`^[a-z\-_]+$`); + auto nameRegex = regex(`^[a-z0-9\-_]+$`); string triedName = input("Name", p.name); if (triedName.matchFirst(nameRegex).empty) { logError("Invalid name, \""~triedName~"\", names should consist only of lowercase alphanumeric characters, - and _."); @@ -847,6 +855,7 @@ private { string m_mainFile; bool m_combined = false; + bool m_parallel = false; bool m_force = false; } @@ -885,6 +894,9 @@ args.getopt("combined", &m_combined, [ "Tries to build the whole project in a single compiler run." ]); + args.getopt("parallel", &m_parallel, [ + "Runs multiple compiler instances in parallel, if possible." + ]); args.getopt("f|force", &m_force, [ "Forces a recompilation even if the target is up to date" ]); @@ -912,6 +924,7 @@ settings.buildMode = m_buildMode; settings.buildSettings = m_buildSettings; settings.combined = m_combined; + settings.parallelBuild = m_parallel; settings.force = m_force; settings.tempBuild = m_single; settings.run = true; diff --git a/source/dub/compilers/buildsettings.d b/source/dub/compilers/buildsettings.d index beebd0f..3da87b1 100644 --- a/source/dub/compilers/buildsettings.d +++ b/source/dub/compilers/buildsettings.d @@ -108,8 +108,9 @@ void removeOptions(in BuildOption[] value...) { foreach (v; value) this.options &= ~v; } void removeOptions(in BuildOptions value) { this.options &= ~value; } +private: // Adds vals to arr without adding duplicates. - private void add(ref string[] arr, in string[] vals, bool no_duplicates = true) + static void add(ref string[] arr, in string[] vals, bool no_duplicates = true) { if (!no_duplicates) { arr ~= vals; @@ -127,7 +128,16 @@ } } - private void prepend(ref string[] arr, in string[] vals, bool no_duplicates = true) + unittest + { + auto ary = ["-dip1000", "-vgc"]; + BuildSettings.add(ary, ["-dip1000", "-vgc"]); + assert(ary == ["-dip1000", "-vgc"]); + BuildSettings.add(ary, ["-dip1001", "-vgc"], false); + assert(ary == ["-dip1000", "-vgc", "-dip1001", "-vgc"]); + } + + static void prepend(ref string[] arr, in string[] vals, bool no_duplicates = true) { if (!no_duplicates) { arr = vals ~ arr; @@ -145,8 +155,17 @@ } } + unittest + { + auto ary = ["-dip1000", "-vgc"]; + BuildSettings.prepend(ary, ["-dip1000", "-vgc"]); + assert(ary == ["-dip1000", "-vgc"]); + BuildSettings.prepend(ary, ["-dip1001", "-vgc"], false); + assert(ary == ["-dip1001", "-vgc", "-dip1000", "-vgc"]); + } + // add string import files (avoids file name duplicates in addition to path duplicates) - private void addSI(ref string[] arr, in string[] vals) + static void addSI(ref string[] arr, in string[] vals) { bool[string] existing; foreach (v; arr) existing[Path(v).head.toString()] = true; @@ -159,7 +178,16 @@ } } - private void removePaths(ref string[] arr, in string[] vals) + unittest + { + auto ary = ["path/foo.txt"]; + BuildSettings.addSI(ary, ["path2/foo2.txt"]); + assert(ary == ["path/foo.txt", "path2/foo2.txt"]); + BuildSettings.addSI(ary, ["path2/foo.txt"]); // no duplicate basenames + assert(ary == ["path/foo.txt", "path2/foo2.txt"]); + } + + static void removePaths(ref string[] arr, in string[] vals) { bool matches(string s) { @@ -171,7 +199,18 @@ arr = arr.filter!(s => !matches(s))().array(); } - private void remove(ref string[] arr, in string[] vals) + unittest + { + auto ary = ["path1", "root/path1", "root/path2", "root2/path1"]; + BuildSettings.removePaths(ary, ["path1"]); + assert(ary == ["root/path1", "root/path2", "root2/path1"]); + BuildSettings.removePaths(ary, ["*/path1"]); + assert(ary == ["root/path2"]); + BuildSettings.removePaths(ary, ["foo", "bar", "root/path2"]); + assert(ary == []); + } + + static void remove(ref string[] arr, in string[] vals) { bool matches(string s) { @@ -182,6 +221,21 @@ } arr = arr.filter!(s => !matches(s))().array(); } + + unittest + { + import std.string : join; + + auto ary = ["path1", "root/path1", "root/path2", "root2/path1"]; + BuildSettings.remove(ary, ["path1"]); + assert(ary == ["root/path1", "root/path2", "root2/path1"]); + BuildSettings.remove(ary, ["root/path*"]); + assert(ary == ["root/path1", "root/path2", "root2/path1"]); + BuildSettings.removePaths(ary, ["foo", "root/path2", "bar", "root2/path1"]); + assert(ary == ["root/path1"]); + BuildSettings.remove(ary, ["root/path1", "foo"]); + assert(ary == []); + } } enum BuildSetting { @@ -277,9 +331,10 @@ deprecationErrors = 1<<19, /// Stop compilation upon usage of deprecated features (-de) property = 1<<20, /// DEPRECATED: Enforce property syntax (-property) profileGC = 1<<21, /// Profile runtime allocations + pic = 1<<22, /// Generate position independent code // for internal usage - _docs = 1<<22, // Write ddoc to docs - _ddox = 1<<23, // Compile docs.json + _docs = 1<<23, // Write ddoc to docs + _ddox = 1<<24 // Compile docs.json } struct BuildOptions { @@ -326,4 +381,5 @@ | BuildOption.noBoundsCheck | BuildOption.profile | BuildOption.ignoreUnknownPragmas | BuildOption.syntaxOnly | BuildOption.warnings | BuildOption.warningsAsErrors | BuildOption.ignoreDeprecations | BuildOption.deprecationWarnings - | BuildOption.deprecationErrors | BuildOption.property | BuildOption.profileGC; + | BuildOption.deprecationErrors | BuildOption.property | BuildOption.profileGC + | BuildOption.pic; diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d index 0295a64..b13736e 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -20,7 +20,6 @@ import std.exception; import std.file; import std.process; -import std.random; import std.typecons; @@ -117,7 +116,7 @@ } version (Posix) { - if (settings.targetType == TargetType.dynamicLibrary) + if (settings.options & BuildOption.pic) settings.addDFlags("-fPIC"); } diff --git a/source/dub/compilers/gdc.d b/source/dub/compilers/gdc.d index 7a20f54..f0b74bd 100644 --- a/source/dub/compilers/gdc.d +++ b/source/dub/compilers/gdc.d @@ -20,7 +20,6 @@ import std.exception; import std.file; import std.process; -import std.random; import std.typecons; @@ -68,9 +67,8 @@ } settings.addDFlags(arch_flags); - auto binary_file = getTempFile("dub_platform_probe"); return probePlatform(compiler_binary, - arch_flags ~ ["-c", "-o", binary_file.toNativeString()], + arch_flags ~ ["-S"], arch_override); } @@ -119,7 +117,7 @@ settings.lflags = null; } - if (settings.targetType == TargetType.dynamicLibrary) + if (settings.options & BuildOption.pic) settings.addDFlags("-fPIC"); assert(fields & BuildSetting.dflags); diff --git a/source/dub/compilers/ldc.d b/source/dub/compilers/ldc.d index 8953e5e..df8c2de 100644 --- a/source/dub/compilers/ldc.d +++ b/source/dub/compilers/ldc.d @@ -20,7 +20,6 @@ import std.exception; import std.file; import std.process; -import std.random; import std.typecons; @@ -117,7 +116,7 @@ settings.lflags = null; } - if (settings.targetType == TargetType.dynamicLibrary) + if (settings.options & BuildOption.pic) settings.addDFlags("-relocation-model=pic"); assert(fields & BuildSetting.dflags); diff --git a/source/dub/compilers/utils.d b/source/dub/compilers/utils.d index 218fd87..d97abcf 100644 --- a/source/dub/compilers/utils.d +++ b/source/dub/compilers/utils.d @@ -175,7 +175,7 @@ {["-debug="], `Use "debugVersions" to specify version constants in a compiler independent way`}, {["-I"], `Use "importPaths" to specify import paths in a compiler independent way`}, {["-J"], `Use "stringImportPaths" to specify import paths in a compiler independent way`}, - {["-m32", "-m64", "-m32mscoff"], `Use --arch=x86/--arch=x86_64/--arch=x86_mscoff to specify the target architecture`} + {["-m32", "-m64", "-m32mscoff"], `Use --arch=x86/--arch=x86_64/--arch=x86_mscoff to specify the target architecture, e.g. 'dub build --arch=x86_64'`} ]; struct SpecialOption { diff --git a/source/dub/dub.d b/source/dub/dub.d index 32c84bf..d47632f 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -133,9 +133,11 @@ PackageSupplier[] ps = additional_package_suppliers; if (skip_registry < SkipPackageSuppliers.all) - ps ~= m_config.registryURLs + { + ps ~= (environment.get("DUB_REGISTRY", null).split(";") ~ m_config.registryURLs) .map!(url => cast(PackageSupplier)new RegistryPackageSupplier(URL(url))) .array; + } if (skip_registry < SkipPackageSuppliers.standard) ps ~= defaultPackageSuppliers(); @@ -145,6 +147,22 @@ updatePackageSearchPath(); } + unittest + { + scope (exit) environment.remove("DUB_REGISTRY"); + auto dub = new Dub(".", null, SkipPackageSuppliers.standard); + assert(dub.m_packageSuppliers.length == 0); + environment["DUB_REGISTRY"] = "http://example.com/"; + dub = new Dub(".", null, SkipPackageSuppliers.standard); + logInfo("%s", dub.m_packageSuppliers); + assert(dub.m_packageSuppliers.length == 1); + environment["DUB_REGISTRY"] = "http://example.com/;http://foo.com/"; + dub = new Dub(".", null, SkipPackageSuppliers.standard); + assert(dub.m_packageSuppliers.length == 2); + dub = new Dub(".", [new RegistryPackageSupplier(URL("http://bar.com/"))], SkipPackageSuppliers.standard); + assert(dub.m_packageSuppliers.length == 3); + } + /** Initializes the instance with a single package search path, without loading a package. @@ -273,6 +291,7 @@ { import dub.recipe.io : parsePackageRecipe; import std.file : mkdirRecurse, readText; + import std.path : baseName, stripExtension; path = makeAbsolute(path); @@ -295,12 +314,16 @@ recipe_content = file_content[0 .. idx].strip(); } else throw new Exception("The source file must start with a recipe comment."); + auto nidx = recipe_content.indexOf('\n'); + auto idx = recipe_content.indexOf(':'); - enforce(idx > 0, "Missing recipe file name (e.g. \"dub.sdl:\") in recipe comment"); + enforce(idx > 0 && (nidx < 0 || nidx > idx), + "The first line of the recipe comment must list the recipe file name followed by a colon (e.g. \"/+ dub.sdl:\")."); auto recipe_filename = recipe_content[0 .. idx]; recipe_content = recipe_content[idx+1 .. $]; + auto recipe_default_package_name = path.toString.baseName.stripExtension.strip; - auto recipe = parsePackageRecipe(recipe_content, recipe_filename); + auto recipe = parsePackageRecipe(recipe_content, recipe_filename, null, recipe_default_package_name); enforce(recipe.buildSettings.sourceFiles.length == 0, "Single-file packages are not allowed to specify source files."); enforce(recipe.buildSettings.sourcePaths.length == 0, "Single-file packages are not allowed to specify source paths."); enforce(recipe.buildSettings.importPaths.length == 0, "Single-file packages are not allowed to specify import paths."); @@ -366,7 +389,7 @@ if (versions.canFind!(v => dep.matches(v))) continue next_pack; } catch (Exception e) { - logDiagnostic("Error querying versions for %s, %s: %s", p, ps.description, e.msg); + logWarn("Error querying versions for %s, %s: %s", p, ps.description, e.msg); logDebug("Full error: %s", e.toString().sanitize()); } } @@ -645,10 +668,12 @@ foreach(ps; m_packageSuppliers){ try { pinfo = ps.fetchPackageRecipe(packageId, dep, (options & FetchOptions.usePrerelease) != 0); + if (pinfo.type == Json.Type.null_) + continue; supplier = ps; break; } catch(Exception e) { - logDiagnostic("Package %s not found for %s: %s", packageId, ps.description, e.msg); + logWarn("Package %s not found for %s: %s", packageId, ps.description, e.msg); logDebug("Full error: %s", e.toString().sanitize()); } } @@ -925,8 +950,15 @@ */ auto searchPackages(string query) { - return m_packageSuppliers.map!(ps => tuple(ps.description, ps.searchPackages(query))).array - .filter!(t => t[1].length); + Tuple!(string, PackageSupplier.SearchResult[])[] results; + foreach (ps; this.m_packageSuppliers) { + try + results ~= tuple(ps.description, ps.searchPackages(query)); + catch (Exception e) { + logWarn("Searching %s for '%s' failed: %s", ps.description, query, e.msg); + } + } + return results.filter!(tup => tup[1].length); } /** Returns a list of all available versions (including branches) for a @@ -943,7 +975,7 @@ foreach (ps; this.m_packageSuppliers) { try versions ~= ps.getVersions(name); catch (Exception e) { - logDebug("Failed to get versions for package %s on provider %s: %s", name, ps.description, e.msg); + logWarn("Failed to get versions for package %s on provider %s: %s", name, ps.description, e.msg); } } return versions.sort().uniq.array; @@ -1241,7 +1273,7 @@ versions ~= vers; break; } catch (Exception e) { - logDebug("Package %s not found in %s: %s", pack, ps.description, e.msg); + logWarn("Package %s not found in %s: %s", pack, ps.description, e.msg); logDebug("Full error: %s", e.toString().sanitize); } } @@ -1396,6 +1428,8 @@ if (rootpack == name) { try { auto desc = ps.fetchPackageRecipe(name, dep, prerelease); + if (desc.type == Json.Type.null_) + continue; auto ret = new Package(desc); m_remotePackages[key] = ret; return ret; diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 7938cc7..7865d9e 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -188,6 +188,10 @@ 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); diff --git a/source/dub/init.d b/source/dub/init.d index 36d68bd..578074a 100644 --- a/source/dub/init.d +++ b/source/dub/init.d @@ -87,7 +87,7 @@ } writePackageRecipe(root_path ~ ("dub."~format.to!string), p); - writeGitignore(root_path); + writeGitignore(root_path, p); } alias RecipeCallback = void delegate(ref PackageRecipe, ref PackageFormat); @@ -153,10 +153,24 @@ createDirectory(root_path ~ "deimos"); } -private void writeGitignore(Path root_path) +private void writeGitignore(Path root_path, PackageRecipe p) { write((root_path ~ ".gitignore").toNativeString(), - ".dub\ndocs.json\n__dummy.html\n*.o\n*.obj\n__test__*__\n"); +q"{.dub +docs.json +__dummy.html +docs/ +%1$s.so +%1$s.dylib +%1$s.dll +%1$s.a +%1$s.lib +%1$s-test-* +*.exe +*.o +*.obj +*.lst +}".format(p.name)); } private string getUserName() @@ -168,6 +182,8 @@ import core.sys.posix.pwd, core.sys.posix.unistd, core.stdc.string : strlen; import std.algorithm : splitter; + // Bionic doesn't have pw_gecos on ARM + version(CRuntime_Bionic) {} else if (auto pw = getpwuid(getuid)) { auto uinfo = pw.pw_gecos[0 .. strlen(pw.pw_gecos)].splitter(','); diff --git a/source/dub/internal/utils.d b/source/dub/internal/utils.d index 65b9497..e1e2175 100644 --- a/source/dub/internal/utils.d +++ b/source/dub/internal/utils.d @@ -16,7 +16,7 @@ // todo: cleanup imports. import core.thread; -import std.algorithm : startsWith; +import std.algorithm : canFind, startsWith; import std.array; import std.conv; import std.exception; @@ -199,6 +199,38 @@ } } +version(DubUseCurl) { + /++ + Exception thrown on HTTP request failures, e.g. 404 Not Found. + +/ + static if (__VERSION__ <= 2075) class HTTPStatusException : CurlException + { + /++ + Params: + status = The HTTP status code. + msg = The message for the exception. + file = The file where the exception occurred. + line = The line number where the exception occurred. + next = The previous exception in the chain of exceptions, if any. + +/ + @safe pure nothrow + this( + int status, + string msg, + string file = __FILE__, + size_t line = __LINE__, + Throwable next = null) + { + this.status = status; + super(msg, file, line, next); + } + + int status; /// The HTTP status code + } +} else version (Have_vibe_d_http) { + public import vibe.http.common : HTTPStatusException; +} + /** Downloads a file from the specified URL. @@ -211,10 +243,19 @@ auto conn = HTTP(); setupHTTPClient(conn); logDebug("Storing %s...", url); - std.net.curl.download(url, filename, conn); - enforce(conn.statusLine.code < 400, - format("Failed to download %s: %s %s", - url, conn.statusLine.code, conn.statusLine.reason)); + static if (__VERSION__ <= 2075) + { + try + std.net.curl.download(url, filename, conn); + catch (CurlException e) + { + if (e.msg.canFind("404")) + throw new HTTPStatusException(404, e.msg); + throw e; + } + } + else + std.net.curl.download(url, filename, conn); } else version (Have_vibe_d) { import vibe.inet.urltransfer; vibe.inet.urltransfer.download(url, filename); @@ -232,11 +273,19 @@ auto conn = HTTP(); setupHTTPClient(conn); logDebug("Getting %s...", url); - auto ret = cast(ubyte[])get(url, conn); - enforce(conn.statusLine.code < 400, - format("Failed to GET %s: %s %s", - url, conn.statusLine.code, conn.statusLine.reason)); - return ret; + static if (__VERSION__ <= 2075) + { + try + return cast(ubyte[])get(url, conn); + catch (CurlException e) + { + if (e.msg.canFind("404")) + throw new HTTPStatusException(404, e.msg); + throw e; + } + } + else + return cast(ubyte[])get(url, conn); } else version (Have_vibe_d) { import vibe.inet.urltransfer; import vibe.stream.operations; @@ -276,6 +325,9 @@ auto proxy = environment.get("http_proxy", null); if (proxy.length) conn.proxy = proxy; + auto noProxy = environment.get("no_proxy", null); + if (noProxy.length) conn.handle.set(CurlOption.noproxy, noProxy); + conn.addRequestHeader("User-Agent", "dub/"~getDUBVersion()~" (std.net.curl; +https://github.com/rejectedsoftware/dub)"); } } diff --git a/source/dub/internal/vibecompat/data/json.d b/source/dub/internal/vibecompat/data/json.d index 1699f40..a2705a3 100644 --- a/source/dub/internal/vibecompat/data/json.d +++ b/source/dub/internal/vibecompat/data/json.d @@ -1915,7 +1915,7 @@ char[13] buf; int len; dchar codepoint = decode(s, pos); - import std.c.stdio : sprintf; + import core.stdc.stdio : sprintf; /* codepoint is in BMP */ if(codepoint < 0x10000) { diff --git a/source/dub/internal/vibecompat/inet/url.d b/source/dub/internal/vibecompat/inet/url.d index 389046e..9115c9c 100644 --- a/source/dub/internal/vibecompat/inet/url.d +++ b/source/dub/internal/vibecompat/inet/url.d @@ -107,7 +107,7 @@ } } - this.localURI = str; + this.localURI = (str == "") ? "/" : str; } /// ditto static URL parse(string url_string) @@ -277,4 +277,10 @@ assert(url.path.toString() == "/sub2/index.html", url.path.toString()); assert(url.queryString == "query", url.queryString); assert(url.anchor == "anchor", url.anchor); + + url = URL("http://localhost")~Path("packages"); + assert(url.toString() == "http://localhost/packages", url.toString()); + + url = URL("http://localhost/")~Path("packages"); + assert(url.toString() == "http://localhost/packages", url.toString()); } diff --git a/source/dub/package_.d b/source/dub/package_.d index c499c6e..0f5cf2d 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -500,7 +500,7 @@ This includes dependencies that are declared at the root level of the package recipe, as well as those declared within the specified configuration. If no configuration with the given name exists, only - dependencies declared at the root level will be retunred. + dependencies declared at the root level will be returned. See_Also: `hasDependency` */ diff --git a/source/dub/packagesupplier.d b/source/dub/packagesupplier.d index 540e718..cf12f3c 100644 --- a/source/dub/packagesupplier.d +++ b/source/dub/packagesupplier.d @@ -170,8 +170,10 @@ Version[] getVersions(string package_id) { + auto md = getMetadata(package_id); + if (md.type == Json.Type.null_) + return null; Version[] ret; - Json md = getMetadata(package_id); foreach (json; md["versions"]) { auto cur = Version(cast(string)json["version"]); ret ~= cur; @@ -184,6 +186,8 @@ { import std.array : replace; Json best = getBestPackage(packageId, dep, pre_release); + if (best.type == Json.Type.null_) + return; auto vers = best["version"].get!string; auto url = m_registryUrl ~ Path(PackagesPath~"/"~packageId~"/"~vers~".zip"); logDiagnostic("Downloading from '%s'", url); @@ -209,7 +213,16 @@ logDebug("Downloading metadata for %s", packageId); logDebug("Getting from %s", url); - auto jsonData = cast(string)download(url); + string jsonData; + try + jsonData = cast(string)download(url); + catch (HTTPStatusException e) + { + if (e.status != 404) + throw e; + logDebug("Package %s not found in %s: %s", packageId, description, e.msg); + return Json(null); + } Json json = parseJsonString(jsonData, url.toString()); // strip readme data (to save size and time) foreach (ref v; json["versions"]) @@ -223,10 +236,7 @@ auto url = m_registryUrl; url.localURI = "/api/packages/search?q="~encodeComponent(query); string data; - try - data = cast(string)download(url); - catch (Exception) - return null; + data = cast(string)download(url); import std.algorithm : map; return data.parseJson.opt!(Json[]) .map!(j => SearchResult(j["name"].opt!string, j["description"].opt!string, j["version"].opt!string)) @@ -236,6 +246,8 @@ private Json getBestPackage(string packageId, Dependency dep, bool pre_release) { Json md = getMetadata(packageId); + if (md.type == Json.Type.null_) + return md; Json best = null; Version bestver; foreach (json; md["versions"]) { diff --git a/source/dub/recipe/io.d b/source/dub/recipe/io.d index 9704931..52dbefe 100644 --- a/source/dub/recipe/io.d +++ b/source/dub/recipe/io.d @@ -53,11 +53,14 @@ to determine the file format from the file extension parent_name = Optional name of the parent package (if this is a sub package) + default_package_name = Optional default package name (if no package name + is found in the recipe this value will be used) Returns: Returns the package recipe contents Throws: Throws an exception if an I/O or syntax error occurs */ -PackageRecipe parsePackageRecipe(string contents, string filename, string parent_name = null) +PackageRecipe parsePackageRecipe(string contents, string filename, string parent_name = null, + string default_package_name = null) { import std.algorithm : endsWith; import dub.internal.vibecompat.data.json; @@ -66,6 +69,8 @@ PackageRecipe ret; + ret.name = default_package_name; + if (filename.endsWith(".json")) parseJson(ret, parseJsonString(contents, filename), parent_name); else if (filename.endsWith(".sdl")) parseSDL(ret, contents, parent_name, filename); else assert(false, "readPackageRecipe called with filename with unknown extension: "~filename); diff --git a/test/1-dynLib-simple/.no_build b/test/1-dynLib-simple/.no_build deleted file mode 100644 index 72679d2..0000000 --- a/test/1-dynLib-simple/.no_build +++ /dev/null @@ -1 +0,0 @@ -Remove me when bug with dynamic libs get fixed. diff --git a/test/1-dynLib-simple/.no_build_gdc b/test/1-dynLib-simple/.no_build_gdc new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/1-dynLib-simple/.no_build_gdc diff --git a/test/1-dynLib-simple/.no_build_ldc2 b/test/1-dynLib-simple/.no_build_ldc2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/1-dynLib-simple/.no_build_ldc2 diff --git a/test/1-dynLib-simple/.no_run b/test/1-dynLib-simple/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/1-dynLib-simple/.no_run diff --git a/test/2-dynLib-with-staticLib-dep/.no_build_gdc b/test/2-dynLib-with-staticLib-dep/.no_build_gdc new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/2-dynLib-with-staticLib-dep/.no_build_gdc diff --git a/test/2-dynLib-with-staticLib-dep/.no_build_ldc2 b/test/2-dynLib-with-staticLib-dep/.no_build_ldc2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/2-dynLib-with-staticLib-dep/.no_build_ldc2 diff --git a/test/2-dynLib-with-staticLib-dep/.no_run b/test/2-dynLib-with-staticLib-dep/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/2-dynLib-with-staticLib-dep/.no_run diff --git a/test/2-dynLib-with-staticLib-dep/dub.json b/test/2-dynLib-with-staticLib-dep/dub.json new file mode 100644 index 0000000..f0b6043 --- /dev/null +++ b/test/2-dynLib-with-staticLib-dep/dub.json @@ -0,0 +1,7 @@ +{ + "name": "dynlib-with-staticlib-dep", + "targetType": "dynamicLibrary", + "dependencies": { + "staticlib-simple": { "path": "../1-staticLib-simple/" } + } +} diff --git a/test/2-dynLib-with-staticLib-dep/source/dynlib/app.d b/test/2-dynLib-with-staticLib-dep/source/dynlib/app.d new file mode 100644 index 0000000..9741cae --- /dev/null +++ b/test/2-dynLib-with-staticLib-dep/source/dynlib/app.d @@ -0,0 +1,8 @@ +module dynlib.app; +import std.stdio; +import staticlib.app; + +void foo() +{ + entry(); +} diff --git a/test/common.sh b/test/common.sh index f4585cf..7bd2a27 100644 --- a/test/common.sh +++ b/test/common.sh @@ -7,7 +7,7 @@ local line=$1 local msg=${2:-command failed} local supplemental=${3:-} - >&2 echo "$SOURCE_FILE:$1 Error: $msg" + >&2 echo "[ERROR] $SOURCE_FILE:$1 $msg" if [ ! -z "$supplemental" ]; then echo "$supplemental" | >&2 sed 's|^| |g' fi diff --git a/test/ddox.sh b/test/ddox.sh index 44f836e..9675ed8 100755 --- a/test/ddox.sh +++ b/test/ddox.sh @@ -2,6 +2,12 @@ . $(dirname "${BASH_SOURCE[0]}")/common.sh +# gdc 4.8.5 not working with ddox due to missing +# std.experimental.allocator.mallocator for libdparse +if [ ${DC} = gdc ]; then + exit 0 +fi + (cd $CURR_DIR/ddox/default && $DUB build -b ddox) grep -qF ddox_project $CURR_DIR/ddox/default/docs/index.html diff --git a/test/issue103-single-file-package.sh b/test/issue103-single-file-package.sh index 693a926..0c23eb2 100755 --- a/test/issue103-single-file-package.sh +++ b/test/issue103-single-file-package.sh @@ -16,3 +16,8 @@ if [ -f single-file-test ]; then die $LINENO 'Shebang invocation produced binary in current directory' fi + +if ${DUB} "issue103-single-file-package-error.d" 2> /dev/null; then + echo "Invalid package comment syntax did not trigger an error." + exit 1 +fi diff --git a/test/run-unittest.sh b/test/run-unittest.sh index f04e487..312c9ea 100755 --- a/test/run-unittest.sh +++ b/test/run-unittest.sh @@ -7,7 +7,7 @@ } function logError() { - echo -e 1>&2 "\033[0;31m"$@"\033[0m" + echo -e 1>&2 "\033[0;31m[ERROR] "$@"\033[0m" any_errors=1 } @@ -20,7 +20,7 @@ export -f die if [ -z ${DUB:-} ]; then - die 'Error: Variable $DUB must be defined to run the tests.' + die 'Variable $DUB must be defined to run the tests.' fi if [ -z ${DC:-} ]; then @@ -28,6 +28,7 @@ DC=dmd fi +DC_BIN=$(basename "$DC") CURR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) for script in $(ls $CURR_DIR/*.sh); do @@ -39,8 +40,10 @@ for pack in $(ls -d $CURR_DIR/*/); do if [ -e $pack/.min_frontend ] && [ ! -z "$FRONTEND" -a "$FRONTEND" \< $(cat $pack/.min_frontend) ]; then continue; fi + # First we build the packages - if [ ! -e $pack/.no_build ]; then # For sourceLibrary + if [ ! -e $pack/.no_build ] && [ ! -e $pack/.no_build_$DC_BIN ]; then # For sourceLibrary + build=1 if [ -e $pack/.fail_build ]; then log "Building $pack, expected failure..." $DUB build --force --root=$pack --compiler=$DC 2>/dev/null && logError "Error: Failure expected, but build passed." @@ -48,16 +51,18 @@ log "Building $pack..." $DUB build --force --root=$pack --compiler=$DC || logError "Build failure." fi + else + build=0 fi - # We run the ones that are supposed to be ran - if [ ! -e $pack/.no_build ] && [ ! -e $pack/.no_run ]; then + # We run the ones that are supposed to be run + if [ $build -eq 1 ] && [ ! -e $pack/.no_run ] && [ ! -e $pack/.no_run_$DC_BIN ]; then log "Running $pack..." $DUB run --force --root=$pack --compiler=$DC || logError "Run failure." fi # Finally, the unittest part - if [ ! -e $pack/.no_build ] && [ ! -e $pack/.no_test ]; then + if [ $build -eq 1 ] && [ ! -e $pack/.no_test ] && [ ! -e $pack/.no_test_$DC_BIN ]; then log "Testing $pack..." $DUB test --force --root=$pack --compiler=$DC || logError "Test failure." fi diff --git a/test/single-file-sdl-default-name.d b/test/single-file-sdl-default-name.d new file mode 100644 index 0000000..e7e7bef --- /dev/null +++ b/test/single-file-sdl-default-name.d @@ -0,0 +1,10 @@ +/++dub.sdl: +dependency "sourcelib-simple" path="1-sourceLib-simple" ++/ +module single; + +void main(string[] args) +{ + import sourcelib.app; + entry(); +} diff --git a/test/single-file-sdl-default-name.sh b/test/single-file-sdl-default-name.sh new file mode 100755 index 0000000..1c61540 --- /dev/null +++ b/test/single-file-sdl-default-name.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e +cd ${CURR_DIR} +rm -f single-file-sdl-default-name + +${DUB} run --single single-file-sdl-default-name.d --compiler=${DC} +if [ ! -f single-file-sdl-default-name ]; then + echo "Normal invocation did not produce a binary in the current directory" + exit 1 +fi +rm single-file-sdl-default-name diff --git a/travis-ci.sh b/travis-ci.sh index 7005767..9046bf3 100755 --- a/travis-ci.sh +++ b/travis-ci.sh @@ -2,6 +2,8 @@ set -v -e -o pipefail +source ~/dlang/*/activate # activate host compiler + if [ -z "$FRONTEND" -o "$FRONTEND" \> 2.067.z ]; then vibe_ver=$(jq -r '.versions | .["vibe-d"]' < dub.selections.json) dub fetch vibe-d --version=$vibe_ver # get optional dependency @@ -12,14 +14,25 @@ # library-nonet fails to build with coverage (Issue 13742) dub test --compiler=${DC} -b unittest-cov ./build.sh -cov + + # run tests with different compilers + DUB=`pwd`/bin/dub DC=${DC} test/run-unittest.sh + deactivate + git clean -dxf -- test + source $(~/dlang/install.sh ldc --activate) + DUB=`pwd`/bin/dub DC=${DC} test/run-unittest.sh + deactivate + git clean -dxf -- test + source $(~/dlang/install.sh gdc --activate) + DUB=`pwd`/bin/dub DC=${DC} test/run-unittest.sh else ./build.sh + DUB=`pwd`/bin/dub DC=${DC} test/run-unittest.sh fi -DUB=`pwd`/bin/dub DC=${DC} test/run-unittest.sh if [ "$COVERAGE" = true ]; then - dub fetch doveralls - dub run doveralls --compiler=${DC} + wget https://codecov.io/bash -O codecov.sh + bash codecov.sh fi # check for trailing whitespace (needs to be done only once per build)