Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stack uninstall, the opposite of stack install #361

Closed
spinda opened this issue Jun 19, 2015 · 41 comments
Closed

Add stack uninstall, the opposite of stack install #361

spinda opened this issue Jun 19, 2015 · 41 comments
Assignees
Milestone

Comments

@spinda
Copy link

spinda commented Jun 19, 2015

This is another gap in cabal that stack could fill. If stack install foo installs foo, it would be nice to have stack uninstall foo reverse the process.

@spinda spinda changed the title stack uninstall, the opposite of stack install Add stack uninstall, the opposite of stack install Jun 19, 2015
@chrisdone
Copy link
Member

Indeed.

Ideas: There is the database entry (ghc-pkg unregister) and removing the data files and the installed executable. It should be possible to track what was installed where and then go remove that later, if it matches (e.g. does the thing here have the same sha1 hash and creation time as what we installed), that would permit removing from ~/.local/bin without fear.

@bitemyapp
Copy link
Contributor

👍 I've needed this.

@snoyberg
Copy link
Contributor

Can someone explain what the motivation would be for using uninstall? I can understand this in a world where your build tools make a mess of things regularly, but presuming package databases are properly handled (as stack endeavors to do), when would we tell a user "you should use stack uninstall"?

@bitemyapp
Copy link
Contributor

@snoyberg I've had difficulty reinstalling vendored/internal libraries in the past with Cabal and needed to unregister to get it to use the new version or get unstuck. It's possible this won't be an issue with Stack though.

@spinda
Copy link
Author

spinda commented Jun 21, 2015

Say I install pandoc with stack install pandoc. Then I decide I don't want pandoc anymore. It would be better to be able to run stack uninstall pandoc than to have to manually delete ~/.local/bin/pandoc, etc.

@snoyberg snoyberg added this to the 0.2.0.0 milestone Jun 21, 2015
@drwebb
Copy link
Contributor

drwebb commented Jun 21, 2015

With #342, which I've been implementing, this would become a bit of a mess (how would you know which custom path to uninstall from?) stack uninstall XXX should also take a --path in this case, with ~/.local/bin (on Linux at least) being the default.

Edit: what would be the expected result if I ran stack install pandoc, stack install pandoc --path /usr/bin, stack uninstall pandoc. Would the package database entry be deleted in that case? How would the stack keep track of the two installed locations?

@conklech
Copy link

Aren't there two or three separate issues here: (1) deleting and unregistering library snapshots from the global stack database; (2) deleting and unregistering libraries from .stack-work; and (3) deleting executables and other installation artifacts (~/.local/bin/pandoc)?

As @snoyberg says, if the package database works correctly the first two shouldn't ever be necessary except for space saving. (Right? Even if dependencies in the stack.yaml file change?) The stack rm command discussed in #133 might be the appropriate mechanism to deal with build-artifact space constraints.

@snoyberg
Copy link
Contributor

snoyberg commented Jul 2, 2015

I'm quite tempted to close as wontfix. I haven't seen the use case clearly demonstrated that stack uninstall would be useful. I know others ask for this all the time though, which is why I'll leave this open a bit longer.

@snoyberg snoyberg modified the milestones: 0.3.0.0, 0.2.0.0 Jul 2, 2015
@DanBurton
Copy link
Contributor

If we haven't already, we should print a helpful message if people call
stack uninstall. (But preferably it shouldn't show up in the bash
completion or the --help.)

On Thursday, July 2, 2015, Michael Snoyman [email protected] wrote:

I'm quite tempted to close as wontfix. I haven't seen the use case clearly
demonstrated that stack uninstall would be useful. I know others ask for
this all the time though, which is why I'll leave this open a bit longer.


Reply to this email directly or view it on GitHub
#361 (comment)
.

-- Dan Burton

@cdepillabout
Copy link
Member

I would appreciate a stack uninstall command.
My use case would be similar to what @drwebb brought up. I might install a command like pandoc. After playing around with it for a while, I decide I don't want it anymore. It would be much easier to do stack uninstall pandoc than something like the following:

$ which pandoc
/home/me/some/path/bin/pandoc
$ rm -rf /home/me/some/path/bin/pandoc
$

Usually at this point I start wondering if pandoc left around a settings file like /home/me/some/path/etc/pandoc.conf. I have to look for it and delete it if it exists.

