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 ### nimble uninstall
The ``uninstall`` command will remove an installed package. Attempting to remove 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 a package which other packages depend on will result in an error. You can use the
error. You must currently manually remove the reverse dependencies first. ``--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: 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 ### Compile with `nim` after changing the nimble directory
The Nim compiler has been preconfigured to look at the default nimble directory while compiling, 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. 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 However, if you are using a custom `nimbleDir`, you need to specify the
`--nimblePath:PATH` option. For example, `--nimblePath:PATH` option. For example,
if your `nimble` directory is located at `/some/custom/path/nimble`, this should work: if your `nimble` directory is located at `/some/custom/path/nimble`, this should work:
``` ```
nim c --nimblePath:/some/custom/path/nimble/pkgs main.nim 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 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, 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: 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: for pkg in pkgList:
# Check whether any packages depend on the ones the user is trying to # Check whether any packages depend on the ones the user is trying to
# uninstall. # uninstall.
let revDeps = getRevDeps(options, pkg) if options.uninstallRevDeps:
var reason = "" getAllRevDeps(options, pkg, pkgsToDelete)
if revDeps.len == 1:
reason = "$1 ($2) depends on it" % [revDeps[0].name, $revDeps[0].ver]
else: else:
for i in 0 ..< revDeps.len: let revDeps = getRevDeps(options, pkg)
reason.add("$1 ($2)" % [revDeps[i].name, $revDeps[i].ver]) var reason = ""
if i != revDeps.len-1: if revDeps.len == 1:
reason.add ", " reason = "$1 ($2) depends on it" % [revDeps[0].name, $revDeps[0].ver]
reason.add " depend on it" 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: if revDeps.len > 0:
errors.add("Cannot uninstall $1 ($2) because $3" % errors.add("Cannot uninstall $1 ($2) because $3" %
[pkgTup.name, pkg.specialVersion, reason]) [pkgTup.name, pkg.specialVersion, reason])
else: else:
pkgsToDelete.add pkg pkgsToDelete.add pkg
if pkgsToDelete.len == 0: if pkgsToDelete.len == 0:
raise newException(NimbleError, "\n " & errors.join("\n ")) raise newException(NimbleError, "\n " & errors.join("\n "))
@ -1007,7 +1010,7 @@ proc test(options: Options) =
existsBefore = existsFile(binFileName) existsBefore = existsFile(binFileName)
execBackend(optsCopy) execBackend(optsCopy)
let let
existsAfter = existsFile(binFileName) existsAfter = existsFile(binFileName)
canRemove = not existsBefore and existsAfter canRemove = not existsBefore and existsAfter

View file

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

View file

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

View file

@ -76,6 +76,19 @@ proc getRevDeps*(options: Options, pkg: PackageInfo): seq[PkgTuple] =
result.add(pkgTup) 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: when isMainModule:
var nimbleData = %{"reverseDeps": newJObject()} var nimbleData = %{"reverseDeps": newJObject()}

View file

@ -568,6 +568,27 @@ suite "reverse dependencies":
verify execNimbleYes("remove", "pkgA") verify execNimbleYes("remove", "pkgA")
verify execNimbleYes("remove", "mydep") 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": test "issue #373":
cd "revdep/mydep": cd "revdep/mydep":
verify execNimbleYes("install") verify execNimbleYes("install")