diff --git a/changelog/file-system-supplier.dd b/changelog/file-system-supplier.dd new file mode 100644 index 0000000..3f0c95d --- /dev/null +++ b/changelog/file-system-supplier.dd @@ -0,0 +1,7 @@ +File system supplier enabled + +Existing file system supplier is enabled for usage. +It searches a certain directory for files with names of +the form "[package name]-[version].zip". + +Example `dub fetch mypackage --registry=file:///etc/dub/packages/` \ No newline at end of file diff --git a/source/dub/dub.d b/source/dub/dub.d index f6e3682..92ca4c0 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -93,12 +93,14 @@ */ PackageSupplier getRegistryPackageSupplier(string url) { - switch (url.startsWith("dub+", "mvn+")) + switch (url.startsWith("dub+", "mvn+", "file://")) { case 1: return new RegistryPackageSupplier(URL(url[4..$])); case 2: return new MavenRegistryPackageSupplier(URL(url[4..$])); + case 3: + return new FileSystemPackageSupplier(NativePath(url[7..$])); default: return new RegistryPackageSupplier(URL(url)); } @@ -114,6 +116,9 @@ auto mavenRegistryPackageSupplier = getRegistryPackageSupplier("mvn+http://localhost:8040/maven/libs-release/dubpackages"); assert(mavenRegistryPackageSupplier.description.canFind(" http://localhost:8040/maven/libs-release/dubpackages")); + + auto fileSystemPackageSupplier = getRegistryPackageSupplier("file:///etc/dubpackages"); + assert(fileSystemPackageSupplier.description.canFind(" " ~ NativePath("/etc/dubpackages").toNativeString)); } /** Provides a high-level entry point for DUB's functionality. diff --git a/source/dub/internal/utils.d b/source/dub/internal/utils.d index 42ecdf1..6466e5b 100644 --- a/source/dub/internal/utils.d +++ b/source/dub/internal/utils.d @@ -16,7 +16,7 @@ import core.time : Duration; import std.algorithm : canFind, startsWith; -import std.array : appender; +import std.array : appender, array; import std.conv : to; import std.exception : enforce; import std.file; @@ -130,6 +130,39 @@ return parseJsonString(text, file.toNativeString()); } +/** + Read package info file content from archive. + File needs to be in root folder or in first + sub folder. + + Params: + zip = path to archive file + fileName = Package file name + Returns: + package file content. +*/ +string packageInfoFileFromZip(NativePath zip, out string fileName) { + import std.zip : ZipArchive, ArchiveMember; + import dub.package_ : packageInfoFiles; + + auto f = openFile(zip, FileMode.read); + ubyte[] b = new ubyte[cast(size_t)f.size]; + f.rawRead(b); + f.close(); + auto archive = new ZipArchive(b); + alias PSegment = typeof (NativePath.init.head); + foreach (ArchiveMember am; archive.directory) { + auto path = NativePath(am.name).bySegment.array; + foreach (fil; packageInfoFiles) { + if ((path.length == 1 && path[0] == fil.filename) || (path.length == 2 && path[$-1].toString == fil.filename)) { + fileName = fil.filename; + return stripUTF8Bom(cast(string) archive.expand(archive.directory[am.name])); + } + } + } + throw new Exception("No package descriptor found"); +} + Json jsonFromZip(NativePath zip, string filename) { import std.zip : ZipArchive; auto f = openFile(zip, FileMode.read); diff --git a/source/dub/packagesuppliers/filesystem.d b/source/dub/packagesuppliers/filesystem.d index 323e47b..61b125c 100644 --- a/source/dub/packagesuppliers/filesystem.d +++ b/source/dub/packagesuppliers/filesystem.d @@ -50,9 +50,19 @@ 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"); + import std.array : split; + import std.path : stripExtension; + import dub.internal.utils : packageInfoFileFromZip; + import dub.recipe.io : parsePackageRecipe; + import dub.recipe.json : toJson; + + auto filePath = bestPackageFile(packageId, dep, pre_release); + string packageFileName; + string packageFileContent = packageInfoFileFromZip(filePath, packageFileName); + auto recipe = parsePackageRecipe(packageFileContent, packageFileName); + Json json = toJson(recipe); + json["version"] = filePath.toNativeString().split("-")[$-1].stripExtension(); + return json; } SearchResult[] searchPackages(string query) diff --git a/test/issue1401-file-system-pkg-supplier/.no_build b/test/issue1401-file-system-pkg-supplier/.no_build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1401-file-system-pkg-supplier/.no_build diff --git a/test/issue1401-file-system-pkg-supplier/fs-json-dubpackage-1.0.7.zip b/test/issue1401-file-system-pkg-supplier/fs-json-dubpackage-1.0.7.zip new file mode 100644 index 0000000..1b9915e --- /dev/null +++ b/test/issue1401-file-system-pkg-supplier/fs-json-dubpackage-1.0.7.zip Binary files differ diff --git a/test/issue1401-file-system-pkg-supplier/fs-sdl-dubpackage-1.0.5.zip b/test/issue1401-file-system-pkg-supplier/fs-sdl-dubpackage-1.0.5.zip new file mode 100644 index 0000000..6e58d2f --- /dev/null +++ b/test/issue1401-file-system-pkg-supplier/fs-sdl-dubpackage-1.0.5.zip Binary files differ diff --git a/test/issue1401-file-system-pkg-supplier/fs-sdl-dubpackage-1.0.6.zip b/test/issue1401-file-system-pkg-supplier/fs-sdl-dubpackage-1.0.6.zip new file mode 100644 index 0000000..76f3dcf --- /dev/null +++ b/test/issue1401-file-system-pkg-supplier/fs-sdl-dubpackage-1.0.6.zip Binary files differ diff --git a/test/issue1401-filesystem-supplier.sh b/test/issue1401-filesystem-supplier.sh new file mode 100755 index 0000000..1367fc6 --- /dev/null +++ b/test/issue1401-filesystem-supplier.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +DIR=$(dirname "${BASH_SOURCE[0]}") + +. "$DIR"/common.sh + +dub remove fs-json-dubpackage --non-interactive --version=* 2>/dev/null || true +dub remove fs-sdl-dubpackage --non-interactive --version=* 2>/dev/null || true + +echo "Trying to get fs-sdl-dubpackage (1.0.5)" +"$DUB" fetch fs-sdl-dubpackage --version=1.0.5 --skip-registry=all --registry=file://"$DIR"/issue1401-file-system-pkg-supplier + +if ! dub remove fs-sdl-dubpackage --non-interactive --version=1.0.5 2>/dev/null; then + die 'DUB did not install package from file system.' +fi + +echo "Trying to get fs-sdl-dubpackage (latest)" +"$DUB" fetch fs-sdl-dubpackage --skip-registry=all --registry=file://"$DIR"/issue1401-file-system-pkg-supplier + +if ! dub remove fs-sdl-dubpackage --non-interactive --version=1.0.6 2>/dev/null; then + die 'DUB did not install latest package from file system.' +fi + +echo "Trying to get fs-json-dubpackage (1.0.7)" +"$DUB" fetch fs-json-dubpackage --version=1.0.7 --skip-registry=all --registry=file://"$DIR"/issue1401-file-system-pkg-supplier + +if ! dub remove fs-json-dubpackage --non-interactive --version=1.0.7 2>/dev/null; then + die 'DUB did not install package from file system.' +fi