I then wonder if pandoc left around some sort of man file like /home/me/some/path/man/man1/pandoc.1.gz. I don't like it when the man files are left but the command itself doesn't exist. I then have to search for them and delete them.

I guess I could do something like find /home/me/some/path -iname '*pandoc*', but there's always a possibility that stack install pandoc created a file that doesn't have pandoc in the name.

As an aside, when I'm installing a normal unix/linux package from source with ./configure --prefix=/home/me/some/path ; make ; make install, it's really nice when the Makefile has an uninstall target so I can easily uninstall it with make uninstall. A lot of packages don't provide an uninstall target, but I've always found it really nice when they do.

@snoyberg
Copy link
Contributor

snoyberg commented Jul 5, 2015

This actually proves the point of why I don't think stack uninstall is a good idea: cabal doesn't give us enough information to determine how to remove such stray files, and therefore stack uninstall can't be any more intelligent than the command you provided (which, as you mention, is not satisfactory).

@cdepillabout
Copy link
Member

@snoyberg: I guess stack can't do something smarter than cabal? For instance, record the location of which files are installed?

I'm guessing something like this would not be super simple to implement. It might not be worth it unless a lot of people want a stack uninstall command.

@snoyberg
Copy link
Contributor

snoyberg commented Jul 5, 2015

Uninstalling the executables is trivial, since stack copies those itself. The rest of the files are not installed by stack at all. But I'm dubious about the value in uninstalling them anyway, since they (should) all be installed inside a snapshot-specific directory instead.

Like I said, I've never felt the need for an uninstall command, so I may be the wrong person to make a call on this. But it doesn't seem like this is something people actually need, rather something people think they need.

@spinda
Copy link
Author

spinda commented Jul 6, 2015

There's the perspective of newbie-friendliness. To remove an installed program, other languages have package managers with gem uninstall, pip uninstall, npm remove, and so on. When you get to cabal/stack, the user has to track down where the binary is stored and manually delete it. Even if stack uninstall is as simple as automating that process, it's an amenity that makes Haskell tooling just a bit friendlier.

@AphonicChaos
Copy link

I just wanted to echo some comments above in support of this feature. My use case for wanting an uninstall command is two-fold:

  1. There are often times that I jump between tools as I explore feature sets and am unsure of which, if any, I'll keep around. For instance, speed of execution had me reconsider hdevtools as a replacement for ghc-mod. At the moment, I have to do a ghc-pkg unregister to get rid of the libraries, then manually remove the executable in ~/.cabal/bin. While it's only two steps, I think the same argument for using stack instead of resorting to have to remember cabal sandbox-init; cabal install --only-dependencies; cabal install applies here. Further, no other language-specific package manager* that I've used requires me to remember arbitrary commands to uninstall software.
  2. I think stack may have solved this problem already, but for some mini projects that I'm working on, I spend time exploring libraries to use. Those libraries have build dependencies which leave behind binaries. If I later decide during evaluation that I want to use a different library, I don't want artifacts from the old library to be left around.

As I look back at what I wrote, I think both use cases are similar enough that they could be summarized as follows: Libraries used during development might change, and uninstall would ideally make changing libraries a clean process without leaving behind artifacts or requiring the user to remember multiple invocations that don't have any obvious mnemonic .

As another note, which perhaps isn't convincing, except perhaps on Mac OS X and a couple of fringe Linux distros, having to manually delete files to uninstall something feels wrong. I'm neither confident that I have uninstalled things properly, nor am I confident that in just deleting them (even if it is in my own home directory) that I haven't broken something else in the process. An official uninstall command would offer me some peace of mind.

[*] I know, "stack is not a package manager". If it's existence is meant to improve the tooling situation for Haskell, I think perhaps it should be.

@ajnsit
Copy link

ajnsit commented Jul 6, 2015

I think it's important for a package manager to be able to remove packages it has installed in the project directory. Even if it can't cause build errors because the dependency version is explicitly specified in stack.yaml, it is confusing to have old versions hanging around. Unlike the global and the snapshot dbs, old files inside the local db cannot be used by any other project and are truly junk.

At the very least, a "stack cleanup" command should be added which would remove all locally installed packages which are not being referred to by stack,yaml.

@radix
Copy link
Contributor

radix commented Jul 6, 2015

@ajnsit @Aspidites

