Hello community,

here is the log from the commit of package dub for openSUSE:Factory checked in 
at 2018-07-09 13:29:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/dub (Old)
 and      /work/SRC/openSUSE:Factory/.dub.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "dub"

Mon Jul  9 13:29:46 2018 rev:10 rq:621565 version:1.10.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/dub/dub.changes  2018-05-13 16:05:02.394386937 
+0200
+++ /work/SRC/openSUSE:Factory/.dub.new/dub.changes     2018-07-09 
13:31:32.562466220 +0200
@@ -1,0 +2,6 @@
+Sun Jul  8 13:24:16 UTC 2018 - [email protected]
+
+- Update to 1.10.0
+  * DUB supports "customCachePaths" for providing read-only package paths
+
+-------------------------------------------------------------------

Old:
----
  dub-1.9.0.tar.gz

New:
----
  dub-1.10.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ dub.spec ++++++
--- /var/tmp/diff_new_pack.o6nb2c/_old  2018-07-09 13:31:33.062465214 +0200
+++ /var/tmp/diff_new_pack.o6nb2c/_new  2018-07-09 13:31:33.066465206 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           dub
-Version:        1.9.0
+Version:        1.10.0
 Release:        0
 Summary:        Package manager and meta build tool for the D programming 
language
 License:        MIT

++++++ dub-1.9.0.tar.gz -> dub-1.10.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/.gitignore new/dub-1.10.0/.gitignore
--- old/dub-1.9.0/.gitignore    2018-05-01 15:43:29.000000000 +0200
+++ new/dub-1.10.0/.gitignore   2018-07-03 20:08:52.000000000 +0200
@@ -18,6 +18,7 @@
 /bin/dub-*
 
 # Ignore files or directories created by the test suite.
+/test/test.log
 /test/custom-source-main-bug487/custom-source-main-bug487
 /test/3-copyFiles/bin/
 /test/ignore-hidden-1/ignore-hidden-1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/CHANGELOG.md new/dub-1.10.0/CHANGELOG.md
--- old/dub-1.9.0/CHANGELOG.md  2018-05-01 15:43:29.000000000 +0200
+++ new/dub-1.10.0/CHANGELOG.md 2018-07-03 20:08:52.000000000 +0200
@@ -1,6 +1,10 @@
 Changelog
 =========
 
+v1.10.0 - 2018-07-01
+-------------------
+See <https://dlang.org/changelog/2.081.0.html>
+
 v1.9.0 - 2018-05-01
 -------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/CONTRIBUTING.md 
new/dub-1.10.0/CONTRIBUTING.md
--- old/dub-1.9.0/CONTRIBUTING.md       1970-01-01 01:00:00.000000000 +0100
+++ new/dub-1.10.0/CONTRIBUTING.md      2018-07-03 20:08:52.000000000 +0200
@@ -0,0 +1,11 @@
+# Guidelines for Contributing
+
+## Building
+
+Build a development version of dub using either `./build.sh` or `./build.cmd` 
on Windows.
+When you already have a working dub binary, you can also just run `dub build`, 
though that won't update the version string.
+
+## Changelog
+
+Every feature addition should come with a changelog entry, see the 
[changelog/README.md](changelog/README.md) for how to add a new entry. Any 
`.dd` file is rendered using ddoc and is the same format used across all dlang 
repos.
+For bugfixes make sure to automatically [close the issue via commit 
message](https://blog.github.com/2013-01-22-closing-issues-via-commit-messages/)
 (e.g. `fixes #123`), so that they can be listed in the changelog.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/build-files.txt 
new/dub-1.10.0/build-files.txt
--- old/dub-1.9.0/build-files.txt       2018-05-01 15:43:29.000000000 +0200
+++ new/dub-1.10.0/build-files.txt      2018-07-03 20:08:52.000000000 +0200
@@ -7,6 +7,12 @@
 source/dub/init.d
 source/dub/packagemanager.d
 source/dub/packagesupplier.d
+source/dub/packagesuppliers/package.d
+source/dub/packagesuppliers/fallback.d
+source/dub/packagesuppliers/filesystem.d
+source/dub/packagesuppliers/packagesupplier.d
+source/dub/packagesuppliers/maven.d
+source/dub/packagesuppliers/registry.d
 source/dub/package_.d
 source/dub/platform.d
 source/dub/project.d
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/changelog/README.md 
new/dub-1.10.0/changelog/README.md
--- old/dub-1.9.0/changelog/README.md   1970-01-01 01:00:00.000000000 +0100
+++ new/dub-1.10.0/changelog/README.md  2018-07-03 20:08:52.000000000 +0200
@@ -0,0 +1,42 @@
+This directory will get copied to dlang.org and cleared when master gets
+merged into stable prior to a new release.
+
+How to add a new changelog entry to the pending changelog?
+==========================================================
+
+Create a new file in the `changelog` folder. It should end with `.dd` and look
+similar to a git commit message. The first line represents the title of the 
change.
+After an empty line follows the long description:
+
+```
+My fancy title of the new feature
+
+A long description of the new feature in `std.range`.
+It can be followed by an example:
+-------
+import std.range : padLeft, padRight;
+import std.algorithm.comparison : equal;
+
+assert([1, 2, 3, 4, 5].padLeft(0, 7).equal([0, 0, 1, 2, 3, 4, 5]));
+
+assert("Hello World!".padRight('!', 15).equal("Hello World!!!!"));
+-------
+and links to the documentation, e.g. $(REF drop, std, range) or
+$(REF_ALTTEXT a custom name for the function, drop, std, range).
+
+Links to the spec can look like this $(LINK2 $(ROOT_DIR)spec/module.html, this)
+and of course you can link to other $(LINK2 https://forum.dlang.org/, external 
resources).
+```
+
+The title can't contain links (it's already one).
+For more infos, see the [Ddoc spec](https://dlang.org/spec/ddoc.html).
+
+Preview changes
+---------------
+
+If you have cloned the [tools](https://github.com/dlang/tools) and 
[dlang.org](https://github.com/dlang/dlang.org) repo,
+you can preview the changelog with:
+
+```
+make -C ../dlang.org -f posix.mak pending_changelog
+```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/changelog/customCachePaths.dd 
new/dub-1.10.0/changelog/customCachePaths.dd
--- old/dub-1.9.0/changelog/customCachePaths.dd 1970-01-01 01:00:00.000000000 
+0100
+++ new/dub-1.10.0/changelog/customCachePaths.dd        2018-07-03 
20:08:52.000000000 +0200
@@ -0,0 +1,6 @@
+DUB supports "customCachePaths" for providing read-only package paths
+
+With this release DUB allows defining additional paths that contain packages 
in subfolders with the pattern "(name)-(version)/(name)/" by defining a 
"customCachePaths" field in `/etc/dub/settings.json` or `~/.dub/settings.json.`
+
+"customCachePaths" can be used to provide prebuilt DUB libraries (e.g. for 
distribution package maintainers).
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/dub.sdl new/dub-1.10.0/dub.sdl
--- old/dub-1.9.0/dub.sdl       2018-05-01 15:43:29.000000000 +0200
+++ new/dub-1.10.0/dub.sdl      2018-07-03 20:08:52.000000000 +0200
@@ -1,6 +1,7 @@
 name "dub"
 description "Package manager for D packages"
-authors "Matthias Dondorff" "Sönke Ludwig"
+authors "Sönke Ludwig" "Martin Nowak" "Matthias Dondorff" "Sebastian Wilzbach" 
\
+       "more than 80 contributors total"
 copyright "Copyright © 2012-2016 rejectedsoftware e.K., Copyright © 2012-2014 
Matthias Dondorff"
 license "MIT"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/commandline.d 
new/dub-1.10.0/source/dub/commandline.d
--- old/dub-1.9.0/source/dub/commandline.d      2018-05-01 15:43:29.000000000 
+0200
+++ new/dub-1.10.0/source/dub/commandline.d     2018-07-03 20:08:52.000000000 
+0200
@@ -17,7 +17,7 @@
 import dub.internal.vibecompat.inet.url;
 import dub.package_;
 import dub.packagemanager;
-import dub.packagesupplier;
+import dub.packagesuppliers;
 import dub.project;
 import dub.internal.utils : getDUBVersion, getClosestMatch;
 
@@ -230,11 +230,11 @@
                                        // should simply retry over all 
registries instead of using a special
                                        // FallbackPackageSupplier.
                                        auto urls = url.splitter(' ');
-                                       PackageSupplier ps = new 
RegistryPackageSupplier(URL(urls.front));
+                                       PackageSupplier ps = 
getRegistryPackageSupplier(urls.front);
                                        urls.popFront;
                                        if (!urls.empty)
                                                ps = new 
FallbackPackageSupplier(ps,
-                                                       urls.map!(u => 
cast(PackageSupplier) new RegistryPackageSupplier(URL(u))).array);
+                                                       urls.map!(u => 
getRegistryPackageSupplier(u)).array);
                                        return ps;
                                })
                                .array;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/compilers/utils.d 
