diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 9534134..2edc4d9 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -3119,7 +3119,7 @@ { Dependency dep; const parts = UserPackageDesc.fromString(depspec); - const depname = parts.name; + const depname = PackageName(parts.name); if (parts.range == VersionRange.Any) { try { diff --git a/source/dub/dub.d b/source/dub/dub.d index e76f670..951d5db 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -645,7 +645,7 @@ if (m_packageManager.getPackage(p, dep.version_)) continue; foreach (ps; m_packageSuppliers) { try { - auto versions = ps.getVersions(p); + auto versions = ps.getVersions(name); if (versions.canFind!(v => dep.matches(v, VersionMatchMode.strict))) continue next_pack; } catch (Exception e) { @@ -1290,12 +1290,11 @@ See_also: `getLatestVersion` */ - Version[] listPackageVersions(string name) + Version[] listPackageVersions(in PackageName name) { Version[] versions; - auto basePackageName = PackageName(name).main; foreach (ps; this.m_packageSuppliers) { - try versions ~= ps.getVersions(basePackageName); + try versions ~= ps.getVersions(name); catch (Exception e) { logWarn("Failed to get versions for package %s on provider %s: %s", name, ps.description, e.msg); } @@ -1303,6 +1302,13 @@ return versions.sort().uniq.array; } + deprecated("Use `listPackageVersions(PackageName)`") + Version[] listPackageVersions(string name) + { + const n = PackageName(name); + return this.listPackageVersions(n); + } + /** Returns the latest available version for a particular package. This function returns the latest numbered version of a package. If no @@ -1310,21 +1316,30 @@ preferring "~master". Params: - package_name = The name of the package in question. + name = The name of the package in question. prefer_stable = If set to `true` (the default), returns the latest stable version, even if there are newer pre-release versions. See_also: `listPackageVersions` */ - Version getLatestVersion(string package_name, bool prefer_stable = true) + Version getLatestVersion(in PackageName name, bool prefer_stable = true) { - auto vers = listPackageVersions(package_name); - enforce(!vers.empty, "Failed to find any valid versions for a package name of '"~package_name~"'."); + auto vers = this.listPackageVersions(name); + enforce(!vers.empty, + "Failed to find any valid versions for a package name of '%s'." + .format(name)); auto final_versions = vers.filter!(v => !v.isBranch && !v.isPreRelease).array; if (prefer_stable && final_versions.length) return final_versions[$-1]; else return vers[$-1]; } + deprecated("Use `getLatestVersion(PackageName, bool)`") + Version getLatestVersion(string name, bool prefer_stable = true) + { + const n = PackageName(name); + return this.getLatestVersion(n, prefer_stable); + } + /** Initializes a directory with a package skeleton. Params: @@ -1348,8 +1363,9 @@ VersionRange[string] depVers; string[] notFound; // keep track of any failed packages in here foreach (dep; deps) { + const name = PackageName(dep); try { - Version ver = getLatestVersion(dep); + Version ver = this.getLatestVersion(name); if (ver.isBranch()) depVers[dep] = VersionRange(ver); else @@ -1762,7 +1778,7 @@ foreach (ps; m_dub.m_packageSuppliers) { try { - auto vers = ps.getVersions(pack); + auto vers = ps.getVersions(name); vers.reverse(); if (!vers.length) { logDiagnostic("No versions for %s for %s", pack, ps.description); diff --git a/source/dub/packagesuppliers/fallback.d b/source/dub/packagesuppliers/fallback.d index b9235c7..5145173 100644 --- a/source/dub/packagesuppliers/fallback.d +++ b/source/dub/packagesuppliers/fallback.d @@ -28,9 +28,9 @@ } // 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, in VersionRange dep, bool pre_release); - abstract override Json fetchPackageRecipe(string package_id, in VersionRange dep, bool pre_release); + abstract override Version[] getVersions(in PackageName name); + abstract override void fetchPackage(in NativePath path, in PackageName name, in VersionRange dep, bool pre_release); + abstract override Json fetchPackageRecipe(in PackageName name, in VersionRange dep, bool pre_release); abstract override SearchResult[] searchPackages(string query); } diff --git a/source/dub/packagesuppliers/filesystem.d b/source/dub/packagesuppliers/filesystem.d index 268ba4d..299b064 100644 --- a/source/dub/packagesuppliers/filesystem.d +++ b/source/dub/packagesuppliers/filesystem.d @@ -21,18 +21,19 @@ override @property string description() { return "file repository at "~m_path.toNativeString(); } - Version[] getVersions(string package_id) + Version[] getVersions(in PackageName name) { import std.algorithm.sorting : sort; import std.file : dirEntries, DirEntry, SpanMode; import std.conv : to; import dub.semver : isValidVersion; Version[] ret; - foreach (DirEntry d; dirEntries(m_path.toNativeString(), package_id~"*.zip", SpanMode.shallow)) { + const zipFileGlob = name.main.toString() ~ "*.zip"; + foreach (DirEntry d; dirEntries(m_path.toNativeString(), zipFileGlob, SpanMode.shallow)) { NativePath p = NativePath(d.name); - auto vers = p.head.name[package_id.length+1..$-4]; + auto vers = p.head.name[name.main.length+1..$-4]; if (!isValidVersion(vers)) { - logDebug("Ignoring entry '%s' because it isn't a version of package '%s'", p, package_id); + logDebug("Ignoring entry '%s' because it isn't a version of package '%s'", p, name.main); continue; } logDebug("Entry: %s", p); @@ -43,17 +44,19 @@ return ret; } - void fetchPackage(NativePath path, string packageId, in VersionRange dep, bool pre_release) + override void fetchPackage(in NativePath path, in PackageName name, + in VersionRange dep, bool pre_release) { import dub.internal.vibecompat.core.file : copyFile, existsFile; enforce(path.absolute); - logInfo("Storing package '%s', version requirements: %s", packageId, dep); - auto filename = bestPackageFile(packageId, dep, pre_release); + logInfo("Storing package '%s', version requirements: %s", name.main, dep); + auto filename = bestPackageFile(name, dep, pre_release); enforce(existsFile(filename)); copyFile(filename, path); } - Json fetchPackageRecipe(string packageId, in VersionRange dep, bool pre_release) + override Json fetchPackageRecipe(in PackageName name, in VersionRange dep, + bool pre_release) { import std.array : split; import std.path : stripExtension; @@ -62,15 +65,16 @@ import dub.recipe.io : parsePackageRecipe; import dub.recipe.json : toJson; - auto filePath = bestPackageFile(packageId, dep, pre_release); + auto filePath = bestPackageFile(name, dep, pre_release); string packageFileName; string packageFileContent = packageInfoFileFromZip(filePath, packageFileName); auto recipe = parsePackageRecipe(packageFileContent, packageFileName); Json json = toJson(recipe); auto basename = filePath.head.name; enforce(basename.endsWith(".zip"), "Malformed package filename: " ~ filePath.toNativeString); - enforce(basename.startsWith(packageId), "Malformed package filename: " ~ filePath.toNativeString); - json["version"] = basename[packageId.length + 1 .. $-4]; + enforce(basename.startsWith(name.main.toString()), + "Malformed package filename: " ~ filePath.toNativeString); + json["version"] = basename[name.main.toString().length + 1 .. $-4]; return json; } @@ -80,16 +84,17 @@ return null; } - private NativePath bestPackageFile(string packageId, in VersionRange dep, bool pre_release) + private NativePath bestPackageFile(in PackageName name, in VersionRange 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"); + return m_path ~ "%s-%s.zip".format(name.main, ver); } - auto versions = getVersions(packageId).filter!(v => dep.matches(v)).array; - enforce(versions.length > 0, format("No package %s found matching %s", packageId, dep)); + auto versions = getVersions(name).filter!(v => dep.matches(v)).array; + enforce(versions.length > 0, format("No package %s found matching %s", name.main, dep)); foreach_reverse (ver; versions) { if (pre_release || !ver.isPreRelease) return toPath(ver); diff --git a/source/dub/packagesuppliers/maven.d b/source/dub/packagesuppliers/maven.d index ecb29b1..cc4d154 100644 --- a/source/dub/packagesuppliers/maven.d +++ b/source/dub/packagesuppliers/maven.d @@ -20,7 +20,7 @@ enum httpTimeout = 16; URL m_mavenUrl; struct CacheEntry { Json data; SysTime cacheTime; } - CacheEntry[string] m_metadataCache; + CacheEntry[PackageName] m_metadataCache; Duration m_maxCacheTime; } @@ -32,10 +32,10 @@ override @property string description() { return "maven repository at "~m_mavenUrl.toString(); } - Version[] getVersions(string package_id) + override Version[] getVersions(in PackageName name) { import std.algorithm.sorting : sort; - auto md = getMetadata(package_id); + auto md = getMetadata(name.main); if (md.type == Json.Type.null_) return null; Version[] ret; @@ -47,15 +47,17 @@ return ret; } - void fetchPackage(NativePath path, string packageId, in VersionRange dep, bool pre_release) + override void fetchPackage(in NativePath path, in PackageName name, + in VersionRange dep, bool pre_release) { import std.format : format; - auto md = getMetadata(packageId); - Json best = getBestPackage(md, packageId, dep, pre_release); + auto md = getMetadata(name.main); + Json best = getBestPackage(md, name.main, 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)); + auto url = m_mavenUrl ~ NativePath( + "%s/%s/%s-%s.zip".format(name.main, vers, name.main, vers)); try { retryDownload(url, path, 3, httpTimeout); @@ -63,58 +65,59 @@ } catch(HTTPStatusException e) { if (e.status == 404) throw e; - else logDebug("Failed to download package %s from %s", packageId, url); + else logDebug("Failed to download package %s from %s", name.main, url); } catch(Exception e) { - logDebug("Failed to download package %s from %s", packageId, url); + logDebug("Failed to download package %s from %s", name.main, url); } - throw new Exception("Failed to download package %s from %s".format(packageId, url)); + throw new Exception("Failed to download package %s from %s".format(name.main, url)); } - Json fetchPackageRecipe(string packageId, in VersionRange dep, bool pre_release) + override Json fetchPackageRecipe(in PackageName name, in VersionRange dep, + bool pre_release) { - auto md = getMetadata(packageId); - return getBestPackage(md, packageId, dep, pre_release); + auto md = getMetadata(name); + return getBestPackage(md, name, dep, pre_release); } - private Json getMetadata(string packageId) + private Json getMetadata(in PackageName name) { import dub.internal.undead.xml; auto now = Clock.currTime(UTC()); - if (auto pentry = packageId in m_metadataCache) { + if (auto pentry = name.main in m_metadataCache) { if (pentry.cacheTime + m_maxCacheTime > now) return pentry.data; - m_metadataCache.remove(packageId); + m_metadataCache.remove(name.main); } - auto url = m_mavenUrl~NativePath(packageId~"/maven-metadata.xml"); + auto url = m_mavenUrl ~ NativePath(name.main.toString() ~ "/maven-metadata.xml"); - logDebug("Downloading maven metadata for %s", packageId); + logDebug("Downloading maven metadata for %s", name.main); string xmlData; try xmlData = cast(string)retryDownload(url, 3, httpTimeout); catch(HTTPStatusException e) { if (e.status == 404) { - logDebug("Maven metadata %s not found at %s (404): %s", packageId, description, e.msg); + logDebug("Maven metadata %s not found at %s (404): %s", name.main, description, e.msg); return Json(null); } else throw e; } - auto json = Json(["name": Json(packageId), "versions": Json.emptyArray]); + auto json = Json(["name": Json(name.main), "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]); + json["versions"] ~= serializeToJson(["name": name.main, "version": e.text]); }; xml.parse(); }; xml.parse(); - m_metadataCache[packageId] = CacheEntry(json, now); + m_metadataCache[name.main] = CacheEntry(json, now); return json; } @@ -122,10 +125,10 @@ { // Only exact search is supported // This enables retrieval of dub packages on dub run - auto md = getMetadata(query); + auto md = getMetadata(PackageName(query)); if (md.type == Json.Type.null_) return null; - auto json = getBestPackage(md, query, VersionRange.Any, true); + auto json = getBestPackage(md, PackageName(query), VersionRange.Any, true); return [SearchResult(json["name"].opt!string, "", json["version"].opt!string)]; } } diff --git a/source/dub/packagesuppliers/packagesupplier.d b/source/dub/packagesuppliers/packagesupplier.d index 71f8b8d..63d83b7 100644 --- a/source/dub/packagesuppliers/packagesupplier.d +++ b/source/dub/packagesuppliers/packagesupplier.d @@ -1,6 +1,6 @@ module dub.packagesuppliers.packagesupplier; -public import dub.dependency : Dependency, Version, VersionRange; +public import dub.dependency : PackageName, Dependency, Version, VersionRange; import dub.dependency : visit; public import dub.internal.vibecompat.core.file : NativePath; public import dub.internal.vibecompat.data.json : Json; @@ -23,25 +23,33 @@ 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); + deprecated("Use `getVersions(PackageName)` instead") + final Version[] getVersions(string name) + { + return this.getVersions(PackageName(name)); + } + + Version[] getVersions(in PackageName name); + /** 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 + name = 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, in VersionRange dep, bool pre_release); + void fetchPackage(in NativePath path, in PackageName name, + in VersionRange dep, bool pre_release); - deprecated("Use the overload that accepts a `VersionRange` instead") - final void fetchPackage(NativePath path, string package_id, Dependency dep, bool pre_release) + deprecated("Use `fetchPackage(NativePath, PackageName, VersionRange, bool)` instead") + final void fetchPackage(NativePath path, string name, Dependency dep, bool pre_release) { return dep.visit!( (const VersionRange rng) { - return this.fetchPackage(path, package_id, rng, pre_release); + return this.fetchPackage(path, PackageName(name), rng, pre_release); }, (any) { assert(0, "Trying to fetch a package with a non-version dependency: " ~ any.toString()); }, @@ -56,14 +64,14 @@ pre_release = If true, matches the latest pre-release version. Otherwise prefers stable versions. */ - Json fetchPackageRecipe(string package_id, in VersionRange dep, bool pre_release); + Json fetchPackageRecipe(in PackageName name, in VersionRange dep, bool pre_release); - deprecated("Use the overload that accepts a `VersionRange` instead") - final Json fetchPackageRecipe(string package_id, Dependency dep, bool pre_release) + deprecated("Use `fetchPackageRecipe(PackageName, VersionRange, bool)` instead") + final Json fetchPackageRecipe(string name, Dependency dep, bool pre_release) { return dep.visit!( (const VersionRange rng) { - return this.fetchPackageRecipe(package_id, rng, pre_release); + return this.fetchPackageRecipe(PackageName(name), rng, pre_release); }, (any) { return Json.init; }, @@ -84,9 +92,12 @@ // a package recipe instead of one (first get version list, then the // package recipe) -package Json getBestPackage(Json metadata, string packageId, in VersionRange dep, bool pre_release) +package Json getBestPackage(Json metadata, in PackageName name, + in VersionRange dep, bool pre_release) { import std.exception : enforce; + import std.format : format; + if (metadata.type == Json.Type.null_) return metadata; Json best = null; @@ -102,6 +113,7 @@ } 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()); + enforce(best != null, + "No package candidate found for %s@%s".format(name.main, dep)); return best; } diff --git a/source/dub/packagesuppliers/registry.d b/source/dub/packagesuppliers/registry.d index b509970..174c9fc 100644 --- a/source/dub/packagesuppliers/registry.d +++ b/source/dub/packagesuppliers/registry.d @@ -22,7 +22,7 @@ private { URL m_registryUrl; struct CacheEntry { Json data; SysTime cacheTime; } - CacheEntry[string] m_metadataCache; + CacheEntry[PackageName] m_metadataCache; Duration m_maxCacheTime; } @@ -34,10 +34,10 @@ override @property string description() { return "registry at "~m_registryUrl.toString(); } - Version[] getVersions(string package_id) + override Version[] getVersions(in PackageName name) { import std.algorithm.sorting : sort; - auto md = getMetadata(package_id); + auto md = getMetadata(name); if (md.type == Json.Type.null_) return null; Version[] ret; @@ -49,26 +49,28 @@ return ret; } - auto genPackageDownloadUrl(string packageId, in VersionRange dep, bool pre_release) + auto genPackageDownloadUrl(in PackageName name, in VersionRange dep, bool pre_release) { import std.array : replace; import std.format : format; import std.typecons : Nullable; - auto md = getMetadata(packageId); - Json best = getBestPackage(md, packageId, dep, pre_release); + auto md = getMetadata(name); + Json best = getBestPackage(md, name, dep, pre_release); Nullable!URL ret; if (best.type != Json.Type.null_) { auto vers = best["version"].get!string; - ret = m_registryUrl ~ NativePath(PackagesPath~"/"~packageId~"/"~vers~".zip"); + ret = m_registryUrl ~ NativePath(PackagesPath~"/"~name.main~"/"~vers~".zip"); } return ret; } - void fetchPackage(NativePath path, string packageId, in VersionRange dep, bool pre_release) + override void fetchPackage(in NativePath path, in PackageName name, + in VersionRange dep, bool pre_release) { import std.format : format; - auto url = genPackageDownloadUrl(packageId, dep, pre_release); + + auto url = genPackageDownloadUrl(name, dep, pre_release); if(url.isNull) return; try { @@ -77,35 +79,36 @@ } catch(HTTPStatusException e) { if (e.status == 404) throw e; - else logDebug("Failed to download package %s from %s", packageId, url); + else logDebug("Failed to download package %s from %s", name.main, url); } catch(Exception e) { - logDebug("Failed to download package %s from %s", packageId, url); + logDebug("Failed to download package %s from %s", name.main, url); } - throw new Exception("Failed to download package %s from %s".format(packageId, url)); + throw new Exception("Failed to download package %s from %s".format(name.main, url)); } - Json fetchPackageRecipe(string packageId, in VersionRange dep, bool pre_release) + override Json fetchPackageRecipe(in PackageName name, in VersionRange dep, + bool pre_release) { - auto md = getMetadata(packageId); - return getBestPackage(md, packageId, dep, pre_release); + auto md = getMetadata(name); + return getBestPackage(md, name, dep, pre_release); } - private Json getMetadata(string packageId) + private Json getMetadata(in PackageName name) { auto now = Clock.currTime(UTC()); - if (auto pentry = packageId in m_metadataCache) { + if (auto pentry = name.main in m_metadataCache) { if (pentry.cacheTime + m_maxCacheTime > now) return pentry.data; - m_metadataCache.remove(packageId); + m_metadataCache.remove(name.main); } auto url = m_registryUrl ~ NativePath("api/packages/infos"); url.queryString = "packages=" ~ - encodeComponent(`["` ~ packageId ~ `"]`) ~ "&include_dependencies=true&minimize=true"; + encodeComponent(`["` ~ name.main ~ `"]`) ~ "&include_dependencies=true&minimize=true"; - logDebug("Downloading metadata for %s", packageId); + logDebug("Downloading metadata for %s", name.main); string jsonData; jsonData = cast(string)retryDownload(url); @@ -114,9 +117,9 @@ foreach (pkg, info; json.get!(Json[string])) { logDebug("adding %s to metadata cache", pkg); - m_metadataCache[pkg] = CacheEntry(info, now); + m_metadataCache[PackageName(pkg)] = CacheEntry(info, now); } - return json[packageId]; + return json[name.main]; } SearchResult[] searchPackages(string query) { diff --git a/source/dub/test/base.d b/source/dub/test/base.d index eaebda2..a268eca 100644 --- a/source/dub/test/base.d +++ b/source/dub/test/base.d @@ -51,6 +51,7 @@ import std.array; public import std.algorithm; +import std.format; import dub.data.settings; public import dub.dependency; @@ -385,7 +386,7 @@ public class MockPackageSupplier : PackageSupplier { /// Mapping of package name to packages, ordered by `Version` - protected Package[][string] pkgs; + protected Package[][PackageName] pkgs; /// URL this was instantiated with protected string url; @@ -403,27 +404,28 @@ } /// - public override Version[] getVersions(string package_id) + public override Version[] getVersions(in PackageName name) { - if (auto ppkgs = package_id in this.pkgs) + if (auto ppkgs = name.main in this.pkgs) return (*ppkgs).map!(pkg => pkg.version_).array; return null; } /// - public override void fetchPackage( - NativePath path, string package_id, in VersionRange dep, bool pre_release) + public override void fetchPackage(in NativePath path, in PackageName name, + in VersionRange dep, bool pre_release) { - assert(0, this.url ~ " - fetchPackage not implemented for: " ~ package_id); + assert(0, "%s - fetchPackage not implemented for: %s" + .format(this.url, name.main)); } /// - public override Json fetchPackageRecipe( - string package_id, in VersionRange dep, bool pre_release) + public override Json fetchPackageRecipe(in PackageName name, + in VersionRange dep, bool pre_release) { import dub.recipe.json; - if (auto ppkgs = package_id in this.pkgs) + if (auto ppkgs = name.main in this.pkgs) foreach_reverse (pkg; *ppkgs) if ((!pkg.version_.isPreRelease || pre_release) && dep.matches(pkg.version_))