diff --git a/.travis.yml b/.travis.yml index 175b072..d6b50cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,15 @@ matrix: include: - d: dmd-nightly - env: [FRONTEND=2.075] + env: [FRONTEND=2.076] - d: dmd-beta - env: [FRONTEND=2.075] + env: [FRONTEND=2.076] - d: dmd env: - - [FRONTEND=2.074] + - [FRONTEND=2.075] - [COVERAGE=true] + - d: dmd-2.075.1 + env: [FRONTEND=2.075] - d: dmd-2.074.1 env: [FRONTEND=2.074] - d: dmd-2.073.2 @@ -33,7 +35,9 @@ - d: ldc-beta env: [FRONTEND=2.073] - d: ldc - env: [FRONTEND=2.072] + env: [FRONTEND=2.073] + - d: ldc-1.3.0 + env: [FRONTEND=2.073] - d: ldc-1.2.0 env: [FRONTEND=2.072] - d: ldc-1.1.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 71fb969..02af669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,50 @@ Changelog ========= +v1.6.0 - 2017- +------------------- + +- The version list displayed for interactive package removal is now sorted - [pull #1225][issue1225], [issue #1224][issue1224] +- File attributes of fetched packages are now preserved - [pull #1226][issue1226] +- `http://code-mirror.dlang.io` is now used as a fallback for `code.dlang.org` - [pull #1190][issue1190] +- Failed package downloads are now retried two more times (by Colin Grogan) - [pull #1198][issue1198] + +[issue1190]: https://github.com/dlang/dub/issues/1190 +[issue1198]: https://github.com/dlang/dub/issues/1198 +[issue1224]: https://github.com/dlang/dub/issues/1224 +[issue1225]: https://github.com/dlang/dub/issues/1225 +[issue1226]: https://github.com/dlang/dub/issues/1226 + + v1.5.0 - 2017-09-01 ------------------- +- Allow digits in package names (by Chad Joan) - [pull #1165][issue1165] +- Support the `no_proxy` environment variable for HTTP requests (by André Pany) - [pull #1162][issue1162], [issue #1159][issue1159] - Read additional registry URLs (semicolon separated) from DUB_REGISTRY env var - [pull #1173][issue1173] +- Single file packages don't have to specify an explicit name anymore (will be inferred from the file name) - [pull #1081][issue1081] +- Add support for the `--parallel` switch for `dub test` (currently only has an effect for `--build-mode=singleFile`) - [pull #1182][issue1182] +- Improved error reporting for package download failures - [pull #1104][issue1104] +- Fixed building the code base against Android/Bionic - [pull #1202][issue1202] +- Extended the generated gitignore file (by Ryan Frame) - [pull #1050][issue1050] +[issue1050]: https://github.com/dlang/dub/issues/1050 +[issue1081]: https://github.com/dlang/dub/issues/1081 +[issue1104]: https://github.com/dlang/dub/issues/1104 +[issue1182]: https://github.com/dlang/dub/issues/1182 +[issue1159]: https://github.com/dlang/dub/issues/1159 +[issue1162]: https://github.com/dlang/dub/issues/1162 +[issue1165]: https://github.com/dlang/dub/issues/1165 [issue1173]: https://github.com/dlang/dub/issues/1173 +[issue1202]: https://github.com/dlang/dub/issues/1202 + v1.4.1 - 2017-08-10 ------------------- +This release is identical with 1.4.0. + + v1.4.0 - 2017-07-19 ------------------- diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..e8aae00 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,3 @@ +#!/bin/env groovy +library 'dlang' +runPipeline() diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..5a05c13 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,124 @@ +platform: x64 +environment: + matrix: + - DC: dmd + DVersion: nightly + arch: x64 + - DC: dmd + DVersion: nightly + arch: x86 + - DC: dmd + DVersion: beta + arch: x64 + - DC: dmd + DVersion: beta + arch: x86 + - DC: dmd + DVersion: stable + arch: x64 + - DC: dmd + DVersion: 2.072.2 + arch: x86 + - DC: dmd + DVersion: 2.072.2 + arch: x64 + - DC: dmd + DVersion: stable + arch: x86 + - DC: ldc + DVersion: beta + arch: x64 + - DC: ldc + DVersion: stable + arch: x64 + - DC: ldc + DVersion: 1.2.0 + arch: x64 + +skip_tags: false +branches: + only: + - master + +install: + - ps: function ResolveLatestDMD + { + $version = $env:DVersion; + if($version -eq "stable") { + $latest = (Invoke-WebRequest "http://downloads.dlang.org/releases/LATEST").toString(); + $url = "http://downloads.dlang.org/releases/2.x/$($latest)/dmd.$($latest).windows.7z"; + }elseif($version -eq "beta") { + $latest = (Invoke-WebRequest "http://downloads.dlang.org/pre-releases/LATEST").toString(); + $latestVersion = $latest.split("-")[0].split("~")[0]; + $url = "http://downloads.dlang.org/pre-releases/2.x/$($latestVersion)/dmd.$($latest).windows.7z"; + }elseif($version -eq "nightly") { + $url = "http://nightlies.dlang.org/dmd-master-2017-05-20/dmd.master.windows.7z" + }else { + $url = "http://downloads.dlang.org/releases/2.x/$($version)/dmd.$($version).windows.7z"; + } + $env:PATH += ";C:\dmd2\windows\bin;"; + return $url; + } + - ps: function ResolveLatestLDC + { + $version = $env:DVersion; + 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"; + }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"; + } else { + $latest = $version; + $url = "https://github.com/ldc-developers/ldc/releases/download/v$($version)/ldc2-$($version)-win64-msvc.zip"; + } + $env:PATH += ";C:\ldc2-$($latest)-win64-msvc\bin"; + $env:DC = "ldc2"; + return $url; + } + - ps: function SetUpDCompiler + { + $env:toolchain = "msvc"; + if($env:DC -eq "dmd"){ + echo "downloading ..."; + $url = ResolveLatestDMD; + echo $url; + Invoke-WebRequest $url -OutFile "c:\dmd.7z"; + echo "finished."; + pushd c:\\; + 7z x dmd.7z > $null; + popd; + } + elseif($env:DC -eq "ldc"){ + echo "downloading ..."; + $url = ResolveLatestLDC; + echo $url; + Invoke-WebRequest $url -OutFile "c:\ldc.zip"; + echo "finished."; + pushd c:\\; + 7z x ldc.zip > $null; + popd; + } + } + - ps: SetUpDCompiler + +build_script: + - ps: if($env:arch -eq "x86"){ + $env:compilersetupargs = "x86"; + $env:Darch = "x86"; + $env:DConf = "m32"; + }elseif($env:arch -eq "x64"){ + $env:compilersetupargs = "amd64"; + $env:Darch = "x86_64"; + $env:DConf = "m64"; + } + - ps: $env:compilersetup = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall"; + - '"%compilersetup%" %compilersetupargs%' + +test_script: + - echo %PLATFORM% + - echo %Darch% + - echo %DC% + - echo %PATH% + - '%DC% --version' + - dub test --arch=%Darch% --compiler=%DC% diff --git a/build.sh b/build.sh index 7cd478e..3b2f527 100755 --- a/build.sh +++ b/build.sh @@ -16,7 +16,7 @@ exit 1 fi -VERSION=$($DMD --version 2>/dev/null | sed -n 's|DMD.* v||p') +VERSION=$($DMD --version 2>/dev/null | sed -En 's|.*DMD.* v([[:digit:]\.]+).*|\1|p') # workaround for link order issues with libcurl (phobos needs to come before curl) if [[ $VERSION < 2.069.0 ]]; then # link against libcurl diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 71e66c3..7da2883 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -18,7 +18,6 @@ import dub.package_; import dub.packagemanager; import dub.packagesupplier; -import dub.platform : determineCompiler; import dub.project; import dub.internal.utils : getDUBVersion, getClosestMatch; @@ -1193,7 +1192,7 @@ "Without specified options, placement/removal will default to a user wide shared location.", "", "Complete applications can be retrieved and run easily by e.g.", - "$ dub fetch vibelog --local", + "$ dub fetch vibelog --cache=local", "$ cd vibelog", "$ dub", "", diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d index b13736e..28367d0 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -12,7 +12,6 @@ import dub.internal.utils; import dub.internal.vibecompat.core.log; import dub.internal.vibecompat.inet.path; -import dub.platform; import std.algorithm; import std.array; diff --git a/source/dub/compilers/gdc.d b/source/dub/compilers/gdc.d index f0b74bd..1718cad 100644 --- a/source/dub/compilers/gdc.d +++ b/source/dub/compilers/gdc.d @@ -12,7 +12,6 @@ import dub.internal.utils; import dub.internal.vibecompat.core.log; import dub.internal.vibecompat.inet.path; -import dub.platform; import std.algorithm; import std.array; diff --git a/source/dub/compilers/ldc.d b/source/dub/compilers/ldc.d index df8c2de..7d25884 100644 --- a/source/dub/compilers/ldc.d +++ b/source/dub/compilers/ldc.d @@ -12,7 +12,6 @@ import dub.internal.utils; import dub.internal.vibecompat.core.log; import dub.internal.vibecompat.inet.path; -import dub.platform; import std.algorithm; import std.array; diff --git a/source/dub/compilers/utils.d b/source/dub/compilers/utils.d index d97abcf..f28f878 100644 --- a/source/dub/compilers/utils.d +++ b/source/dub/compilers/utils.d @@ -8,7 +8,7 @@ module dub.compilers.utils; import dub.compilers.buildsettings; -import dub.platform; +import dub.platform : BuildPlatform, archCheck, compilerCheck, platformCheck; import dub.internal.vibecompat.core.log; import dub.internal.vibecompat.inet.path; import std.algorithm : canFind, endsWith, filter; @@ -255,9 +255,9 @@ fil.close(); } - // NOTE: This must be kept in sync with the dub.platform module fil.write(q{ module dub_platform_probe; + import std.array; template toString(int v) { enum toString = v.stringof; } @@ -273,83 +273,13 @@ pragma(msg, ` ],`); pragma(msg, `}`); - string determinePlatform() - { - string ret; - version(Windows) ret ~= `"windows", `; - version(linux) ret ~= `"linux", `; - version(Posix) ret ~= `"posix", `; - version(OSX) ret ~= `"osx", `; - version(FreeBSD) ret ~= `"freebsd", `; - version(OpenBSD) ret ~= `"openbsd", `; - version(NetBSD) ret ~= `"netbsd", `; - version(DragonFlyBSD) ret ~= `"dragonflybsd", `; - version(BSD) ret ~= `"bsd", `; - version(Solaris) ret ~= `"solaris", `; - version(AIX) ret ~= `"aix", `; - version(Haiku) ret ~= `"haiku", `; - version(SkyOS) ret ~= `"skyos", `; - version(SysV3) ret ~= `"sysv3", `; - version(SysV4) ret ~= `"sysv4", `; - version(Hurd) ret ~= `"hurd", `; - version(Android) ret ~= `"android", `; - version(Cygwin) ret ~= `"cygwin", `; - version(MinGW) ret ~= `"mingw", `; - return ret; - } + string determinePlatform() } ~ '{' ~ platformCheck ~ + ` return '"' ~ ret.data.join("\", \"") ~ "\", "; }` ~ q{ - string determineArchitecture() - { - string ret; - version(X86) ret ~= `"x86", `; - version(X86_64) ret ~= `"x86_64", `; - version(ARM) ret ~= `"arm", `; - version(ARM_Thumb) ret ~= `"arm_thumb", `; - version(ARM_SoftFloat) ret ~= `"arm_softfloat", `; - version(ARM_HardFloat) ret ~= `"arm_hardfloat", `; - version(ARM64) ret ~= `"arm64", `; - version(PPC) ret ~= `"ppc", `; - version(PPC_SoftFP) ret ~= `"ppc_softfp", `; - version(PPC_HardFP) ret ~= `"ppc_hardfp", `; - version(PPC64) ret ~= `"ppc64", `; - version(IA64) ret ~= `"ia64", `; - version(MIPS) ret ~= `"mips", `; - version(MIPS32) ret ~= `"mips32", `; - version(MIPS64) ret ~= `"mips64", `; - version(MIPS_O32) ret ~= `"mips_o32", `; - version(MIPS_N32) ret ~= `"mips_n32", `; - version(MIPS_O64) ret ~= `"mips_o64", `; - version(MIPS_N64) ret ~= `"mips_n64", `; - version(MIPS_EABI) ret ~= `"mips_eabi", `; - version(MIPS_NoFloat) ret ~= `"mips_nofloat", `; - version(MIPS_SoftFloat) ret ~= `"mips_softfloat", `; - version(MIPS_HardFloat) ret ~= `"mips_hardfloat", `; - version(SPARC) ret ~= `"sparc", `; - version(SPARC_V8Plus) ret ~= `"sparc_v8plus", `; - version(SPARC_SoftFP) ret ~= `"sparc_softfp", `; - version(SPARC_HardFP) ret ~= `"sparc_hardfp", `; - version(SPARC64) ret ~= `"sparc64", `; - version(S390) ret ~= `"s390", `; - version(S390X) ret ~= `"s390x", `; - version(HPPA) ret ~= `"hppa", `; - version(HPPA64) ret ~= `"hppa64", `; - version(SH) ret ~= `"sh", `; - version(SH64) ret ~= `"sh64", `; - version(Alpha) ret ~= `"alpha", `; - version(Alpha_SoftFP) ret ~= `"alpha_softfp", `; - version(Alpha_HardFP) ret ~= `"alpha_hardfp", `; - return ret; - } + string determineArchitecture() } ~ '{' ~ archCheck ~ + ` return '"' ~ ret.data.join("\", \"") ~ "\", "; }` ~ q{ - string determineCompiler() - { - version(DigitalMars) return "dmd"; - else version(GNU) return "gdc"; - else version(LDC) return "ldc"; - else version(SDC) return "sdc"; - else return null; - } - }); + string determineCompiler() } ~ '{' ~ compilerCheck ~ " }"); fil.close(); diff --git a/source/dub/dependency.d b/source/dub/dependency.d index 073ac91..40b4863 100644 --- a/source/dub/dependency.d +++ b/source/dub/dependency.d @@ -153,7 +153,7 @@ m_inclusiveB = false; ves = ves[2..$]; m_versA = Version(expandVersion(ves)); - m_versB = Version(bumpVersion(ves)); + m_versB = Version(bumpVersion(ves) ~ "-0"); } else if (ves[0] == Version.branchPrefix) { m_inclusiveA = true; m_inclusiveB = true; @@ -222,7 +222,7 @@ foreach (i; 0 .. 3) { auto vp = parts[0 .. i+1].join("."); auto ve = Version(expandVersion(vp)); - auto veb = Version(expandVersion(bumpVersion(vp))); + auto veb = Version(bumpVersion(vp) ~ "-0"); if (ve == m_versA && veb == m_versB) return "~>" ~ vp; } } @@ -555,16 +555,18 @@ // Approximate versions. a = Dependency("~>3.0"); - b = Dependency(">=3.0.0 <4.0.0"); + b = Dependency(">=3.0.0 <4.0.0-0"); assert(a == b, "Testing failed: " ~ a.toString()); assert(a.matches(Version("3.1.146")), "Failed: Match 3.1.146 with ~>0.1.2"); assert(!a.matches(Version("0.2.0")), "Failed: Match 0.2.0 with ~>0.1.2"); + assert(!a.matches(Version("4.0.0-beta.1"))); a = Dependency("~>3.0.0"); - assert(a == Dependency(">=3.0.0 <3.1.0"), "Testing failed: " ~ a.toString()); + assert(a == Dependency(">=3.0.0 <3.1.0-0"), "Testing failed: " ~ a.toString()); a = Dependency("~>3.5"); - assert(a == Dependency(">=3.5.0 <4.0.0"), "Testing failed: " ~ a.toString()); + assert(a == Dependency(">=3.5.0 <4.0.0-0"), "Testing failed: " ~ a.toString()); a = Dependency("~>3.5.0"); - assert(a == Dependency(">=3.5.0 <3.6.0"), "Testing failed: " ~ a.toString()); + assert(a == Dependency(">=3.5.0 <3.6.0-0"), "Testing failed: " ~ a.toString()); + assert(!Dependency("~>3.0.0").matches(Version("3.1.0-beta"))); a = Dependency("~>0.1.1"); b = Dependency("==0.1.0"); @@ -573,9 +575,11 @@ assert(a.merge(b).valid); b = Dependency("==0.2.0"); assert(!a.merge(b).valid); + b = Dependency("==0.2.0-beta.1"); + assert(!a.merge(b).valid); a = Dependency("~>1.0.1-beta"); - b = Dependency(">=1.0.1-beta <1.1.0"); + b = Dependency(">=1.0.1-beta <1.1.0-0"); assert(a == b, "Testing failed: " ~ a.toString()); assert(a.matches(Version("1.0.1-beta"))); assert(a.matches(Version("1.0.1-beta.6"))); diff --git a/source/dub/dub.d b/source/dub/dub.d index d47632f..3e48d90 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -22,18 +22,14 @@ import dub.generators.generator; import dub.init; - -// todo: cleanup imports. import std.algorithm; -import std.array; -import std.conv; -import std.datetime; -import std.exception; +import std.array : array, replace; +import std.conv : to; +import std.exception : enforce; import std.file; -import std.process; +import std.process : environment; +import std.range : empty; import std.string; -import std.typecons; -import std.zip; import std.encoding : sanitize; // Workaround for libcurl liker errors when building with LDC @@ -65,6 +61,7 @@ /// The URL to the official package registry. enum defaultRegistryURL = "http://code.dlang.org/"; +enum fallbackRegistryURL = "https://code-mirror.dlang.io/"; /** Returns a default list of package suppliers. @@ -76,7 +73,12 @@ PackageSupplier[] defaultPackageSuppliers() { logDiagnostic("Using dub registry url '%s'", defaultRegistryURL); - return [new RegistryPackageSupplier(URL(defaultRegistryURL))]; + return [ + new FallbackPackageSupplier( + new RegistryPackageSupplier(URL(defaultRegistryURL)), + new RegistryPackageSupplier(URL(fallbackRegistryURL)) + ) + ]; } @@ -733,6 +735,7 @@ // import path leakage. dstpath = dstpath ~ packageId; + import std.datetime : seconds; auto lock = lockFile(dstpath.toNativeString() ~ ".lock", 30.seconds); // possibly wait for other dub instance if (dstpath.existsFile()) { @@ -807,6 +810,9 @@ ~ ")"); } + // Sort package list in ascending version order + packages.sort!((a, b) => a.version_ < b.version_); + immutable idx = resolve_version(packages); if (idx == size_t.max) return; @@ -950,6 +956,7 @@ */ auto searchPackages(string query) { + import std.typecons : Tuple, tuple; Tuple!(string, PackageSupplier.SearchResult[])[] results; foreach (ps; this.m_packageSuppliers) { try @@ -1089,6 +1096,8 @@ */ void runDdox(bool run, string[] generate_args = null) { + import std.process : browse; + if (m_dryRun) return; // allow to choose a custom ddox tool @@ -1159,6 +1168,7 @@ private void determineDefaultCompiler() { + import std.range : front; import std.process : environment; m_defaultCompiler = m_config.defaultCompiler; @@ -1309,6 +1319,7 @@ protected override TreeNodes[] getChildren(TreeNode node) { + import std.array : appender; auto ret = appender!(TreeNodes[]); auto pack = getPackage(node.pack, node.config); if (!pack) { diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d index 86ca3e4..c23ea9d 100644 --- a/source/dub/generators/build.d +++ b/source/dub/generators/build.d @@ -119,12 +119,7 @@ auto build_id = computeBuildID(config, buildsettings, settings); // make all paths relative to shrink the command line - string makeRelative(string path) { - auto p = Path(path); - // storing in a separate temprary to work around #601 - auto prel = p.absolute ? p.relativeTo(cwd) : p; - return prel.toNativeString(); - } + string makeRelative(string path) { return shrinkPath(Path(path), cwd); } foreach (ref f; buildsettings.sourceFiles) f = makeRelative(f); foreach (ref p; buildsettings.importPaths) p = makeRelative(p); foreach (ref p; buildsettings.stringImportPaths) p = makeRelative(p); @@ -193,7 +188,7 @@ // override target path auto cbuildsettings = buildsettings; - cbuildsettings.targetPath = target_path.relativeTo(cwd).toNativeString(); + cbuildsettings.targetPath = shrinkPath(target_path, cwd); buildWithCompiler(settings, cbuildsettings); target_binary_path = getTargetPath(cbuildsettings, settings); @@ -466,13 +461,13 @@ (either in the dub.json, or using a command line flag) */ } else if (generate_binary && (settings.buildMode == BuildMode.allAtOnce || settings.compiler.name != "dmd" || is_static_library)) { + // don't include symbols of dependencies (will be included by the top level target) + if (is_static_library) buildsettings.sourceFiles = buildsettings.sourceFiles.filter!(f => !f.isLinkerFile()).array; + // setup for command line settings.compiler.setTarget(buildsettings, settings.platform); settings.compiler.prepareBuildSettings(buildsettings, BuildSetting.commandLine); - // don't include symbols of dependencies (will be included by the top level target) - if (is_static_library) buildsettings.sourceFiles = buildsettings.sourceFiles.filter!(f => !f.isLinkerFile()).array; - // invoke the compiler settings.compiler.invoke(buildsettings, settings.platform, settings.compileCallback); } else { @@ -565,3 +560,53 @@ { return Path(bs.targetPath) ~ settings.compiler.getTargetFileName(bs, settings.platform); } + +private string shrinkPath(Path path, Path base) +{ + auto orig = path.toNativeString(); + if (!path.absolute) return orig; + auto ret = path.relativeTo(base).toNativeString(); + return ret.length < orig.length ? ret : orig; +} + +unittest { + assert(shrinkPath(Path("/foo/bar/baz"), Path("/foo")) == Path("bar/baz").toNativeString()); + assert(shrinkPath(Path("/foo/bar/baz"), Path("/foo/baz")) == Path("../bar/baz").toNativeString()); + assert(shrinkPath(Path("/foo/bar/baz"), Path("/bar/")) == Path("/foo/bar/baz").toNativeString()); + assert(shrinkPath(Path("/foo/bar/baz"), Path("/bar/baz")) == Path("/foo/bar/baz").toNativeString()); +} + +unittest { // issue #1235 - pass no library files to compiler command line when building a static lib + import dub.internal.vibecompat.data.json : parseJsonString; + import dub.compilers.gdc : GDCCompiler; + import dub.platform : determinePlatform; + + version (Windows) auto libfile = "bar.lib"; + else auto libfile = "bar.a"; + + auto desc = parseJsonString(`{"name": "test", "targetType": "library", "sourceFiles": ["foo.d", "`~libfile~`"]}`); + auto pack = new Package(desc, Path("/tmp/fooproject")); + auto pman = new PackageManager(Path("/tmp/foo/"), Path("/tmp/foo/"), false); + auto prj = new Project(pman, pack); + + final static class TestCompiler : GDCCompiler { + override void invoke(in BuildSettings settings, in BuildPlatform platform, void delegate(int, string) output_callback) { + assert(!settings.dflags[].any!(f => f.canFind("bar"))); + } + override void invokeLinker(in BuildSettings settings, in BuildPlatform platform, string[] objects, void delegate(int, string) output_callback) { + assert(false); + } + } + + auto comp = new TestCompiler; + + GeneratorSettings settings; + settings.platform = BuildPlatform(determinePlatform(), ["x86"], "gdc", "test", 2075); + settings.compiler = new TestCompiler; + settings.config = "library"; + settings.buildType = "debug"; + settings.tempBuild = true; + + auto gen = new BuildGenerator(prj); + gen.generate(settings); +} diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 7865d9e..6154bfb 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -163,7 +163,7 @@ } } 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 it's package description to avoid building it.`, + 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; } diff --git a/source/dub/internal/utils.d b/source/dub/internal/utils.d index 7031b7b..52cf55f 100644 --- a/source/dub/internal/utils.d +++ b/source/dub/internal/utils.d @@ -14,18 +14,15 @@ import dub.compilers.buildsettings : BuildSettings; import dub.version_; -// todo: cleanup imports. -import core.thread; +import core.time : Duration; import std.algorithm : canFind, startsWith; -import std.array; -import std.conv; -import std.exception; +import std.array : appender; +import std.conv : to; +import std.exception : enforce; import std.file; +import std.string : format; import std.process; -import std.string; import std.traits : isIntegral; -import std.typecons; -import std.zip; version(DubUseCurl) { import std.net.curl; @@ -64,6 +61,7 @@ */ auto lockFile(string path, Duration timeout) { + import core.thread : Thread; import std.datetime, std.stdio : File; import std.algorithm : move; @@ -127,6 +125,7 @@ } Json jsonFromZip(Path zip, string filename) { + import std.zip : ZipArchive; auto f = openFile(zip, FileMode.read); ubyte[] b = new ubyte[cast(size_t)f.size]; f.rawRead(b); @@ -308,6 +307,7 @@ string getDUBVersion() { import dub.version_; + import std.array : split, join; // convert version string to valid SemVer format auto verstr = dubVersion; if (verstr.startsWith("v")) verstr = verstr[1 .. $]; @@ -332,6 +332,8 @@ auto noProxy = environment.get("no_proxy", null); if (noProxy.length) conn.handle.set(CurlOption.noproxy, noProxy); + conn.handle.set(CurlOption.encoding, ""); + conn.addRequestHeader("User-Agent", "dub/"~getDUBVersion()~" (std.net.curl; +https://github.com/rejectedsoftware/dub)"); } } diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index 4ff4e6f..a0f9f61 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -379,6 +379,16 @@ return path[zip_prefix.length..path.length]; } + static void setAttributes(string path, ArchiveMember am) + { + import std.datetime : DosFileTimeToSysTime; + + auto mtime = DosFileTimeToSysTime(am.time); + setTimes(path, mtime, mtime); + if (auto attrs = am.fileAttributes) + std.file.setAttributes(path, attrs); + } + // extract & place mkdirRecurse(destination.toNativeString()); logDebug("Copying all files..."); @@ -395,9 +405,12 @@ } else { if( !existsDirectory(dst_path.parentPath) ) mkdirRecurse(dst_path.parentPath.toNativeString()); - auto dstFile = openFile(dst_path, FileMode.createTrunc); - scope(exit) dstFile.close(); - dstFile.put(archive.expand(a)); + { + auto dstFile = openFile(dst_path, FileMode.createTrunc); + scope(exit) dstFile.close(); + dstFile.put(archive.expand(a)); + } + setAttributes(dst_path.toNativeString(), a); ++countFiles; } } diff --git a/source/dub/packagesupplier.d b/source/dub/packagesupplier.d index cf12f3c..449cbd0 100644 --- a/source/dub/packagesupplier.d +++ b/source/dub/packagesupplier.d @@ -21,6 +21,7 @@ import std.exception; import std.file; import std.string : format; +import std.typecons : AutoImplement; import std.zip; // TODO: Could drop the "best package" behavior and let retrievePackage/ @@ -191,7 +192,20 @@ auto vers = best["version"].get!string; auto url = m_registryUrl ~ Path(PackagesPath~"/"~packageId~"/"~vers~".zip"); logDiagnostic("Downloading from '%s'", url); - download(url, path); + foreach(i; 0..3) { + try{ + download(url, path); + return; + } + catch(HTTPStatusException e) { + if (e.status == 404) throw e; + else { + logDebug("Failed to download package %s from %s (Attempt %s of 3)", packageId, url, i + 1); + continue; + } + } + } + throw new Exception("Failed to download package %s from %s".format(packageId, url)); } Json fetchPackageRecipe(string packageId, Dependency dep, bool pre_release) @@ -214,14 +228,24 @@ logDebug("Getting from %s", 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); + foreach(i; 0..3) { + try { + jsonData = cast(string)download(url); + break; + } + catch (HTTPStatusException e) + { + if (e.status == 404) { + logDebug("Package %s not found at %s (404): %s", packageId, description, e.msg); + return Json(null); + } + else { + logDebug("Error getting metadata for package %s at %s (attempt %s of 3): %s", packageId, description, i + 1, e.msg); + if (i == 2) + throw e; + continue; + } + } } Json json = parseJsonString(jsonData, url.toString()); // strip readme data (to save size and time) @@ -266,4 +290,41 @@ } } +package abstract class AbstractFallbackPackageSupplier : PackageSupplier +{ + protected PackageSupplier m_default, m_fallback; + + this(PackageSupplier default_, PackageSupplier fallback) + { + m_default = default_; + m_fallback = fallback; + } + + override @property string description() + { + return format("%s (fallback %s)", m_default.description, m_fallback.description); + } + + // Workaround https://issues.dlang.org/show_bug.cgi?id=2525 + abstract override Version[] getVersions(string package_id); + abstract override void fetchPackage(Path path, string package_id, Dependency dep, bool pre_release); + abstract override Json fetchPackageRecipe(string package_id, Dependency dep, bool pre_release); + abstract override SearchResult[] searchPackages(string query); +} + +/** + Combines two package suppliers and uses the second as fallback to handle failures. + + Assumes that both registries serve the same packages (--mirror). +*/ +package alias FallbackPackageSupplier = AutoImplement!(AbstractFallbackPackageSupplier, fallback); + +private template fallback(T, alias func) +{ + enum fallback = q{ + scope (failure) return m_fallback.%1$s(args); + return m_default.%1$s(args); + }.format(__traits(identifier, func)); +} + private enum PackagesPath = "packages"; diff --git a/source/dub/platform.d b/source/dub/platform.d index 830c1d4..3b8ee88 100644 --- a/source/dub/platform.d +++ b/source/dub/platform.d @@ -1,5 +1,5 @@ /** - Build platform identification and speficiation matching. + Build platform identification and specification matching. This module is useful for determining the build platform for a certain machine and compiler invocation. Example applications include classifying @@ -8,7 +8,7 @@ It also contains means to match build platforms against a platform specification string as used in package reciptes. - Copyright: © 2012-2016 rejectedsoftware e.K. + Copyright: © 2012-2017 rejectedsoftware e.K. License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. Authors: Sönke Ludwig */ @@ -16,35 +16,11 @@ import std.array; - -/** Determines the full build platform used for the current build. - - Note that the `BuildPlatform.compilerBinary` field will be left empty. - - See_Also: `determinePlatform`, `determineArchitecture`, `determineCompiler` -*/ -BuildPlatform determineBuildPlatform() -{ - BuildPlatform ret; - ret.platform = determinePlatform(); - ret.architecture = determineArchitecture(); - ret.compiler = determineCompiler(); - ret.frontendVersion = __VERSION__; - return ret; -} - - -/** Returns a list of platform identifiers that apply to the current - build. - - Example results are `["windows"]` or `["posix", "osx"]`. The identifiers - correspond to the compiler defined version constants built into the - language, except that they are converted to lower case. - - See_Also: `determineBuildPlatform` -*/ -string[] determinePlatform() -{ +// archCheck, compilerCheck, and platformCheck are used below and in +// generatePlatformProbeFile, so they've been extracted into these strings +// that can be reused. +/// private +enum string platformCheck = q{ auto ret = appender!(string[])(); version(Windows) ret.put("windows"); version(linux) ret.put("linux"); @@ -65,20 +41,10 @@ version(Android) ret.put("android"); version(Cygwin) ret.put("cygwin"); version(MinGW) ret.put("mingw"); - return ret.data; -} +}; -/** Returns a list of architecture identifiers that apply to the current - build. - - Example results are `["x86_64"]` or `["arm", "arm_softfloat"]`. The - identifiers correspond to the compiler defined version constants built into - the language, except that they are converted to lower case. - - See_Also: `determineBuildPlatform` -*/ -string[] determineArchitecture() -{ +/// private +enum string archCheck = q{ auto ret = appender!(string[])(); version(X86) ret.put("x86"); version(X86_64) ret.put("x86_64"); @@ -117,23 +83,74 @@ version(Alpha) ret.put("alpha"); version(Alpha_SoftFP) ret.put("alpha_softfp"); version(Alpha_HardFP) ret.put("alpha_hardfp"); +}; + +/// private +enum string compilerCheck = q{ + version(DigitalMars) return "dmd"; + else version(GNU) return "gdc"; + else version(LDC) return "ldc"; + else version(SDC) return "sdc"; + else return null; +}; + +/** Determines the full build platform used for the current build. + + Note that the `BuildPlatform.compilerBinary` field will be left empty. + + See_Also: `determinePlatform`, `determineArchitecture`, `determineCompiler` +*/ +BuildPlatform determineBuildPlatform() +{ + BuildPlatform ret; + ret.platform = determinePlatform(); + ret.architecture = determineArchitecture(); + ret.compiler = determineCompiler(); + ret.frontendVersion = __VERSION__; + return ret; +} + + +/** Returns a list of platform identifiers that apply to the current + build. + + Example results are `["windows"]` or `["posix", "osx"]`. The identifiers + correspond to the compiler defined version constants built into the + language, except that they are converted to lower case. + + See_Also: `determineBuildPlatform` +*/ +string[] determinePlatform() +{ + mixin(platformCheck); + return ret.data; +} + +/** Returns a list of architecture identifiers that apply to the current + build. + + Example results are `["x86_64"]` or `["arm", "arm_softfloat"]`. The + identifiers correspond to the compiler defined version constants built into + the language, except that they are converted to lower case. + + See_Also: `determineBuildPlatform` +*/ +string[] determineArchitecture() +{ + mixin(archCheck); return ret.data; } /** Determines the canonical compiler name used for the current build. - The possible values currently are "dmd", "gdc", "ldc2" or "sdc". If an + The possible values currently are "dmd", "gdc", "ldc" or "sdc". If an unknown compiler is used, this function will return an empty string. See_Also: `determineBuildPlatform` */ string determineCompiler() { - version(DigitalMars) return "dmd"; - else version(GNU) return "gdc"; - else version(LDC) return "ldc2"; - else version(SDC) return "sdc"; - else return null; + mixin(compilerCheck); } /** Matches a platform specification string against a build platform. diff --git a/source/dub/project.d b/source/dub/project.d index b8f7813..23a3a96 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -20,18 +20,12 @@ import dub.packagesupplier; import dub.generators.generator; - -// todo: cleanup imports. import std.algorithm; import std.array; -import std.conv; +import std.conv : to; import std.datetime; -import std.exception; -import std.file; -import std.process; +import std.exception : enforce; import std.string; -import std.typecons; -import std.zip; import std.encoding : sanitize; /** @@ -1099,6 +1093,7 @@ } private void writeDubJson() { + import std.file : exists, mkdir; // don't bother to write an empty file if( m_packageSettings.length == 0 ) return; @@ -1218,6 +1213,7 @@ private string getVariable(string name, in Project project, in Package pack) { + import std.process : environment; if (name == "PACKAGE_DIR") return pack.path.toNativeString(); if (name == "ROOT_PACKAGE_DIR") return project.rootPackage.path.toNativeString(); diff --git a/test/issue884-init-defer-file-creation.sh b/test/issue884-init-defer-file-creation.sh index b71b268..013842c 100755 --- a/test/issue884-init-defer-file-creation.sh +++ b/test/issue884-init-defer-file-creation.sh @@ -9,8 +9,7 @@ cd ${TMPDIR} # kill dub init during interactive mode -${DUB} init < /dev/stdin & -sleep 1 +${DUB} init <(while :; do sleep 1; done) & kill $! # ensure that no files are left behind