new/dub-1.10.0/source/dub/compilers/utils.d
--- old/dub-1.9.0/source/dub/compilers/utils.d  2018-05-01 15:43:29.000000000 
+0200
+++ new/dub-1.10.0/source/dub/compilers/utils.d 2018-07-03 20:08:52.000000000 
+0200
@@ -253,10 +253,13 @@
                module dub_platform_probe;
 
                template toString(int v) { enum toString = v.stringof; }
-               string join(string[] ary, string sep) {
-                       string res = ary[0];
-                       foreach (e; ary[1 .. $])
-                               res ~= sep ~ e;
+               string stringArray(string[] ary) {
+                       string res;
+                       foreach (i, e; ary) {
+                               if (i)
+                                       res ~= ", ";
+                               res ~= '"' ~ e ~ '"';
+                       }
                        return res;
                }
 
@@ -265,10 +268,10 @@
                pragma(msg, `  "frontendVersion": ` ~ toString!__VERSION__ ~ 
`,`);
                pragma(msg, `  "compilerVendor": "` ~ __VENDOR__ ~ `",`);
                pragma(msg, `  "platform": [`);
-               pragma(msg, `    "` ~ determinePlatform().join(`", "`) ~ '"');
+               pragma(msg, `    ` ~ determinePlatform().stringArray);
                pragma(msg, `  ],`);
                pragma(msg, `  "architecture": [`);
-               pragma(msg, `    "` ~ determineArchitecture().join(`", "`) ~ 
'"');
+               pragma(msg, `    ` ~ determineArchitecture().stringArray);
                pragma(msg, `   ],`);
                pragma(msg, `}`);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/dub.d 
new/dub-1.10.0/source/dub/dub.d
--- old/dub-1.9.0/source/dub/dub.d      2018-05-01 15:43:29.000000000 +0200
+++ new/dub-1.10.0/source/dub/dub.d     2018-07-03 20:08:52.000000000 +0200
@@ -17,7 +17,7 @@
 import dub.internal.vibecompat.inet.url;
 import dub.package_;
 import dub.packagemanager;
-import dub.packagesupplier;
+import dub.packagesuppliers;
 import dub.project;
 import dub.generators.generator;
 import dub.init;
@@ -87,6 +87,34 @@
        ];
 }
 