It is clear that a lot of people are confusing what stack install and a potential stack uninstall should do.

stack install is for installing executables, and nothing else. The proposal to make stack uninstall remove packages from a package DB would not be the inverse of stack install, and so I think that would be a bad set of names for those behaviors.

Maybe stack install should be renamed to stack install-exes as one step in clearing up this confusion?

So there are a few different behaviors here:

  1. installing executables: currently stack install
  2. installing packages in a package DB: currently implicitly done when building
  3. removing executables: not implemented
  4. removing packages from a package DB: not implemented

@spinda
Copy link
Author

spinda commented Jul 6, 2015

@radix

Splitting the up the issues, your list could be filled in as:

  1. installing executables: stack install
  2. installing packages in a package DB: implicitly done when building
  3. removing executables: stack uninstall
  4. removing packages from a package DB: stack gc to sweep up all "orphaned" packages (borrowing from git gc)

@spinda
Copy link
Author

spinda commented Jul 7, 2015

I meant to add that I'm not certain of the specifics of how a stack gc would operate, but it does seem like something separate from stack uninstall.

@drwebb
Copy link
Contributor

drwebb commented Jul 7, 2015

I thought about the option to add packages to a nix database, as a stack aware plugin. Uninstall could rollback the database to before the install, and that way it's not essential to keep track of dependencies or do a gc.

Every install would keep track of the files to be written to the database, as I believe BuildPlan is tracking.

As one possibility I had in mindstack nix install would hash using the current package-db, and stack nix uninstall would end up just rolling back state of the package db before the installation. The great part about using stack nix install is it would provide these rollback points and possibly open the doors to fancier dependency tracking than we would be capable of pulling off with stack.

@vyp
Copy link
Contributor

vyp commented Jul 7, 2015

@drwebb Can nix be used separately from nixOS? As in have a nix store for haskell things specifically, alongside the rest of the system? If so, are there any writeups or guides on this? Have you done it? I can't seem to find any.

@cdepillabout
Copy link
Member

@vyp Nix can be used seperately from nixOS. The try-reflex project is using this approach to give users an easy way to try out reflex and ghcjs without having to install from source.

The nix manual should (?) have all the information you need to get started using Nix.

@vyp
Copy link
Contributor

vyp commented Jul 7, 2015

@cdepillabout Thanks. In that case I +1 to @drwebb's proposal. It could avoid a lot of work already handled much better with nix.

I'm assuming this would mean that one would have to use nix (at least for haskell things), correct? If so, how difficult is it to write nix expressions for haskell packages. As in, it looks easy enough, but does anyone know of anyone who has any actually successfully done one? (For a large package.)

Edit: Actually I take that back, it's pretty easy.

@ajnsit
Copy link

ajnsit commented Jul 7, 2015

I'm pretty excited about a 'cleanup'/'gc' command being added to stack!

Bikeshedding here, but 'gc' doesn't seem to be a good name. Garbage collection usually doesn't have any observable effect on any semantics and is purely an implementation detail. I would vote for something more descriptive like 'autoremove' which is used in apt-get to perform exactly the same function i.e. remove packages which are not depended on by anything.

Edit: Also, borrowing more cues from apt-get, on every 'stack build', it would be nice to ask the user to run 'autoremove' if there are orphan packages.

@mboes
Copy link
Contributor

mboes commented Jul 7, 2015

I'm +1 on stack gc, with that name exactly (because unlike apt-get, it doesn't mutate global state in any meaningfully observable way, using it just means future stack build commands might take longer than usual - and still yield the exact same result). However, that's a topic for a separate ticket.

@AphonicChaos
Copy link

Or (also borrowing from git), stack clean which would remove anything not tracked by the project (unnamed dependencies, etc). It also parallels make's clean directive.

@ajnsit
Copy link

ajnsit commented Jul 7, 2015

Stack clean already exists. Though I'm unsure of what it does exactly.

@spinda
Copy link
Author

spinda commented Jul 7, 2015

stack clean removes the packages registered via stack build.

On Tue, Jul 7, 2015, 10:39 Anupam Jain [email protected] wrote:

Stack clean already exists. Though I'm unsure of what it does exactly.


Reply to this email directly or view it on GitHub
#361 (comment)
.

@snoyberg
Copy link
Contributor

There's a relevant pull request at #602. See the discussion in #569 for more information about it.

