diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 2ede07d..433ad7b 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -62,6 +62,7 @@ new AddLocalCommand, new RemoveLocalCommand, new ListCommand, + new SearchCommand, new ListInstalledCommand, new AddOverrideCommand, new RemoveOverrideCommand, @@ -1273,6 +1274,42 @@ } } +class SearchCommand : Command { + this() + { + this.name = "search"; + this.argumentsPattern = ""; + this.description = "Seach for available packages."; + this.helpText = [ + "Search all specified DUB registries for packages matching query." + ]; + } + override void prepare(scope CommandArgs args) {} + override int execute(Dub dub, string[] free_args, string[] app_args) + { + enforce(free_args.length == 1, "Expected one argument."); + auto res = dub.searchPackages(free_args[0]); + if (res.empty) + { + logError("No matches found."); + return 1; + } + auto justify = res + .map!((descNmatches) => descNmatches[1]) + .joiner + .map!(m => m.name.length + m.version_.length) + .reduce!max + " ()".length; + justify += (~justify & 3) + 1; // round to next multiple of 4 + foreach (desc, matches; res) + { + logInfo("==== %s ====", desc); + foreach (m; matches) + logInfo("%s%s", leftJustify(m.name ~ " (" ~ m.version_ ~ ")", justify), m.description); + } + return 0; + } +} + /******************************************************************************/ /* OVERRIDES */ @@ -1754,4 +1791,3 @@ { logWarn("The '%s' Command was renamed to '%s'. Please update your scripts.", prev, curr); } - diff --git a/source/dub/dub.d b/source/dub/dub.d index d06f888..7741e6a 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -683,6 +683,12 @@ m_packageManager.removeSearchPath(makeAbsolute(path), system ? LocalPackageType.system : LocalPackageType.user); } + auto searchPackages(string query) + { + return m_packageSuppliers.map!(ps => tuple(ps.description, ps.searchPackages(query))) + .filter!(t => t[1].length); + } + void createEmptyPackage(Path path, string[] deps, string type, PackageFormat format = PackageFormat.sdl) { if (!path.absolute) path = m_rootPath ~ path; diff --git a/source/dub/packagesupplier.d b/source/dub/packagesupplier.d index 782fd65..64096c3 100644 --- a/source/dub/packagesupplier.d +++ b/source/dub/packagesupplier.d @@ -41,6 +41,9 @@ /// perform cache operation void cacheOp(Path cacheDir, CacheOp op); + + static struct SearchResult { string name, description, version_; } + SearchResult[] searchPackages(string query); } /// operations on package supplier cache @@ -92,6 +95,10 @@ void cacheOp(Path cacheDir, CacheOp op) { } + SearchResult[] searchPackages(string query) { + return null; + } + private Path bestPackageFile(string packageId, Dependency dep, bool pre_release) { Path toPath(Version ver) { @@ -216,6 +223,21 @@ return json; } + SearchResult[] searchPackages(string query) { + import std.uri : encodeComponent; + auto url = m_registryUrl; + url.localURI = "/api/packages/search?q="~encodeComponent(query); + string data; + try + data = cast(string)download(url); + catch (Exception) + return null; + 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); diff --git a/test/feat663-search.sh b/test/feat663-search.sh new file mode 100755 index 0000000..1f6f3a4 --- /dev/null +++ b/test/feat663-search.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +${DUB} search 2>/dev/null && exit 1 +${DUB} search nonexistent123456789package 2>/dev/null && exit 1 +${DUB} search dub | grep -q '^dub' || exit 1