+/** Returns a registry package supplier according to protocol.
+
+       Allowed protocols are dub+http(s):// and maven+http(s)://.
+*/
+PackageSupplier getRegistryPackageSupplier(string url)
+{
+       switch (url.startsWith("dub+", "mvn+"))
+       {
+               case 1:
+                       return new RegistryPackageSupplier(URL(url[4..$]));
+               case 2:
+                       return new MavenRegistryPackageSupplier(URL(url[4..$]));
+               default:
+                       return new RegistryPackageSupplier(URL(url));
+       }
+}
+
+unittest
+{
+       auto dubRegistryPackageSupplier = 
getRegistryPackageSupplier("dub+https://code.dlang.org";);
+       assert(dubRegistryPackageSupplier.description.canFind(" 
https://code.dlang.org";));
+
+       dubRegistryPackageSupplier = 
getRegistryPackageSupplier("https://code.dlang.org";);
+       assert(dubRegistryPackageSupplier.description.canFind(" 
https://code.dlang.org";));
+
+       auto mavenRegistryPackageSupplier = 
getRegistryPackageSupplier("mvn+http://localhost:8040/maven/libs-release/dubpackages";);
+       assert(mavenRegistryPackageSupplier.description.canFind(" 
http://localhost:8040/maven/libs-release/dubpackages";));
+}
 
 /** Provides a high-level entry point for DUB's functionality.
 
@@ -145,14 +173,14 @@
                {
                        ps ~= environment.get("DUB_REGISTRY", null)
                                .splitter(";")
-                               .map!(url => cast(PackageSupplier)new 
RegistryPackageSupplier(URL(url)))
+                               .map!(url => getRegistryPackageSupplier(url))
                                .array;
                }
 
                if (skip_registry < SkipPackageSuppliers.configured)
                {
                        ps ~= m_config.registryURLs
-                               .map!(url => cast(PackageSupplier)new 
RegistryPackageSupplier(URL(url)))
+                               .map!(url => getRegistryPackageSupplier(url))
                                .array;
                }
 
@@ -161,6 +189,11 @@
 
                m_packageSuppliers = ps;
                m_packageManager = new PackageManager(m_dirs.localRepository, 
m_dirs.systemSettings);
+
+               auto ccps = m_config.customCachePaths;
+               if (ccps.length)
+                       m_packageManager.customCachePaths = ccps;
+
                updatePackageSearchPath();
        }
 
@@ -224,12 +257,12 @@
                m_defaultArchitecture = m_config.defaultArchitecture;
        }
 
-       version(Windows) 
+       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))
@@ -237,7 +270,7 @@
             mkdirRecurse(localDirPath);
         }
 
-        runCommand("xcopy /s /e /y " ~ roamingDirPath ~ " " ~ localDirPath ~ " 
> NUL"); 
+        runCommand("xcopy /s /e /y " ~ roamingDirPath ~ " " ~ localDirPath ~ " 
> NUL");
         rmdirRecurse(roamingDirPath);
        }
 
@@ -1234,16 +1267,15 @@
                import std.path : buildPath, dirName, expandTilde, isAbsolute, 
isDirSeparator;
                import std.process : environment;
                import std.range : front;
-               import std.regex : ctRegex, matchFirst;
 
                m_defaultCompiler = m_config.defaultCompiler.expandTilde;
                if (m_defaultCompiler.length && m_defaultCompiler.isAbsolute)
                        return;
 
-               auto dubPrefix = 
m_defaultCompiler.matchFirst(ctRegex!(`^\$DUB_BINARY_PATH`));
-               if(!dubPrefix.empty)
+               static immutable BinaryPrefix = `$DUB_BINARY_PATH`;
+               if(m_defaultCompiler.startsWith(BinaryPrefix))
                {
-                       m_defaultCompiler = thisExePath().dirName() ~ 
dubPrefix.post;
+                       m_defaultCompiler = thisExePath().dirName() ~ 
m_defaultCompiler[BinaryPrefix.length .. $];
                        return;
                }
 
@@ -1626,6 +1658,21 @@
                return ret;
        }
 
+       @property NativePath[] customCachePaths()
+       {
+               import std.algorithm.iteration : map;
+               import std.array : array;
+
+               NativePath[] ret;
+               if (auto pv = "customCachePaths" in m_data)
+                       ret = (*pv).deserializeJson!(string[])
+                               .map!(s => NativePath(s))
+                               .array;
+               if (m_parentConfig)
+                       ret ~= m_parentConfig.customCachePaths;
+               return ret;
+       }
+
        @property string defaultCompiler()
        const {
                if (auto pv = "defaultCompiler" in m_data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/internal/utils.d 
new/dub-1.10.0/source/dub/internal/utils.d
--- old/dub-1.9.0/source/dub/internal/utils.d   2018-05-01 15:43:29.000000000 
+0200
+++ new/dub-1.10.0/source/dub/internal/utils.d  2018-07-03 20:08:52.000000000 
+0200
@@ -198,7 +198,8 @@
                Pid pid;
                pid = spawnShell(cmd, stdin, childStdout, childStderr, env, 
config);
                auto exitcode = pid.wait();
-               enforce(exitcode == 0, "Command failed with exit code 
"~to!string(exitcode));
+               enforce(exitcode == 0, "Command failed with exit code "
+                       ~ to!string(exitcode) ~ ": " ~ cmd);
        }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/internal/vibecompat/data/json.d 
new/dub-1.10.0/source/dub/internal/vibecompat/data/json.d
--- old/dub-1.9.0/source/dub/internal/vibecompat/data/json.d    2018-05-01 
15:43:29.000000000 +0200
+++ new/dub-1.10.0/source/dub/internal/vibecompat/data/json.d   2018-07-03 
20:08:52.000000000 +0200
@@ -2102,13 +2102,19 @@
 
 private void enforceJson(string file = __FILE__, size_t line = __LINE__)(bool 
cond, lazy string message = "JSON exception")
 {
-       enforceEx!JSONException(cond, message, file, line);
+       static if (__VERSION__ >= 2079)
+               enforce!JSONException(cond, message, file, line);
+       else
+               enforceEx!JSONException(cond, message, file, line);
 }
 
 private void enforceJson(string file = __FILE__, size_t line = __LINE__)(bool 
cond, lazy string message, string err_file, int err_line)
 {
        auto errmsg() { return format("%s(%s): Error: %s", err_file, 
err_line+1, message); }
-       enforceEx!JSONException(cond, errmsg, file, line);
+       static if (__VERSION__ >= 2079)
+               enforce!JSONException(cond, errmsg, file, line);
+       else
+               enforceEx!JSONException(cond, errmsg, file, line);
 }
 
 private void enforceJson(string file = __FILE__, size_t line = __LINE__)(bool 
cond, lazy string message, string err_file, int* err_line)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/packagemanager.d 
new/dub-1.10.0/source/dub/packagemanager.d
--- old/dub-1.9.0/source/dub/packagemanager.d   2018-05-01 15:43:29.000000000 
+0200
+++ new/dub-1.10.0/source/dub/packagemanager.d  2018-07-03 20:08:52.000000000 
+0200
@@ -30,7 +30,7 @@
 /// packages.
 class PackageManager {
        private {
-               Repository[LocalPackageType] m_repositories;
+               Repository[] m_repositories;
                NativePath[] m_searchPath;
                Package[] m_packages;
                Package[] m_temporaryPackages;
@@ -39,8 +39,9 @@
 
        this(NativePath user_path, NativePath system_path, bool 
refresh_packages = true)
        {
-               m_repositories[LocalPackageType.user] = Repository(user_path);
-               m_repositories[LocalPackageType.system] = 
Repository(system_path);
+               m_repositories.length = LocalPackageType.max+1;
+               m_repositories[LocalPackageType.user] = Repository(user_path ~ 
"packages/");
+               m_repositories[LocalPackageType.system] = 
Repository(system_path ~ "packages/");
                if (refresh_packages) refresh(true);
        }
 
@@ -71,14 +72,33 @@
                auto ret = appender!(NativePath[])();
                ret.put(cast(NativePath[])m_searchPath); // work around Phobos 
17251
                if (!m_disableDefaultSearchPaths) {
-                       
ret.put(cast(NativePath[])m_repositories[LocalPackageType.user].searchPath);
-                       
ret.put(cast(NativePath)m_repositories[LocalPackageType.user].packagePath);
-                       
ret.put(cast(NativePath[])m_repositories[LocalPackageType.system].searchPath);
-                       
ret.put(cast(NativePath)m_repositories[LocalPackageType.system].packagePath);
+                       foreach (ref repo; m_repositories) {
+                               ret.put(cast(NativePath[])repo.searchPath);
+                               ret.put(cast(NativePath)repo.packagePath);
+                       }
                }
                return ret.data;
        }
 
+       /** Sets additional (read-only) package cache paths to search for 
packages.
+
+               Cache paths have the same structure as the default cache paths, 
such as
+               ".dub/packages/".
+
+               Note that previously set custom paths will be removed when 
setting this
+               property.
+       */
+       @property void customCachePaths(NativePath[] custom_cache_paths)
+       {
+               import std.algorithm.iteration : map;
+               import std.array : array;
+
+               m_repositories.length = LocalPackageType.max+1;
+               m_repositories ~= custom_cache_paths.map!(p => 
Repository(p)).array;
+
+               refresh(false);
+       }
+
 
        /** Looks up a specific package.
 
@@ -100,8 +120,8 @@
        Package getPackage(string name, Version ver, bool enable_overrides = 
true)
        {
                if (enable_overrides) {
-                       foreach (tp; [LocalPackageType.user, 
LocalPackageType.system])
-                               foreach (ovr; m_repositories[tp].overrides)
+                       foreach (ref repo; m_repositories)
+                               foreach (ovr; repo.overrides)
                                        if (ovr.package_ == name && 
ovr.version_.matches(ver)) {
                                                Package pack;
                                                if (!ovr.targetPath.empty) pack 
= getOrLoadPackage(ovr.targetPath);
@@ -266,8 +286,8 @@
                                if (auto ret = del(tp)) return ret;
 
                        // first search local packages
-                       foreach (tp; LocalPackageType.min .. 
LocalPackageType.max+1)
-                               foreach (p; 
m_repositories[cast(LocalPackageType)tp].localPackages)
+                       foreach (ref repo; m_repositories)
+                               foreach (p; repo.localPackages)
                                        if (auto ret = del(p)) return ret;
 
                        // and then all packages gathered from the search path
@@ -803,7 +823,6 @@
 
 
 private struct Repository {
-       NativePath path;
        NativePath packagePath;
        NativePath[] searchPath;
        Package[] localPackages;
@@ -811,7 +830,6 @@
 
        this(NativePath path)
        {
-               this.path = path;
-               this.packagePath = path ~"packages/";
+               this.packagePath = path;
        }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/packagesupplier.d 
new/dub-1.10.0/source/dub/packagesupplier.d
--- old/dub-1.9.0/source/dub/packagesupplier.d  2018-05-01 15:43:29.000000000 
+0200
+++ new/dub-1.10.0/source/dub/packagesupplier.d 2018-07-03 20:08:52.000000000 
+0200
@@ -1,344 +1,10 @@
-/**
-       Contains (remote) package supplier interface and implementations.
+/**    +deprecated("Please use dub.packagesuppliers")
+       Contains (remote) package supplier interface and implementations.       
+public import dub.packagesuppliers;
 
        Copyright: © 2012-2013 Matthias Dondorff, 2012-2016 Sönke Ludwig
        License: Subject to the terms of the MIT license, as written in the 
included LICENSE.txt file.
        Authors: Matthias Dondorff
 */
+deprecated("Please use dub.packagesuppliers")
 module dub.packagesupplier;
-
-import dub.dependency;
-import dub.internal.utils;
-import dub.internal.vibecompat.core.log;
-import dub.internal.vibecompat.core.file;
-import dub.internal.vibecompat.data.json;
-import dub.internal.vibecompat.inet.url;
-
-import std.algorithm : filter, sort;
-import std.array : array;
-import std.conv;
-import std.datetime;
-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/
-//       getPackageDescription take a Version instead of Dependency. But note
-//       this means that two requests to the registry are necessary to retrieve
-//       a package recipe instead of one (first get version list, then the
-//       package recipe)
-
-/**
-       Base interface for remote package suppliers.
-
-       Provides functionality necessary to query package versions, recipes and
-       contents.
-*/
-interface PackageSupplier {
-       /// Represents a single package search result.
-       static struct SearchResult { string name, description, version_; }
-
-       /// Returns a human-readable representation of the package supplier.
-       @property string description();
-
-       /** Retrieves a list of all available versions(/branches) of a package.
-
-               Throws: Throws an exception if the package name is not known, 
or if
-                       an error occurred while retrieving the version list.
-       */
-       Version[] getVersions(string package_id);
-
-       /** Downloads a package and stores it as a ZIP file.
-
-               Params:
-                       path = Absolute path of the target ZIP file
-                       package_id = Name of the package to retrieve
-                       dep: Version constraint to match against
-                       pre_release: If true, matches the latest pre-release 
version.
-                               Otherwise prefers stable versions.
-       */
-       void fetchPackage(NativePath path, string package_id, Dependency dep, 
bool pre_release);
-
-       /** Retrieves only the recipe of a particular package.
-
-               Params:
-                       package_id = Name of the package of which to retrieve 
the recipe
-                       dep: Version constraint to match against
-                       pre_release: If true, matches the latest pre-release 
version.
-                               Otherwise prefers stable versions.
-       */
-       Json fetchPackageRecipe(string package_id, Dependency dep, bool 
pre_release);
-
-       /** Searches for packages matching the given search query term.
-
-               Search queries are currently a simple list of words separated by
-               white space. Results will get ordered from best match to worst.
-       */
-       SearchResult[] searchPackages(string query);
-}
-
-
-/**
-       File system based package supplier.
-
-       This package supplier searches a certain directory for files with names 
of
-       the form "[package name]-[version].zip".
-*/
-class FileSystemPackageSupplier : PackageSupplier {
-       private {
-               NativePath m_path;
-       }
-
-       this(NativePath root) { m_path = root; }
-
-       override @property string description() { return "file repository at 
"~m_path.toNativeString(); }
-
-       Version[] getVersions(string package_id)
-       {
-               Version[] ret;
-               foreach (DirEntry d; dirEntries(m_path.toNativeString(), 
package_id~"*", SpanMode.shallow)) {
-                       NativePath p = NativePath(d.name);
-                       logDebug("Entry: %s", p);
-                       enforce(to!string(p.head)[$-4..$] == ".zip");
-                       auto vers = p.head.toString()[package_id.length+1..$-4];
-                       logDebug("Version: %s", vers);
-                       ret ~= Version(vers);
-               }
-               ret.sort();
-               return ret;
-       }
-
-       void fetchPackage(NativePath path, string packageId, Dependency dep, 
bool pre_release)
-       {
-               enforce(path.absolute);
-               logInfo("Storing package '"~packageId~"', version requirements: 
%s", dep);
-               auto filename = bestPackageFile(packageId, dep, pre_release);
-               enforce(existsFile(filename));
-               copyFile(filename, path);
-       }
-
-       Json fetchPackageRecipe(string packageId, Dependency dep, bool 
pre_release)
-       {
-               auto filename = bestPackageFile(packageId, dep, pre_release);
-               return jsonFromZip(filename, "dub.json");
-       }
-
-       SearchResult[] searchPackages(string query)
-       {
-               // TODO!
-               return null;
-       }
-
-       private NativePath bestPackageFile(string packageId, Dependency dep, 
bool pre_release)
-       {
-               NativePath toPath(Version ver) {
-                       return m_path ~ (packageId ~ "-" ~ ver.toString() ~ 
".zip");
-               }
-               auto versions = getVersions(packageId).filter!(v => 
dep.matches(v)).array;
-               enforce(versions.length > 0, format("No package %s found 
matching %s", packageId, dep));
-               foreach_reverse (ver; versions) {
-                       if (pre_release || !ver.isPreRelease)
-                               return toPath(ver);
-               }
-               return toPath(versions[$-1]);
-       }
-}
-
-
-/**
-       Online registry based package supplier.
-
-       This package supplier connects to an online registry (e.g.
-       $(LINK https://code.dlang.org/)) to search for available packages.
-*/
-class RegistryPackageSupplier : PackageSupplier {
-       private {
-               URL m_registryUrl;
-               struct CacheEntry { Json data; SysTime cacheTime; }
-               CacheEntry[string] m_metadataCache;
-               Duration m_maxCacheTime;
-       }
-
-       this(URL registry)
-       {
-               m_registryUrl = registry;
-               m_maxCacheTime = 24.hours();
-       }
-
-       override @property string description() { return "registry at 
"~m_registryUrl.toString(); }
-
-       Version[] getVersions(string package_id)
-       {
-               auto md = getMetadata(package_id);
-               if (md.type == Json.Type.null_)
-                       return null;
-               Version[] ret;
-               foreach (json; md["versions"]) {
-                       auto cur = Version(cast(string)json["version"]);
-                       ret ~= cur;
-               }
-               ret.sort();
-               return ret;
-       }
-
-       void fetchPackage(NativePath path, string packageId, Dependency dep, 
bool pre_release)
-       {
-               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 ~ 
NativePath(PackagesPath~"/"~packageId~"/"~vers~".zip");
-               logDiagnostic("Downloading from '%s'", url);
-               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)
-       {
-               return getBestPackage(packageId, dep, pre_release);
-       }
-
-       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);
-               }
-
-               auto url = m_registryUrl ~ NativePath(PackagesPath ~ "/" ~ 
packageId ~ ".json");
-
-               logDebug("Downloading metadata for %s", packageId);
-               logDebug("Getting from %s", url);
-
-               string jsonData;
-               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)
-               foreach (ref v; json["versions"])
-                       v.remove("readme");
-               m_metadataCache[packageId] = CacheEntry(json, now);
-               return json;
-       }
-
-       SearchResult[] searchPackages(string query) {
-               import std.uri : encodeComponent;
-               auto url = m_registryUrl;
-               url.localURI = "/api/packages/search?q="~encodeComponent(query);
-               string data;
-               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))
-                       .array;
-       }
-
-       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"]) {
-                       auto cur = Version(cast(string)json["version"]);
-                       if (!dep.matches(cur)) continue;
-                       if (best == null) best = json;
-                       else if (pre_release) {
-                               if (cur > bestver) best = json;
-                       } else if (bestver.isPreRelease) {
-                               if (!cur.isPreRelease || cur > bestver) best = 
json;
-                       } else if (!cur.isPreRelease && cur > bestver) best = 
json;
-                       bestver = Version(cast(string)best["version"]);
-               }
-               enforce(best != null, "No package candidate found for 
"~packageId~" "~dep.toString());
-               return best;
-       }
-}
-
-package abstract class AbstractFallbackPackageSupplier : PackageSupplier
-{
-       protected PackageSupplier m_default;
-       protected PackageSupplier[] m_fallbacks;
-
-       this(PackageSupplier default_, PackageSupplier[] fallbacks)
-       {
-               m_default = default_;
-               m_fallbacks = fallbacks;
-       }
-
-       override @property string description()
-       {
-               import std.algorithm : map;
-               return format("%s (fallback %s)", m_default.description, 
m_fallbacks.map!(x => x.description));
-       }
-
-       // Workaround https://issues.dlang.org/show_bug.cgi?id=2525
-       abstract override Version[] getVersions(string package_id);
-       abstract override void fetchPackage(NativePath 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{
-               import std.range : back, dropBackOne;
-               import dub.internal.vibecompat.core.log : logDebug;
-               scope (failure)
-               {
-                       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);
-               }
-               return m_default.%1$s(args);
-       }.format(__traits(identifier, func));
-}
-
-private enum PackagesPath = "packages";
+public import dub.packagesuppliers;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/packagesuppliers/fallback.d 
new/dub-1.10.0/source/dub/packagesuppliers/fallback.d
--- old/dub-1.9.0/source/dub/packagesuppliers/fallback.d        1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/source/dub/packagesuppliers/fallback.d       2018-07-03 
20:08:52.000000000 +0200
@@ -0,0 +1,58 @@
+module dub.packagesuppliers.fallback;
+
+import dub.packagesuppliers.packagesupplier;
+import std.typecons : AutoImplement;
+
+package abstract class AbstractFallbackPackageSupplier : PackageSupplier
+{
+       protected PackageSupplier m_default;
+       protected PackageSupplier[] m_fallbacks;
+
+       this(PackageSupplier default_, PackageSupplier[] fallbacks)
+       {
+               m_default = default_;
+               m_fallbacks = fallbacks;
+       }
+
+       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));
+       }
+
+       // Workaround https://issues.dlang.org/show_bug.cgi?id=2525
+       abstract override Version[] getVersions(string package_id);
+       abstract override void fetchPackage(NativePath 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(dub) alias FallbackPackageSupplier = 
AutoImplement!(AbstractFallbackPackageSupplier, fallback);
+
+private template fallback(T, alias func)
+{
+       import std.format : format;
+       enum fallback = q{
+               import std.range : back, dropBackOne;
+               import dub.internal.vibecompat.core.log : logDebug;
+               scope (failure)
+               {
+                       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);
+               }
+               return m_default.%1$s(args);
+       }.format(__traits(identifier, func));
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/packagesuppliers/filesystem.d 
new/dub-1.10.0/source/dub/packagesuppliers/filesystem.d
--- old/dub-1.9.0/source/dub/packagesuppliers/filesystem.d      1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/source/dub/packagesuppliers/filesystem.d     2018-07-03 
20:08:52.000000000 +0200
@@ -0,0 +1,80 @@
+module dub.packagesuppliers.filesystem;
+
+import dub.packagesuppliers.packagesupplier;
+
+/**
+       File system based package supplier.
+
+       This package supplier searches a certain directory for files with names 
of
+       the form "[package name]-[version].zip".
+*/
+class FileSystemPackageSupplier : PackageSupplier {
+       import dub.internal.vibecompat.core.log;
+       version (Have_vibe_core) import dub.internal.vibecompat.inet.path : 
toNativeString;
+       import std.exception : enforce;
+       private {
+               NativePath m_path;
+       }
+
+       this(NativePath root) { m_path = root; }
+
+       override @property string description() { return "file repository at 
"~m_path.toNativeString(); }
+
+       Version[] getVersions(string package_id)
+       {
+               import std.algorithm.sorting : sort;
+               import std.file : dirEntries, DirEntry, SpanMode;
+               import std.conv : to;
+               Version[] ret;
+               foreach (DirEntry d; dirEntries(m_path.toNativeString(), 
package_id~"*", SpanMode.shallow)) {
+                       NativePath p = NativePath(d.name);
+                       logDebug("Entry: %s", p);
+                       enforce(to!string(p.head)[$-4..$] == ".zip");
+                       auto vers = p.head.toString()[package_id.length+1..$-4];
+                       logDebug("Version: %s", vers);
+                       ret ~= Version(vers);
+               }
+               ret.sort();
+               return ret;
+       }
+
+       void fetchPackage(NativePath path, string packageId, Dependency dep, 
bool pre_release)
+       {
+               import dub.internal.vibecompat.core.file : copyFile, existsFile;
+               enforce(path.absolute);
+               logInfo("Storing package '"~packageId~"', version requirements: 
%s", dep);
+               auto filename = bestPackageFile(packageId, dep, pre_release);
+               enforce(existsFile(filename));
+               copyFile(filename, path);
+       }
+
+       Json fetchPackageRecipe(string packageId, Dependency dep, bool 
pre_release)
+       {
+               import dub.internal.utils : jsonFromZip;
+               auto filename = bestPackageFile(packageId, dep, pre_release);
+               return jsonFromZip(filename, "dub.json");
+       }
+
+       SearchResult[] searchPackages(string query)
+       {
+               // TODO!
+               return null;
+       }
+
+       private NativePath bestPackageFile(string packageId, Dependency dep, 
bool pre_release)
+       {
+               import std.algorithm.iteration : filter;
+               import std.array : array;
+               import std.format : format;
+               NativePath toPath(Version ver) {
+                       return m_path ~ (packageId ~ "-" ~ ver.toString() ~ 
".zip");
+               }
+               auto versions = getVersions(packageId).filter!(v => 
dep.matches(v)).array;
+               enforce(versions.length > 0, format("No package %s found 
matching %s", packageId, dep));
+               foreach_reverse (ver; versions) {
+                       if (pre_release || !ver.isPreRelease)
+                               return toPath(ver);
+               }
+               return toPath(versions[$-1]);
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/packagesuppliers/maven.d 
new/dub-1.10.0/source/dub/packagesuppliers/maven.d
--- old/dub-1.9.0/source/dub/packagesuppliers/maven.d   1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/source/dub/packagesuppliers/maven.d  2018-07-03 
20:08:52.000000000 +0200
@@ -0,0 +1,137 @@
+module dub.packagesuppliers.maven;
+
+import dub.packagesuppliers.packagesupplier;
+
+/**
+       Maven repository based package supplier.
+
+       This package supplier connects to a maven repository
+       to search for available packages.
+*/
+class MavenRegistryPackageSupplier : PackageSupplier {
+       import dub.internal.utils : download, HTTPStatusException;
+       import dub.internal.vibecompat.data.json : serializeToJson;
+       import dub.internal.vibecompat.core.log;
+       import dub.internal.vibecompat.inet.url : URL;
+
+       import std.datetime : Clock, Duration, hours, SysTime, UTC;
+
+       private {
+               URL m_mavenUrl;
+               struct CacheEntry { Json data; SysTime cacheTime; }
+               CacheEntry[string] m_metadataCache;
+               Duration m_maxCacheTime;
+       }
+
+       this(URL mavenUrl)
+       {
+               m_mavenUrl = mavenUrl;
+               m_maxCacheTime = 24.hours();
+       }
+
+       override @property string description() { return "maven repository at 
"~m_mavenUrl.toString(); }
+
+       Version[] getVersions(string package_id)
+       {
+               import std.algorithm.sorting : sort;
+               auto md = getMetadata(package_id);
+               if (md.type == Json.Type.null_)
+                       return null;
+               Version[] ret;
+               foreach (json; md["versions"]) {
+                       auto cur = Version(json["version"].get!string);
+                       ret ~= cur;
+               }
+               ret.sort();
+               return ret;
+       }
+
+       void fetchPackage(NativePath path, string packageId, Dependency dep, 
bool pre_release)
+       {
+               import std.format : format;
+               auto md = getMetadata(packageId);
+               Json best = getBestPackage(md, packageId, dep, pre_release);
+               if (best.type == Json.Type.null_)
+                       return;
+               auto vers = best["version"].get!string;
+               auto url = 
m_mavenUrl~NativePath("%s/%s/%s-%s.zip".format(packageId, vers, packageId, 
vers));
+               logDiagnostic("Downloading from '%s'", url);
+               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)
+       {
+               auto md = getMetadata(packageId);
+               return getBestPackage(md, packageId, dep, pre_release);
+       }
+
+       private Json getMetadata(string packageId)
+       {
+               import std.xml;
+
+               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);
+               }
+
+               auto url = 
m_mavenUrl~NativePath(packageId~"/maven-metadata.xml");
+
+               logDebug("Downloading maven metadata for %s", packageId);
+               logDebug("Getting from %s", url);
+
+               string xmlData;
+               foreach(i; 0..3) {
+                       try {
+                               xmlData = cast(string)download(url);
+                               break;
+                       }
+                       catch (HTTPStatusException e)
+                       {
+                               if (e.status == 404) {
+                                       logDebug("Maven metadata %s not found 
at %s (404): %s", packageId, description, e.msg);
+                                       return Json(null);
+                               }
+                               else {
+                                       logDebug("Error getting maven metadata 
for %s at %s (attempt %s of 3): %s", packageId, description, i + 1, e.msg);
+                                       if (i == 2)
+                                               throw e;
+                                       continue;
+                               }
+                       }
+               }
+
+               auto json = Json(["name": Json(packageId), "versions": 
Json.emptyArray]);
+               auto xml = new DocumentParser(xmlData);
+
+               xml.onStartTag["versions"] = (ElementParser xml) {
+                        xml.onEndTag["version"] = (in Element e) {
+                               json["versions"] ~= serializeToJson(["name": 
packageId, "version": e.text]);
+                        };
+                        xml.parse();
+               };
+               xml.parse();
+               m_metadataCache[packageId] = CacheEntry(json, now);
+               return json;
+       }
+
+       SearchResult[] searchPackages(string query)
+       {
+               return [];
+       }
+}
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/packagesuppliers/package.d 
new/dub-1.10.0/source/dub/packagesuppliers/package.d
--- old/dub-1.9.0/source/dub/packagesuppliers/package.d 1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/source/dub/packagesuppliers/package.d        2018-07-03 
20:08:52.000000000 +0200
@@ -0,0 +1,10 @@
+module dub.packagesuppliers;
+
+/**
+       Contains (remote) package supplier interface and implementations.
+*/
+public import dub.packagesuppliers.fallback;
+public import dub.packagesuppliers.filesystem;
+public import dub.packagesuppliers.packagesupplier;
+public import dub.packagesuppliers.maven;
+public import dub.packagesuppliers.registry;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/dub-1.9.0/source/dub/packagesuppliers/packagesupplier.d 
new/dub-1.10.0/source/dub/packagesuppliers/packagesupplier.d
--- old/dub-1.9.0/source/dub/packagesuppliers/packagesupplier.d 1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/source/dub/packagesuppliers/packagesupplier.d        
2018-07-03 20:08:52.000000000 +0200
@@ -0,0 +1,82 @@
+module dub.packagesuppliers.packagesupplier;
+
+public import dub.dependency : Dependency, Version;
+public import dub.internal.vibecompat.core.file : NativePath;
+public import dub.internal.vibecompat.data.json : Json;
+
+/**
+       Base interface for remote package suppliers.
+
+       Provides functionality necessary to query package versions, recipes and
+       contents.
+*/
+interface PackageSupplier {
+       /// Represents a single package search result.
+       static struct SearchResult { string name, description, version_; }
+
+       /// Returns a human-readable representation of the package supplier.
+       @property string description();
+
+       /** Retrieves a list of all available versions(/branches) of a package.
+
+               Throws: Throws an exception if the package name is not known, 
or if
+                       an error occurred while retrieving the version list.
+       */
+       Version[] getVersions(string package_id);
+
+       /** Downloads a package and stores it as a ZIP file.
+
+               Params:
+                       path = Absolute path of the target ZIP file
+                       package_id = Name of the package to retrieve
+                       dep: Version constraint to match against
+                       pre_release: If true, matches the latest pre-release 
version.
+                               Otherwise prefers stable versions.
+       */
+       void fetchPackage(NativePath path, string package_id, Dependency dep, 
bool pre_release);
+
+       /** Retrieves only the recipe of a particular package.
+
+               Params:
+                       package_id = Name of the package of which to retrieve 
the recipe
+                       dep: Version constraint to match against
+                       pre_release: If true, matches the latest pre-release 
version.
+                               Otherwise prefers stable versions.
+       */
+       Json fetchPackageRecipe(string package_id, Dependency dep, bool 
pre_release);
+
+       /** Searches for packages matching the given search query term.
+
+               Search queries are currently a simple list of words separated by
+               white space. Results will get ordered from best match to worst.
+       */
+       SearchResult[] searchPackages(string query);
+}
+
+// TODO: Could drop the "best package" behavior and let retrievePackage/
+//       getPackageDescription take a Version instead of Dependency. But note
+//       this means that two requests to the registry are necessary to retrieve
+//       a package recipe instead of one (first get version list, then the
+//       package recipe)
+
+package Json getBestPackage(Json metadata, string packageId, Dependency dep, 
bool pre_release)
+{
+       import std.exception : enforce;
+       if (metadata.type == Json.Type.null_)
+               return metadata;
+       Json best = null;
+       Version bestver;
+       foreach (json; metadata["versions"]) {
+               auto cur = Version(json["version"].get!string);
+               if (!dep.matches(cur)) continue;
+               if (best == null) best = json;
+               else if (pre_release) {
+                       if (cur > bestver) best = json;
+               } else if (bestver.isPreRelease) {
+                       if (!cur.isPreRelease || cur > bestver) best = json;
+               } else if (!cur.isPreRelease && cur > bestver) best = json;
+               bestver = Version(cast(string)best["version"]);
+       }
+       enforce(best != null, "No package candidate found for "~packageId~" 
"~dep.toString());
+       return best;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/packagesuppliers/registry.d 
new/dub-1.10.0/source/dub/packagesuppliers/registry.d
--- old/dub-1.9.0/source/dub/packagesuppliers/registry.d        1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/source/dub/packagesuppliers/registry.d       2018-07-03 
20:08:52.000000000 +0200
@@ -0,0 +1,138 @@
+module dub.packagesuppliers.registry;
+
+import dub.packagesuppliers.packagesupplier;
+
+package enum PackagesPath = "packages";
+
+/**
+       Online registry based package supplier.
+
+       This package supplier connects to an online registry (e.g.
+       $(LINK https://code.dlang.org/)) to search for available packages.
+*/
+class RegistryPackageSupplier : PackageSupplier {
+       import dub.internal.utils : download, HTTPStatusException;
+       import dub.internal.vibecompat.core.log;
+       import dub.internal.vibecompat.data.json : parseJson, parseJsonString, 
serializeToJson;
+       import dub.internal.vibecompat.inet.url : URL;
+
+       import std.datetime : Clock, Duration, hours, SysTime, UTC;
+       private {
+               URL m_registryUrl;
+               struct CacheEntry { Json data; SysTime cacheTime; }
+               CacheEntry[string] m_metadataCache;
+               Duration m_maxCacheTime;
+       }
+
+       this(URL registry)
+       {
+               m_registryUrl = registry;
+               m_maxCacheTime = 24.hours();
+       }
+
+       override @property string description() { return "registry at 
"~m_registryUrl.toString(); }
+
+       Version[] getVersions(string package_id)
+       {
+               import std.algorithm.sorting : sort;
+               auto md = getMetadata(package_id);
+               if (md.type == Json.Type.null_)
+                       return null;
+               Version[] ret;
+               foreach (json; md["versions"]) {
+                       auto cur = Version(cast(string)json["version"]);
+                       ret ~= cur;
+               }
+               ret.sort();
+               return ret;
+       }
+
+       void fetchPackage(NativePath path, string packageId, Dependency dep, 
bool pre_release)
+       {
+               import std.array : replace;
+               import std.format : format;
+               auto md = getMetadata(packageId);
+               Json best = getBestPackage(md, packageId, dep, pre_release);
+               if (best.type == Json.Type.null_)
+                       return;
+               auto vers = best["version"].get!string;
+               auto url = m_registryUrl ~ 
NativePath(PackagesPath~"/"~packageId~"/"~vers~".zip");
+               logDiagnostic("Downloading from '%s'", url);
+               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)
+       {
+               auto md = getMetadata(packageId);
+               return getBestPackage(md, packageId, dep, pre_release);
+       }
+
+       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);
+               }
+
+               auto url = m_registryUrl ~ NativePath(PackagesPath ~ "/" ~ 
packageId ~ ".json");
+
+               logDebug("Downloading metadata for %s", packageId);
+               logDebug("Getting from %s", url);
+
+               string jsonData;
+               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)
+               foreach (ref v; json["versions"])
+                       v.remove("readme");
+               m_metadataCache[packageId] = CacheEntry(json, now);
+               return json;
+       }
+
+       SearchResult[] searchPackages(string query) {
+               import std.array : array;
+               import std.algorithm.iteration : map;
+               import std.uri : encodeComponent;
+               auto url = m_registryUrl;
+               url.localURI = "/api/packages/search?q="~encodeComponent(query);
+               string data;
+               data = cast(string)download(url);
+               return data.parseJson.opt!(Json[])
+                       .map!(j => SearchResult(j["name"].opt!string, 
j["description"].opt!string, j["version"].opt!string))
+                       .array;
+       }
+}
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/project.d 
new/dub-1.10.0/source/dub/project.d
--- old/dub-1.9.0/source/dub/project.d  2018-05-01 15:43:29.000000000 +0200
+++ new/dub-1.10.0/source/dub/project.d 2018-07-03 20:08:52.000000000 +0200
@@ -17,7 +17,6 @@
 import dub.internal.vibecompat.inet.url;
 import dub.package_;
 import dub.packagemanager;
-import dub.packagesupplier;
 import dub.generators.generator;
 
 import std.algorithm;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/source/dub/version_.d 
new/dub-1.10.0/source/dub/version_.d
--- old/dub-1.9.0/source/dub/version_.d 2018-05-01 15:43:29.000000000 +0200
+++ new/dub-1.10.0/source/dub/version_.d        2018-07-03 20:08:52.000000000 
+0200
@@ -1,2 +1,2 @@
 module dub.version_;
-enum dubVersion = "v1.9.0";
+enum dubVersion = "v1.10.0";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/test/common.sh 
new/dub-1.10.0/test/common.sh
--- old/dub-1.9.0/test/common.sh        2018-05-01 15:43:29.000000000 +0200
+++ new/dub-1.10.0/test/common.sh       2018-07-03 20:08:52.000000000 +0200
@@ -2,12 +2,17 @@
 
 set -ueEo pipefail
 
+function log() {
+    echo -e "\033[0;33m[INFO] $@\033[0m"
+    echo "[INFO]  $@" >> $(dirname "${BASH_SOURCE[0]}")/test.log
+}
+
 # lineno[, msg]
 function die() {
     local line=$1
     local msg=${2:-command failed}
     local supplemental=${3:-}
-    >&2 echo "[ERROR] $SOURCE_FILE:$1 $msg"
+    echo "[ERROR] $SOURCE_FILE:$1 $msg" | tee -a $(dirname 
"${BASH_SOURCE[0]}")/test.log | cat 1>&2
     if [ ! -z "$supplemental" ]; then
         echo "$supplemental" | >&2 sed 's|^|        |g'
     fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier/.gitignore 
new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier/.gitignore
--- old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier/.gitignore     
1970-01-01 01:00:00.000000000 +0100
+++ new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier/.gitignore    
2018-07-03 20:08:52.000000000 +0200
@@ -0,0 +1,8 @@
+.dub
+docs.json
+__dummy.html
+docs/
+*.exe
+*.o
+*.obj
+*.lst
Binary files 
old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier/maven/release/dubpackages/maven-dubpackage/1.0.5/maven-dubpackage-1.0.5.zip
 and 
new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier/maven/release/dubpackages/maven-dubpackage/1.0.5/maven-dubpackage-1.0.5.zip
 differ
Binary files 
old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier/maven/release/dubpackages/maven-dubpackage/1.0.6/maven-dubpackage-1.0.6.zip
 and 
new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier/maven/release/dubpackages/maven-dubpackage/1.0.6/maven-dubpackage-1.0.6.zip
 differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier/maven/release/dubpackages/maven-dubpackage/maven-metadata.xml
 
new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier/maven/release/dubpackages/maven-dubpackage/maven-metadata.xml
--- 
old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier/maven/release/dubpackages/maven-dubpackage/maven-metadata.xml
  1970-01-01 01:00:00.000000000 +0100
+++ 
new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier/maven/release/dubpackages/maven-dubpackage/maven-metadata.xml
 2018-07-03 20:08:52.000000000 +0200
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata modelVersion="1.1.0">
+  <groupId>dubpackages</groupId>
+  <artifactId>maven-dubpackage</artifactId>
+  <versioning>
+    <latest>1.0.6</latest>
+    <release>1.0.6</release>
+    <versions>
+      <version>1.0.5</version>
+      <version>1.0.6</version>
+    </versions>
+    <lastUpdated>20180317184845</lastUpdated>
+  </versioning>
+</metadata>
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier.sh 
new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier.sh
--- old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier.sh     1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier.sh    2018-07-03 
20:08:52.000000000 +0200
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+DIR=$(dirname "${BASH_SOURCE[0]}")
+
+. "$DIR"/common.sh
+
+PORT=$(($$ + 1024)) # PID + 1024
+
+dub remove maven-dubpackage --non-interactive --version=* 2>/dev/null || true
+
+"$DUB" build --single "$DIR"/test_registry.d
+"$DIR"/test_registry --folder="$DIR/issue1416-maven-repo-pkg-supplier" 
--port=$PORT &
+PID=$!
+sleep 1
+trap 'kill $PID 2>/dev/null || true' exit
+
+echo "Trying to download maven-dubpackage (1.0.5)"
+"$DUB" fetch maven-dubpackage --version=1.0.5 --skip-registry=all 
--registry=mvn+http://localhost:$PORT/maven/release/dubpackages
+
+if ! dub remove maven-dubpackage --non-interactive --version=1.0.5 
2>/dev/null; then
+    die 'DUB did not install package from maven registry.'
+fi
+
+echo "Trying to download maven-dubpackage (latest)"
+"$DUB" fetch maven-dubpackage --skip-registry=all 
--registry=mvn+http://localhost:$PORT/maven/release/dubpackages
+
+if ! dub remove maven-dubpackage --non-interactive --version=1.0.6 
2>/dev/null; then
+    die 'DUB did not install latest package from maven registry.'
+fi
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier.sh.min_frontend 
new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier.sh.min_frontend
--- old/dub-1.9.0/test/issue1416-maven-repo-pkg-supplier.sh.min_frontend        
1970-01-01 01:00:00.000000000 +0100
+++ new/dub-1.10.0/test/issue1416-maven-repo-pkg-supplier.sh.min_frontend       
2018-07-03 20:08:52.000000000 +0200
@@ -0,0 +1 @@
+2.076
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/dub-1.9.0/test/issue838-custom-cache-paths/cache/foo-1.0.0/foo/dub.sdl 
new/dub-1.10.0/test/issue838-custom-cache-paths/cache/foo-1.0.0/foo/dub.sdl
--- old/dub-1.9.0/test/issue838-custom-cache-paths/cache/foo-1.0.0/foo/dub.sdl  
1970-01-01 01:00:00.000000000 +0100
+++ new/dub-1.10.0/test/issue838-custom-cache-paths/cache/foo-1.0.0/foo/dub.sdl 
2018-07-03 20:08:52.000000000 +0200
@@ -0,0 +1,3 @@
+name "foo"
+version "1.0.0"
+targetType "sourceLibrary"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/test/issue838-custom-cache-paths/dub.sdl 
new/dub-1.10.0/test/issue838-custom-cache-paths/dub.sdl
--- old/dub-1.9.0/test/issue838-custom-cache-paths/dub.sdl      1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/test/issue838-custom-cache-paths/dub.sdl     2018-07-03 
20:08:52.000000000 +0200
@@ -0,0 +1,2 @@
+name "test"
+dependency "foo" version="1.0.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/dub-1.9.0/test/issue838-custom-cache-paths/source/app.d 
new/dub-1.10.0/test/issue838-custom-cache-paths/source/app.d
--- old/dub-1.9.0/test/issue838-custom-cache-paths/source/app.d 1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/test/issue838-custom-cache-paths/source/app.d        
2018-07-03 20:08:52.000000000 +0200
@@ -0,0 +1,3 @@
+void main()
+{
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/test/issue838-custom-cache-paths.sh 
new/dub-1.10.0/test/issue838-custom-cache-paths.sh
--- old/dub-1.9.0/test/issue838-custom-cache-paths.sh   1970-01-01 
01:00:00.000000000 +0100
+++ new/dub-1.10.0/test/issue838-custom-cache-paths.sh  2018-07-03 
20:08:52.000000000 +0200
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+. $(dirname "${BASH_SOURCE[0]}")/common.sh
+
+CONFIG_FILE=$CURR_DIR/../etc/dub/settings.json
+
+mkdir $CURR_DIR/../etc && mkdir $CURR_DIR/../etc/dub || true
+echo "{\"customCachePaths\": 
[\"$CURR_DIR/issue838-custom-cache-paths/cache\"]}" > $CONFIG_FILE
+
+trap "rm $CONFIG_FILE" EXIT
+
+if ! { $DUB build --root "$CURR_DIR/issue838-custom-cache-paths" 
--skip-registry=all; }; then
+       die $LINENO 'Failed to build package with custom cache path for 
dependencies.'
+fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dub-1.9.0/test/run-unittest.sh 
new/dub-1.10.0/test/run-unittest.sh
--- old/dub-1.9.0/test/run-unittest.sh  2018-05-01 15:43:29.000000000 +0200
+++ new/dub-1.10.0/test/run-unittest.sh 2018-07-03 20:08:52.000000000 +0200
@@ -3,12 +3,16 @@
 
 . $(dirname "${BASH_SOURCE[0]}")/common.sh
 
+> $(dirname "${BASH_SOURCE[0]}")/test.log
+
 function log() {
     echo -e "\033[0;33m[INFO] $@\033[0m"
+    echo "[INFO]  $@" >> $(dirname "${BASH_SOURCE[0]}")/test.log
 }
 
 function logError() {
     echo -e 1>&2 "\033[0;31m[ERROR] $@\033[0m"
+    echo "[ERROR] $@" >> $(dirname "${BASH_SOURCE[0]}")/test.log
     any_errors=1
 }
 
@@ -33,7 +37,10 @@
 CURR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
 FRONTEND="${FRONTEND:-}"
 
+if [ "$#" -gt 0 ]; then FILTER=$1; else FILTER=".*"; fi
+
 for script in $(ls $CURR_DIR/*.sh); do
+    if [[ ! "$script" =~ $FILTER ]]; then continue; fi
     if [ "$script" = "$(readlink -f ${BASH_SOURCE[0]})" ] || [ "$(basename 
$script)" = "common.sh" ]; then continue; fi
     if [ -e $script.min_frontend ] && [ ! -z "$FRONTEND" ] && [ ${FRONTEND} \< 
$(cat $script.min_frontend) ]; then continue; fi
     log "Running $script..."
@@ -41,6 +48,7 @@
 done
 
 for pack in $(ls -d $CURR_DIR/*/); do
+    if [[ ! "$pack" =~ $FILTER ]]; then continue; fi
     if [ -e $pack/.min_frontend ] && [ ! -z "$FRONTEND" -a "$FRONTEND" \< 
$(cat $pack/.min_frontend) ]; then continue; fi
 
     # First we build the packages
@@ -70,4 +78,8 @@
     fi
 done
 
+echo
+echo 'Testing summary:'
+cat $(dirname "${BASH_SOURCE[0]}")/test.log
+
 exit ${any_errors:-0}


Reply via email to