Edit (2015-08-10): the tools have been updated to fix a few bugs as well as incompatibilities with the latest GHC; they now also work on Cabal sandboxes.
Problems
A. There is no way to uninstall packages in Cabal
Currently, cabal-install doesn’t know how to uninstall packages. The best you can do is to unregister the package with the GHC package-database manager, eliminating the package metadata from the database without removing the actual files.
There is a package called cabal-uninstall (and probably a few others) that remedies this to some extent, but it doesn’t work if the package has already been unregistered.
Additionally, while ghc-pkg does warn you of dependency breakage, it doesn’t provide an easy way to remove a package and all its dependents transitively.
B. Removing broken packages is a tedious chore
If for some reason your packages get broken, there’s no easy way to clean up the mess.
On my system, this usually happens because Arch Linux upgrades some of the globally-installed packages, breaking swaths of user-installed packages in the process (or it could be due to a GHC upgrade).
To fix this you’d have to unregister all of the broken packages. And if you want to reclaim the space used by the dead packages, you’d have to dive into ~/.cabal
and remove them manually.
Tools
To help fix the issues outlined above, here are some scripts to assist the process:
cabal-gc: a “garbage collector” that searches for any lingering packages whose files still remain but are no longer registered. (Note: it does not remove any executables in the
bin
directory.)ghc-pkg-check: a thin wrapper around
ghc-pkg check
that suppresses the haddock warnings that no-one seems to care about.ghc-pkg-unregister: a thin wrapper around
ghc-pkg unregister
that allows multiple packages to be unregistered in one call.
While it’s possible to fully automate this process, it’s best to do them one at a time to make sure nothing bad happens.
Tutorial
First off, if you want to manage packages in a sandbox, be sure to run this command prior to everything else below:
cabal
--sandbox-config-file=./cabal.sandbox.config exec -- "$SHELL"
(The --sandbox-config-file=…
flag is optional.)
Now,
- if your goal is to uninstall a specific package as well as its dependents, then follow all the steps below;
- if your goal is to only remove broken packages, then jump straight to step 2.
1. Remove the target packages
To remove packages, the first thing to do would be to run:
ghc-pkg-unregister my-package-0.5.0 some-package-1.0.0
If there are any dependent packages, you will receive an error telling you that those will be broken:
ghc-pkg: unregistering some-package-1.0.0 would break the following packages: other-package-2.0.0 another-package-3.0.0 (use --force to override)
If you’re alright with this, add the --force
flag to remove it for good. We’ll eliminate the broken packages shortly.
ghc-pkg-unregister --force some-package-1.0.0
unregistering some-package-1.0.0 would break the following packages: other-package-2.0.0 another-package-3.0.0 (ignoring)
Despite the conditional mood in the message, the package will indeed be unregistered.
2. Remove the dependent packages
Now, we need to get rid of the broken packages. Let’s see which packages are broken:
ghc-pkg-check
There are problems in package other-package-2.0.0:
dependency "some-package-1.0.0-…" doesn't exist
There are problems in package another-package-3.0.0:
dependency "some-package-1.0.0-…" doesn't exist
The following packages are broken, either because they have a problem
listed above, or because they depend on a broken package.
other-package-2.0.0
another-package-3.0.0
To remove all of these broken packages, run:
ghc-pkg-check --simple-output | xargs ghc-pkg-unregister --force
To make sure all of the broken packages are taken care of, run ghc-pkg-check
again. If there are more broken packages, you’ll need to keep repeating this step until all of them have been eliminated.
3. Delete the associated files
This step is optional, although it can be useful to reclaim some disk space.
Since we will be deleting files, it’s best to perform a dry run first:
cabal-gc
can be removed: /home/user/.cabal/lib/x86_64-linux-ghc-7.10.1/anoth_d9K7jTHCBftCdWJFHesDel
can be removed: /home/user/.cabal/lib/x86_64-linux-ghc-7.10.1/other_8j0AdSQVkKosS3ev8r3pBu
can be removed: /home/user/.cabal/lib/x86_64-linux-ghc-7.10.1/mypac_XYf894wKraySpNs9RUwwMV
can be removed: /home/user/.cabal/lib/x86_64-linux-ghc-7.10.1/somep_x3XTaLFeSmcMHNpv7Ng8xw
can be removed: /home/user/.cabal/share/doc/x86_64-linux-ghc-7.10.1/another-package-3.0.0
can be removed: /home/user/.cabal/share/doc/x86_64-linux-ghc-7.10.1/other-package-2.0.0
can be removed: /home/user/.cabal/share/doc/x86_64-linux-ghc-7.10.1/my-package-0.5.0
can be removed: /home/user/.cabal/share/doc/x86_64-linux-ghc-7.10.1/some-package-1.0.0
If everything looks okay, go ahead and delete them for real:
cabal-gc -r
removed: /home/user/.cabal/lib/x86_64-linux-ghc-7.10.1/anoth_d9K7jTHCBftCdWJFHesDel
removed: /home/user/.cabal/lib/x86_64-linux-ghc-7.10.1/other_8j0AdSQVkKosS3ev8r3pBu
removed: /home/user/.cabal/lib/x86_64-linux-ghc-7.10.1/mypac_XYf894wKraySpNs9RUwwMV
removed: /home/user/.cabal/lib/x86_64-linux-ghc-7.10.1/somep_x3XTaLFeSmcMHNpv7Ng8xw
removed: /home/user/.cabal/share/doc/x86_64-linux-ghc-7.10.1/another-package-3.0.0
removed: /home/user/.cabal/share/doc/x86_64-linux-ghc-7.10.1/other-package-2.0.0
removed: /home/user/.cabal/share/doc/x86_64-linux-ghc-7.10.1/my-package-0.5.0
removed: /home/user/.cabal/share/doc/x86_64-linux-ghc-7.10.1/some-package-1.0.0
Show Disqus comments
comments powered by Disqus