diff --git a/source/dub/commandline.d b/source/dub/commandline.d index bbcfde5..947aefe 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -1213,6 +1213,10 @@ } class RemoveCommand : FetchRemoveCommand { + private { + bool m_nonInteractive; + } + this() { this.name = "remove"; @@ -1226,6 +1230,7 @@ override void prepare(scope CommandArgs args) { super.prepare(args); + args.getopt("n|non-interactive", &m_nonInteractive, ["Don't enter interactive mode."]); } override int execute(Dub dub, string[] free_args, string[] app_args) @@ -1236,7 +1241,29 @@ auto package_id = free_args[0]; auto location = dub.defaultPlacementLocation; - dub.remove(package_id, m_version, location, m_forceRemove); + size_t resolveVersion(in Package[] packages) { + writeln("Select version of '", package_id, "' to remove from location '", location, "':"); + foreach(i, pack; packages) + writeln(i, ". ", pack.version_); + writeln(packages.length, ". ", "all versions"); + while (true) { + writef("> "); + auto inp = readln(); + if (!inp.length) // Ctrl+D + return size_t.max; + if (inp.length > 1) { + try { + immutable selection = inp[0 .. $ - 1].to!size_t; + if (selection <= packages.length) + return selection; + } catch (ConvException e) { + } + logError("Please enter a number between 0 and %s.", packages.length); + } + } + } + + dub.remove(package_id, m_version, location, m_forceRemove, m_nonInteractive ? null : &resolveVersion); return 0; } } diff --git a/source/dub/dub.d b/source/dub/dub.d index 1d4a647..2d46817 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -738,8 +738,10 @@ name/version. force_remove = Forces removal of the package, even if untracked files are found in its folder. + resolveVersion = Callback to select package version. */ - void remove(string package_id, string version_, PlacementLocation location, bool force_remove) + void remove(string package_id, string version_, PlacementLocation location, bool force_remove, + scope size_t delegate(in Package[] packages) resolveVersion=null) { enforce(!package_id.empty); if (location == PlacementLocation.local) { @@ -763,13 +765,21 @@ ~ ")"); } if(version_.empty && packages.length > 1) { - logError("Cannot remove package '" ~ package_id ~ "', there are multiple possibilities at location\n" - ~ "'" ~ to!string(location) ~ "'."); - logError("Available versions:"); - foreach(pack; packages) - logError(" %s", pack.version_); - throw new Exception("Please specify a individual version using --version=... or use the" - ~ " wildcard --version=" ~ RemoveVersionWildcard ~ " to remove all versions."); + if (resolveVersion is null) { + logError("Cannot remove package '" ~ package_id ~ "', there are multiple possibilities at location\n" + ~ "'" ~ to!string(location) ~ "'."); + logError("Available versions:"); + foreach(pack; packages) + logError(" %s", pack.version_); + throw new Exception("Please specify a individual version using --version=... or use the" + ~ " wildcard --version=" ~ RemoveVersionWildcard ~ " to remove all versions."); + } else { + immutable idx = resolveVersion(packages); + if (idx == size_t.max) + return; + else if (idx != packages.length) + packages = packages[idx .. idx + 1]; + } } logDebug("Removing %s packages.", packages.length); diff --git a/test/interactive-remove.sh b/test/interactive-remove.sh new file mode 100755 index 0000000..a523e32 --- /dev/null +++ b/test/interactive-remove.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -euo pipefail + +$DUB fetch dub --version=0.9.20 && [ -d $HOME/.dub/packages/dub-0.9.20/dub ] +$DUB fetch dub --version=0.9.21 && [ -d $HOME/.dub/packages/dub-0.9.21/dub ] +if $DUB remove dub --non-interactive; then + echo "Non-interactive remove should fail" 1>&2 + exit 1 +fi +echo 0 | $DUB remove dub | tr --delete '\n' | grep --ignore-case 'select.*0\.9\.20.*0\.9\.21.*' +if [ -d $HOME/.dub/packages/dub-0.9.20/dub ]; then + echo "Failed to remove dub-0.9.20" 1>&2 + exit 1 +fi +$DUB fetch dub --version=0.9.20 && [ -d $HOME/.dub/packages/dub-0.9.20/dub ] +# EOF aborts remove +echo -n '' | $DUB remove dub +if [ ! -d $HOME/.dub/packages/dub-0.9.20/dub ] || [ ! -d $HOME/.dub/packages/dub-0.9.21/dub ]; then + echo "Aborted dub still removed a package" 1>&2 + exit 1 +fi +# validates input +echo -e 'abc\n3\n-1\n2' | $DUB remove dub +if [ -d $HOME/.dub/packages/dub-0.9.20/dub ] || [ -d $HOME/.dub/packages/dub-0.9.21/dub ]; then + echo "Failed to remove all version of dub" 1>&2 + exit 1 +fi