Allow removal of reverse dependencies with uninstall --deps flag (#601)

* Fix for #398

* Updated fix for #398

* Enable uninstall of reverse deps

* Update README

* Updates based on feedback
This commit is contained in:
genotrance 2019-01-08 13:58:19 -06:00 • committed by Dominik Picheta
commit 88f5545c75
6 changed files with 70 additions and 21 deletions

View file

@ -221,8 +221,8 @@ instead of a name.
### nimble uninstall
The ``uninstall`` command will remove an installed package. Attempting to remove
a package which other packages depend on is disallowed and will result in an
error. You must currently manually remove the reverse dependencies first.
a package which other packages depend on will result in an error. You can use the
``--inclDeps`` or ``-i`` flag to remove all dependent packages along with the package.
Similar to the ``install`` command you can specify a version range, for example:
@ -749,16 +749,16 @@ to ensure that the dependencies you specified are correct.
### Compile with `nim` after changing the nimble directory
The Nim compiler has been preconfigured to look at the default nimble directory while compiling,
so no extra step is required to use nimble managed packages in your code.
However, if you are using a custom `nimbleDir`, you need to specify the
so no extra step is required to use nimble managed packages in your code.
However, if you are using a custom `nimbleDir`, you need to specify the
`--nimblePath:PATH` option. For example,
if your `nimble` directory is located at `/some/custom/path/nimble`, this should work:
```
nim c --nimblePath:/some/custom/path/nimble/pkgs main.nim
```
```
Some code editors rely on `nim check` to check for errors under the hood (e.g. VScode),
Some code editors rely on `nim check` to check for errors under the hood (e.g. VScode),
and the editor extension may not allow users to pass custom option to `nim check`, which
will cause `nim check` to scream `Error: cannot open file:<the_package>`. In this case,
you will have to use [Nim compiler's configuration files](https://nim-lang.org/docs/nimc.html#compiler-usage-configuration-files). Simply add the line:

View file

@ -846,22 +846,25 @@ proc uninstall(options: Options) =
for pkg in pkgList:
# Check whether any packages depend on the ones the user is trying to
# uninstall.
let revDeps = getRevDeps(options, pkg)
var reason = ""
if revDeps.len == 1:
reason = "$1 ($2) depends on it" % [revDeps[0].name, $revDeps[0].ver]
if options.uninstallRevDeps:
getAllRevDeps(options, pkg, pkgsToDelete)
else:
for i in 0 ..< revDeps.len:
reason.add("$1 ($2)" % [revDeps[i].name, $revDeps[i].ver])
if i != revDeps.len-1:
reason.add ", "
reason.add " depend on it"
let revDeps = getRevDeps(options, pkg)
var reason = ""
if revDeps.len == 1:
reason = "$1 ($2) depends on it" % [revDeps[0].name, $revDeps[0].ver]
else:
for i in 0 ..< revDeps.len:
reason.add("$1 ($2)" % [revDeps[i].name, $revDeps[i].ver])
if i != revDeps.len-1:
reason.add ", "
reason.add " depend on it"
if revDeps.len > 0:
errors.add("Cannot uninstall $1 ($2) because $3" %
[pkgTup.name, pkg.specialVersion, reason])
else:
pkgsToDelete.add pkg
if revDeps.len > 0:
errors.add("Cannot uninstall $1 ($2) because $3" %
[pkgTup.name, pkg.specialVersion, reason])
else:
pkgsToDelete.add pkg
if pkgsToDelete.len == 0:
raise newException(NimbleError, "\n " & errors.join("\n "))
@ -1007,7 +1010,7 @@ proc test(options: Options) =
existsBefore = existsFile(binFileName)
execBackend(optsCopy)
let
existsAfter = existsFile(binFileName)
canRemove = not existsBefore and existsAfter

View file

@ -10,6 +10,7 @@ type
Options* = object
forcePrompts*: ForcePrompt
depsOnly*: bool
uninstallRevDeps*: bool
queryVersions*: bool
queryInstalled*: bool
nimbleDir*: string
@ -71,6 +72,7 @@ Commands:
The current working directory needs to be the
toplevel directory of the Nimble package.
uninstall [pkgname, ...] Uninstalls a list of packages.
[-i, --inclDeps] Uninstall package and dependent package(s).
build Builds a package.
c, cc, js [opts, ...] f.nim Builds a file inside a package. Passes options
to the Nim compiler.
@ -301,6 +303,12 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) =
result.depsOnly = true
else:
wasFlagHandled = false
of actionUninstall:
case f
of "incldeps", "i":
result.uninstallRevDeps = true
else:
wasFlagHandled = false
of actionCompile, actionDoc, actionBuild:
let prefix = if kind == cmdShortOption: "-" else: "--"
if val == "":

View file

@ -538,6 +538,10 @@ proc getPkgDest*(pkgInfo: PackageInfo, options: Options): string =
let pkgDestDir = options.getPkgsDir() / (pkgInfo.name & versionStr)
return pkgDestDir
proc `==`*(pkg1: PackageInfo, pkg2: PackageInfo): bool =
if pkg1.name == pkg2.name and pkg1.myPath == pkg2.myPath:
return true
when isMainModule:
doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") ==
("packagea", "0.1")

View file

@ -76,6 +76,19 @@ proc getRevDeps*(options: Options, pkg: PackageInfo): seq[PkgTuple] =
result.add(pkgTup)
proc getAllRevDeps*(options: Options, pkg: PackageInfo, result: var seq[PackageInfo]) =
if pkg in result:
return
let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
for rdepTup in getRevDeps(options, pkg):
for rdepInfo in findAllPkgs(installedPkgs, rdepTup):
if rdepInfo in result:
continue
getAllRevDeps(options, rdepInfo, result)
result.add pkg
when isMainModule:
var nimbleData = %{"reverseDeps": newJObject()}

View file

@ -568,6 +568,27 @@ suite "reverse dependencies":
verify execNimbleYes("remove", "pkgA")
verify execNimbleYes("remove", "mydep")
test "revdep fail test":
cd "revdep/mydep":
verify execNimbleYes("install")
cd "revdep/pkgWithDep":
verify execNimbleYes("install")
let (output, exitCode) = execNimble("uninstall", "mydep")
checkpoint output
check output.processOutput.inLines("cannot uninstall mydep")
check exitCode == QuitFailure
test "revdep -i test":
cd "revdep/mydep":
verify execNimbleYes("install")
cd "revdep/pkgWithDep":
verify execNimbleYes("install")
verify execNimbleYes("remove", "mydep", "-i")
test "issue #373":
cd "revdep/mydep":
verify execNimbleYes("install")