diff --git a/source/dub/commandline.d b/source/dub/commandline.d index b00220d..759dc45 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -254,8 +254,7 @@ PackageSupplier ps = getRegistryPackageSupplier(urls.front); urls.popFront; if (!urls.empty) - ps = new FallbackPackageSupplier(ps, - urls.map!(u => getRegistryPackageSupplier(u)).array); + ps = new FallbackPackageSupplier(ps ~ urls.map!getRegistryPackageSupplier.array); return ps; }) .array; @@ -309,7 +308,7 @@ args.getopt("skip-registry", &skipRegistry, [ "Sets a mode for skipping the search on certain package registry types:", " none: Search all configured or default registries (default)", - " standard: Don't search the main registry (e.g. "~defaultRegistryURL~")", + " standard: Don't search the main registry (e.g. "~defaultRegistryURLs[0]~")", " configured: Skip all default and user configured registries", " all: Only search registries specified with --registry", ]); diff --git a/source/dub/dub.d b/source/dub/dub.d index f6e3682..027e349 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -59,13 +59,12 @@ registerCompiler(new LDCCompiler); } -/// The URL to the official package registry. -enum defaultRegistryURL = "https://code.dlang.org/"; -enum fallbackRegistryURLs = [ - // fallback in case of HTTPS problems - "http://code.dlang.org/", +deprecated("use defaultRegistryURLs") enum defaultRegistryURL = defaultRegistryURLs[0]; + +/// The URL to the official package registry and it's default fallback registries. +enum defaultRegistryURLs = [ + "https://code.dlang.org/", "https://code-mirror.dlang.io/", - "https://code-mirror2.dlang.io/", "https://dub-registry.herokuapp.com/", ]; @@ -74,17 +73,12 @@ This will contain a single package supplier that points to the official package registry. - See_Also: `defaultRegistryURL` + See_Also: `defaultRegistryURLs` */ PackageSupplier[] defaultPackageSuppliers() { - logDiagnostic("Using dub registry url '%s'", defaultRegistryURL); - return [ - new FallbackPackageSupplier( - new RegistryPackageSupplier(URL(defaultRegistryURL)), - fallbackRegistryURLs.map!(x => cast(PackageSupplier) new RegistryPackageSupplier(URL(x))).array - ) - ]; + logDiagnostic("Using dub registry url '%s'", defaultRegistryURLs[0]); + return [new FallbackPackageSupplier(defaultRegistryURLs.map!getRegistryPackageSupplier.array)]; } /** Returns a registry package supplier according to protocol. diff --git a/source/dub/packagesuppliers/fallback.d b/source/dub/packagesuppliers/fallback.d index 7a691a9..39a61e6 100644 --- a/source/dub/packagesuppliers/fallback.d +++ b/source/dub/packagesuppliers/fallback.d @@ -5,20 +5,26 @@ package abstract class AbstractFallbackPackageSupplier : PackageSupplier { - protected PackageSupplier m_default; - protected PackageSupplier[] m_fallbacks; + protected import core.time : minutes; + protected import std.datetime : Clock, SysTime; - this(PackageSupplier default_, PackageSupplier[] fallbacks) + static struct Pair { PackageSupplier ps; SysTime failTime; } + protected Pair[] m_suppliers; + + this(PackageSupplier[] suppliers) { - m_default = default_; - m_fallbacks = fallbacks; + assert(suppliers.length); + m_suppliers.length = suppliers.length; + foreach (i, ps; suppliers) + m_suppliers[i].ps = ps; } override @property string description() { import std.algorithm.iteration : map; import std.format : format; - return format("%s (fallback %s)", m_default.description, m_fallbacks.map!(x => x.description)); + return format("%s (fallbacks %-(%s, %))", m_suppliers[0].ps.description, + m_suppliers[1 .. $].map!(pair => pair.ps.description)); } // Workaround https://issues.dlang.org/show_bug.cgi?id=2525 @@ -40,19 +46,35 @@ { import std.format : format; enum fallback = q{ - import std.range : back, dropBackOne; - import dub.internal.vibecompat.core.log : logDebug; - scope (failure) + import dub.internal.vibecompat.core.log : logDiagnostic; + + Exception firstEx; + try + return m_suppliers[0].ps.%1$s(args); + catch (Exception e) { - foreach (m_fallback; m_fallbacks.dropBackOne) - { - try - return m_fallback.%1$s(args); - catch(Exception) - logDebug("Package supplier %s failed. Trying next fallback.", m_fallback); - } - return m_fallbacks.back.%1$s(args); + logDiagnostic("Package supplier %%s failed with '%%s', trying fallbacks.", + m_suppliers[0].ps.description, e.msg); + firstEx = e; } - return m_default.%1$s(args); + + immutable now = Clock.currTime; + foreach (ref pair; m_suppliers[1 .. $]) + { + if (pair.failTime > now - 10.minutes) + continue; + try + { + scope (success) logDiagnostic("Fallback %%s succeeded", pair.ps.description); + return pair.ps.%1$s(args); + } + catch (Exception e) + { + pair.failTime = now; + logDiagnostic("Fallback package supplier %%s failed with '%%s'.", + pair.ps.description, e.msg); + } + } + throw firstEx; }.format(__traits(identifier, func)); } diff --git a/test/feat663-search.sh b/test/feat663-search.sh index 435c8d8..21cea3e 100755 --- a/test/feat663-search.sh +++ b/test/feat663-search.sh @@ -7,9 +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); then - die $LINENO '`dub search dub` failed' "$OUTPUT" +if ! OUTPUT=$(${DUB} search '"dub-registry"' -v 2>&1); then + die $LINENO '`dub search "dub-registry"` failed' "$OUTPUT" fi -if ! grep -q '^dub (.*)\s'<<<"$OUTPUT"; then - die $LINENO '`grep -q '"'"'^dub (.*)\s'"'"'` failed' "$OUTPUT" +if ! grep -q '^dub-registry (.*)\s'<<<"$OUTPUT"; then + die $LINENO '`grep -q '"'"'^dub-registry (.*)\s'"'"'` failed' "$OUTPUT" fi