@snoyberg snoyberg self-assigned this Jul 15, 2015
@snoyberg snoyberg modified the milestones: 0.2.0.0, 0.3.0.0 Jul 15, 2015
@bitemyapp
Copy link
Contributor

@snoyberg I was working with a vendored version of Yesod for testing a PR and I found a targeted (single package) --force-dirty or uninstall would've been handy. Have I missed a feature that could've handled this?

@mgsloan
Copy link
Contributor

mgsloan commented Mar 17, 2016

@bitemyapp Tracked by #1476

@Blaisorblade
Copy link
Collaborator

But there's still no support for removing executables, which is what is easy for stack, right? Since binaries get easily huge and SSDs are not big enough to ignore disk usage, that has still a point.
For libraries, I can accept for now clearing snapshots every now and then, though it is annoying.

For the rest: yes, cabal support is needed, but since there were attempts to add it (not that it's easy), could this be reconsidered if they finally manage?

@ghost
Copy link

ghost commented Nov 25, 2016

stack uninstall DEPRECATED

user-friendly package manager? :(

@chris-martin
Copy link
Contributor

Here is my use case.

chris@cubby ~ ❯❯❯ stack repl --package cryptonite
Configuring GHCi with the following packages: 
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
Some flags have not been recognized: prompt-cont,  > 
Loaded GHCi configuration from /home/chris/.ghc/ghci.conf
Loaded GHCi configuration from /run/user/1000/ghci19092/ghci-script

λ> import "cryptonite" Crypto.Hash.Algorithms

λ> import "cryptonite" Crypto.Hash

λ> hash "" :: Digest SHA256

<interactive>:1:1: error:
    Ambiguous interface for ‘Crypto.Hash’:
      it was found in multiple packages:
      cryptohash-0.11.9 cryptonite-0.23

I need to uninstall cryptohash because its presence is preventing me from being able to use cryptonite.

@DanBurton
Copy link
Contributor

I believe a workaround is stack exec ghc-pkg unregister cryptohash, though this may break stuff so use with caution.

@mgsloan
Copy link
Contributor

mgsloan commented Nov 17, 2017

It shouldn't break anything to use unregister, but if some project needs the package it will need to get rebuilt.

I am working on a change that will make it so that stack ghci --package cryptonite --package-hiding or just stack ghci cryptonite will use package hiding.

@Blaisorblade
Copy link
Collaborator

I'm also confused that PackageImports are not working, isn't that another bug?

Regardless, having support for uninstall seems still good to be able to workaround other bugs, since those exist.

@chris-martin
Copy link
Contributor

@mgsloan Yeah, it'd be fantastic if stack ghci would hide packages that you didn't ask for.

@mgsloan
Copy link
Contributor

mgsloan commented Nov 17, 2017

Yeah, it looks like there is a ghc bug here. Please file an upstream issue with ghc!

Yeah, uninstall would be good. But I don't see a good way to do it without support for Cabal. Could maybe try to remove some things, but general uninstall seems impossible.

@chris-martin I've fixed the behavior of stack ghci for this! So you can use stack upgrade --git or build from the stack repo. It will work with either stack ghci --package cryptonite or just stack ghci cryptonite

@Blaisorblade
Copy link
Collaborator

Could maybe try to remove some things, but general uninstall seems impossible.

Unregistering packages (recursively, which ghc-pkg unregister IIUC won't do) might be enough for some use cases. Yes, actually removing files is hard, maybe we should give up on that and do the rest (perfect is enemy of the good and so on). If disk usage becomes an actual problem we'll show the evidence to the Cabal devs (not that the needed changes on their side are easy).

I remember I needed it to workaround different bugs (different scenario: ghc-paths had become invalid because Homebrew moved the system GHC). Again: different bugs were involved, but I maintain that alone is not a good argument.
(Who should do the work is a different topic of course, I'm happy enough if we agree on a plan for volunteers).

@mgsloan
Copy link
Contributor

mgsloan commented Nov 19, 2017

Unregistering packages (recursively, which ghc-pkg unregister IIUC won't do) might be enough for some use cases.

Ah, fair point! Well, if you're doing a stack build after the unregister, it will unregister + rebuild recursively. Indeed, though, it could leave some packages in the DB broken.

So, yeah, it'd be worth automating recursive unregister, and probably wouldn't be too hard either!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests