diff --git a/source/dub/commandline.d b/source/dub/commandline.d index cc26a77..a23f786 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -194,7 +194,10 @@ } // execute the command - try return cmd.execute(dub, remaining_args, app_args); + int rc; + try { + rc = cmd.execute(dub, remaining_args, app_args); + } catch (UsageException e) { logError("%s", e.msg); logDiagnostic("Full exception: %s", e.toString().sanitize); @@ -206,6 +209,10 @@ logDiagnostic("Full exception: %s", e.toString().sanitize); return 2; } + + if (!cmd.skipDubInitialization) + dub.shutdown(); + return rc; } class CommandArgs { diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d index 4d64589..4880e3e 100644 --- a/source/dub/compilers/compiler.d +++ b/source/dub/compilers/compiler.d @@ -375,13 +375,13 @@ } fil.write(q{ - import std.array, std.conv; + template toString(int v) { enum toString = v.stringof; } void main() { pragma(msg, `{`); pragma(msg,` "compiler": "`~ determineCompiler() ~ `",`); - pragma(msg, ` "frontendVersion": ` ~ to!string(__VERSION__) ~ `,`); + pragma(msg, ` "frontendVersion": ` ~ toString!__VERSION__ ~ `,`); pragma(msg, ` "compilerVendor": "` ~ __VENDOR__ ~ `",`); pragma(msg, ` "platform": [`); pragma(msg, ` ` ~ determinePlatform()); @@ -395,72 +395,70 @@ string determinePlatform() { - auto ret = appender!(string[])(); - version(Windows) ret.put("windows"); - version(linux) ret.put("linux"); - version(Posix) ret.put("posix"); - version(OSX) ret.put("osx"); - version(FreeBSD) ret.put("freebsd"); - version(OpenBSD) ret.put("openbsd"); - version(NetBSD) ret.put("netbsd"); - version(DragonFlyBSD) ret.put("dragonflybsd"); - version(BSD) ret.put("bsd"); - version(Solaris) ret.put("solaris"); - version(AIX) ret.put("aix"); - version(Haiku) ret.put("haiku"); - version(SkyOS) ret.put("skyos"); - version(SysV3) ret.put("sysv3"); - version(SysV4) ret.put("sysv4"); - version(Hurd) ret.put("hurd"); - version(Android) ret.put("android"); - version(Cygwin) ret.put("cygwin"); - version(MinGW) ret.put("mingw"); - foreach(ref str; ret.data) str = `"` ~ str ~ `"`; - return ret.data.join(",\n "); + 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 determineArchitecture() { - auto ret = appender!(string[])(); - version(X86) ret.put("x86"); - version(X86_64) ret.put("x86_64"); - version(ARM) ret.put("arm"); - version(ARM_Thumb) ret.put("arm_thumb"); - version(ARM_SoftFloat) ret.put("arm_softfloat"); - version(ARM_HardFloat) ret.put("arm_hardfloat"); - version(ARM64) ret.put("arm64"); - version(PPC) ret.put("ppc"); - version(PPC_SoftFP) ret.put("ppc_softfp"); - version(PPC_HardFP) ret.put("ppc_hardfp"); - version(PPC64) ret.put("ppc64"); - version(IA64) ret.put("ia64"); - version(MIPS) ret.put("mips"); - version(MIPS32) ret.put("mips32"); - version(MIPS64) ret.put("mips64"); - version(MIPS_O32) ret.put("mips_o32"); - version(MIPS_N32) ret.put("mips_n32"); - version(MIPS_O64) ret.put("mips_o64"); - version(MIPS_N64) ret.put("mips_n64"); - version(MIPS_EABI) ret.put("mips_eabi"); - version(MIPS_NoFloat) ret.put("mips_nofloat"); - version(MIPS_SoftFloat) ret.put("mips_softfloat"); - version(MIPS_HardFloat) ret.put("mips_hardfloat"); - version(SPARC) ret.put("sparc"); - version(SPARC_V8Plus) ret.put("sparc_v8plus"); - version(SPARC_SoftFP) ret.put("sparc_softfp"); - version(SPARC_HardFP) ret.put("sparc_hardfp"); - version(SPARC64) ret.put("sparc64"); - version(S390) ret.put("s390"); - version(S390X) ret.put("s390x"); - version(HPPA) ret.put("hppa"); - version(HPPA64) ret.put("hppa64"); - version(SH) ret.put("sh"); - version(SH64) ret.put("sh64"); - version(Alpha) ret.put("alpha"); - version(Alpha_SoftFP) ret.put("alpha_softfp"); - version(Alpha_HardFP) ret.put("alpha_hardfp"); - foreach(ref str; ret.data) str = `"` ~ str ~ `"`; - return ret.data.join(",\n "); + 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 determineCompiler() diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d index 10dba58..9f5e65d 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -67,8 +67,8 @@ } settings.addDFlags(arch_flags); - auto result = executeShell(escapeShellCommand(compiler_binary ~ arch_flags ~ ["-quiet", "-od"~getTempDir.toNativeString(), - "-of"~(getTempDir~"dub_platform_probe").toNativeString(), fil.toNativeString()])); + auto result = executeShell(escapeShellCommand(compiler_binary ~ arch_flags ~ + ["-quiet", "-c", "-o-", fil.toNativeString()])); enforce(result.status == 0, format("Failed to invoke the compiler %s to determine the build platform: %s", compiler_binary, result.output)); diff --git a/source/dub/compilers/gdc.d b/source/dub/compilers/gdc.d index ac59d50..b6eae57 100644 --- a/source/dub/compilers/gdc.d +++ b/source/dub/compilers/gdc.d @@ -67,7 +67,7 @@ } settings.addDFlags(arch_flags); - auto result = executeShell(escapeShellCommand(compiler_binary ~ arch_flags ~ ["-o", (getTempDir()~"dub_platform_probe").toNativeString(), fil.toNativeString()])); + auto result = executeShell(escapeShellCommand(compiler_binary ~ arch_flags ~ ["-c", fil.toNativeString()])); enforce(result.status == 0, format("Failed to invoke the compiler %s to determine the build platform: %s", compiler_binary, result.output)); diff --git a/source/dub/dub.d b/source/dub/dub.d index a976cf8..272ae21 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -105,6 +105,10 @@ .array; ps ~= defaultPackageSuppliers(); + auto cacheDir = m_userDubPath ~ "cache/"; + foreach (p; ps) + p.loadCache(cacheDir); + m_packageSuppliers = ps; m_packageManager = new PackageManager(m_userDubPath, m_systemDubPath); updatePackageSearchPath(); @@ -118,6 +122,14 @@ updatePackageSearchPath(); } + /// Perform cleanup and persist caches to disk + void shutdown() + { + auto cacheDir = m_userDubPath ~ "cache/"; + foreach (p; m_packageSuppliers) + p.storeCache(cacheDir); + } + @property void dryRun(bool v) { m_dryRun = v; } /** Returns the root path (usually the current working directory). diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d index 56a72a6..0ca456d 100644 --- a/source/dub/generators/build.d +++ b/source/dub/generators/build.d @@ -307,7 +307,7 @@ logDiagnostic("Copying target from %s to %s", src.toNativeString(), buildsettings.targetPath); if (!existsFile(Path(buildsettings.targetPath))) mkdirRecurse(buildsettings.targetPath); - copyFile(src, Path(buildsettings.targetPath) ~ filename, true); + symlinkFile(src, Path(buildsettings.targetPath) ~ filename, true); } private bool isUpToDate(Path target_path, BuildSettings buildsettings, BuildPlatform platform, in Package main_pack, in Package[] packages, in Path[] additional_dep_files) diff --git a/source/dub/internal/vibecompat/core/file.d b/source/dub/internal/vibecompat/core/file.d index 5a806a3..e6849fe 100644 --- a/source/dub/internal/vibecompat/core/file.d +++ b/source/dub/internal/vibecompat/core/file.d @@ -134,6 +134,31 @@ } /** + Creates a symlink. +*/ +version (Windows) + alias symlinkFile = copyFile; // TODO: symlinks on Windows +else version (Posix) +{ + void symlinkFile(Path from, Path to, bool overwrite = false) + { + if (existsFile(to)) { + enforce(overwrite, "Destination file already exists."); + // remove file before copy to allow "overwriting" files that are in + // use on Linux + removeFile(to); + } + + .symlink(from.toNativeString(), to.toNativeString()); + } +} + +void symlinkFile(string from, string to) +{ + symlinkFile(Path(from), Path(to)); +} + +/** Removes a file */ void removeFile(Path path) @@ -288,4 +313,3 @@ } return ret; } - diff --git a/source/dub/packagesupplier.d b/source/dub/packagesupplier.d index fe65b32..2f6ae81 100644 --- a/source/dub/packagesupplier.d +++ b/source/dub/packagesupplier.d @@ -38,6 +38,12 @@ /// returns the metadata for the package Json getPackageDescription(string packageId, Dependency dep, bool pre_release); + + /// load caches to disk + void loadCache(Path cacheDir); + + /// persist caches to disk + void storeCache(Path cacheDir); } class FileSystemPackageSupplier : PackageSupplier { @@ -79,6 +85,12 @@ return jsonFromZip(filename, "dub.json"); } + void storeCache(Path cacheDir) { + } + + void loadCache(Path cacheDir) { + } + private Path bestPackageFile(string packageId, Dependency dep, bool pre_release) { Path toPath(Version ver) { @@ -102,6 +114,7 @@ struct CacheEntry { Json data; SysTime cacheTime; } CacheEntry[string] m_metadataCache; Duration m_maxCacheTime; + bool m_metadataCacheDirty; } this(URL registry) @@ -139,12 +152,42 @@ return getBestPackage(packageId, dep, pre_release); } + void storeCache(Path cacheDir) + { + if (!m_metadataCacheDirty) return; + + auto path = cacheDir ~ cacheFileName; + if (!cacheDir.existsFile()) + mkdirRecurse(cacheDir.toNativeString()); + // TODO: method is slow due to Json escaping + writeJsonFile(path, m_metadataCache.serializeToJson()); + m_metadataCacheDirty = false; + } + + void loadCache(Path cacheDir) + { + auto path = cacheDir ~ cacheFileName; + if (!path.existsFile()) return; + + deserializeJson(m_metadataCache, jsonFromFile(path)); + m_metadataCacheDirty = false; + } + + private @property string cacheFileName() + { + import std.digest.md; + auto hash = m_registryUrl.toString.md5Of(); + return m_registryUrl.host ~ hash[0 .. $/2].toHexString().idup ~ ".json"; + } + private Json getMetadata(string packageId) { auto now = Clock.currTime(UTC()); if (auto pentry = packageId in m_metadataCache) { if (pentry.cacheTime + m_maxCacheTime > now) return pentry.data; + m_metadataCache.remove(packageId); + m_metadataCacheDirty = true; } auto url = m_registryUrl ~ Path(PackagesPath ~ "/" ~ packageId ~ ".json"); @@ -154,7 +197,11 @@ auto jsonData = cast(string)download(url); Json json = parseJsonString(jsonData); + // strip readme data (to save size and time) + foreach (ref v; json["versions"]) + v.remove("readme"); m_metadataCache[packageId] = CacheEntry(json, now); + m_metadataCacheDirty = true; return json; }