- module dub.packagesuppliers.filesystem;
-
- import dub.internal.logging;
- import dub.internal.vibecompat.inet.path;
- import dub.packagesuppliers.packagesupplier;
-
- import std.exception : enforce;
-
- /**
- 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(in PackageName name)
- {
- import std.algorithm.sorting : sort;
- import std.file : dirEntries, DirEntry, SpanMode;
- import std.conv : to;
- import dub.semver : isValidVersion;
- Version[] ret;
- 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[name.main.toString().length+1..$-4];
- if (!isValidVersion(vers)) {
- logDebug("Ignoring entry '%s' because it isn't a version of package '%s'", p, name.main);
- continue;
- }
- logDebug("Entry: %s", p);
- logDebug("Version: %s", vers);
- ret ~= Version(vers);
- }
- ret.sort();
- return ret;
- }
-
- override ubyte[] fetchPackage(in PackageName name,
- in VersionRange dep, bool pre_release)
- {
- import dub.internal.vibecompat.core.file : readFile, existsFile;
- logInfo("Storing package '%s', version requirements: %s", name.main, dep);
- auto filename = bestPackageFile(name, dep, pre_release);
- enforce(existsFile(filename));
- return readFile(filename);
- }
-
- override Json fetchPackageRecipe(in PackageName name, in VersionRange dep,
- bool pre_release)
- {
- import std.array : split;
- import std.path : stripExtension;
- import std.algorithm : startsWith, endsWith;
- import dub.internal.utils : packageInfoFileFromZip;
- import dub.recipe.io : parsePackageRecipe;
- import dub.recipe.json : toJson;
-
- 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(name.main.toString()),
- "Malformed package filename: " ~ filePath.toNativeString);
- json["version"] = basename[name.main.toString().length + 1 .. $-4];
- return json;
- }
-
- SearchResult[] searchPackages(string query)
- {
- // TODO!
- return null;
- }
-
- 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 ~ "%s-%s.zip".format(name.main, ver);
- }
- 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);
- }
- return toPath(versions[$-1]);
- }
- }