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

[UX] Current mechanism to install several libraries and expose them to the user? #9581

Open
ivanperez-keera opened this issue Jan 2, 2024 · 8 comments
Labels

Comments

@ivanperez-keera
Copy link
Contributor

ivanperez-keera commented Jan 2, 2024

One of Haskell's strongest points is ability to create DSLs, including languages meant for users who did not need to or want to learn Haskell, or the intricacies of our tools.

Prior to the removal of sandboxes, DSLs defined in libraries could easily be made available to the user in a controlled way:

cabal v1-sandbox init
cabal v1-install all_subdirs # or package names
cabal v1-exec -- runhaskell DSLExample.hs

This was excellent especially for users who were not proficient in Haskell (nor did they need to be), since Haskell was just the vehicle to get things running and they only needed to install the libraries once. What they cared about was just being able to run their examples. Such users did not need to or care about cabal, nor did they need to learn it.

Modules were also simple, there were no haskellisms in them. See for example, a Copilot module:
https://github.com/Copilot-Language/copilot?tab=readme-ov-file#examples

We could almost alias:

alias copilot='cabal v1-exec -- runhaskell'

Adjusting the PATH and SANDBOX_DIR, we could even enable that to run from anywhere. It was a great user experience with minimal effort on the user side.

If a user messed up, the way to guarantee that they were exactly back to the starting point was trivial: rm -rf .cabal-sandbox and re-install. With only two installation instructions (v1-sandbox init and v1-install <packages>), it didn't get much smoother than this. Doing so also did not affect any other Haskell packages installed on that machine.

Since the removal of sandboxes, we've struggled to deliver a similar user experience with v2-. To this day, I have no idea how to install copilot from the repository directly without exposing the users to added complexity and more haskellisms.

For example, we could ask them to create a cabal.project every time they want to run a Copilot file. But now there's another file they need to create, every time they want to run an example.

We could also tell them to do:

cabal v2-install --lib copilot

but AFAIK installing libraries globally is discouraged (?).

We could ask them to create a cabal file. But that is a HUGE ask and exposes them to an unbearable amount of complexity. Our target users will simply refuse to use Copilot if that's a requirement.

We could ask them to add the dependencies at the top of their file, with something like:

#!/usr/bin/env cabal
{- cabal:
build-depends: base, copilot
-}

but that now exposes a very ugly element to them that they neither understand nor they care about.

I've been trying to make the user experience simple for our users. Ideally, they could install the DSL libraries once and forget about them. (I've tried to create a Homebrew formula unsuccessfully).

Although I am using Copilot as an example, I think this applies beyond the specifics of that project. One of the reasons why we cannot offer more EDSLs is precisely because installation becomes a show-stopper.

The ability to support EDSLs has been one of Haskell's strongest suites for decades, but it only goes so far as the user experience surrounding such languages is devoid of complexity.

What is the current mechanism to enable such use cases?

Thanks!

@ffaf1
Copy link
Collaborator

ffaf1 commented Jan 2, 2024

We could ask them to create a cabal file. But that is a HUGE ask and exposes them to an unbearable amount of complexity. Our target users will simply refuse to use Copilot if that's a requirement.

Could the package be created non-interactively?

cabal init -n --dependency=…

After that, running should be easy.

Other than that, an idea could be a wrapper that adds the relevant dependencies to file, so the user has just to put:

#! /usr/bin/env cabal-wrapped

(that is easier if dependencies are fixed, more complex if users want to change them. What do you think?

Thanks for opening this, UX experiences and suggestions are always welcome.

@ffaf1 ffaf1 added the re: user experience User experience (UX) issue label Jan 2, 2024
@fgaz
Copy link
Member

fgaz commented Jan 2, 2024

We could also tell them to do:

cabal v2-install --lib copilot

but AFAIK installing libraries globally is discouraged (?).

It is, but nothing is stopping you from doing it if it suits your workflow. After all, removing the global environment is easy (remove ~/.ghc/*/environments/default). It's "only" a problem when you don't know/remember it's there and it's causing other stuff to fail. You can also create named or local environments with the --env flag. These are safer since they only have a localized effect.

Named environment:

cabal install --lib --env=foo-env foo
# requires the use of -package-env in ghc calls
runhaskell -package-env=foo-env UsesFoo.hs
# remove the named environment
rm ~/.ghc/$arch-$os-$version/environments/foo-env

Local environment:

cabal install --lib --env=. foo
# has to be called in the directory where the environment was created
runhaskell UsesFoo.hs
# remove the local environment
rm .ghc.environment.*

Finally, help towards improving the --lib experience is always welcome: #6481

@fgaz
Copy link
Member

fgaz commented Jan 2, 2024

Oh, and the other caveat is that adding packages one by one (ie. modifying an existing environment) might produce an inconsistent environment. Adding them all in a single command (cabal install --lib foo bar baz...) is best. I thought we had an issue about that but the closest I can find are #5559 and #8483 (both closed). I think what I'm describing is #8483 (comment).

edit: filed #9582

@ulysses4ever
Copy link
Collaborator

I double the local package environments based approach. There’s also cabal-env — a stand-alone tool with more polished interface I think. But I never used it.

cabal install --lib --env=. foo

wow, didn’t know about --env and used --package-env for ages — I wasted so many keystrokes!..

@ivanperez-keera
Copy link
Contributor Author

the other caveat is that adding packages one by one (ie. modifying an existing environment) might produce an inconsistent environment. Adding them all in a single command (cabal install --lib foo bar baz...) is best.

Not that we need to do anything about it (at least not urgently), but this is not always possible when cabal does not understand that one of the packages provides a tool that another package needs. It'd be great if there was a way to tell cabal that a certain package has to be installed as early as possible.

Cabal has changed a lot in recent years, maybe specifying any tool dependencies is now possible. At least last time I checked, it only knew about specific tools.

@fgaz
Copy link
Member

fgaz commented Jan 24, 2024

Cabal has changed a lot in recent years, maybe specifying any tool dependencies is now possible.

Indeed :)

@okeuday
Copy link

okeuday commented Jan 24, 2024

The removal of sandboxes (#6445) never had replacement functionality and that has impacted different cabal-install use in different ways. Ignoring the use in #8343 , I also found sandboxes helpful when testing source code with multiple ghc versions (each using separate cabal-install executables) because the dependencies remain isolated in a way that is very visible (for understanding problems and determining dependency requirements).

I do not understand the past cabal-install sandbox discussions that attempt to say "You don't need sandboxes" (the past discussions have shown there is need and there has never been clear justification for removal), but I understand that is the current direction of cabal-install.

I have used ghc --make directly instead of cabal-install, with Setup configure --package-db=${SANDBOX} to continue using sandboxes and that approach should not break in the future. That remains an option if you need to continue using sandboxes.

@gbaz
Copy link
Collaborator

gbaz commented Jan 25, 2024

The removal of sandboxes (#6445) never had replacement functionality

Again, the intended replacement functionality is cabal v2-build with local env files, as detailed above.

I understand that local env files have had problems and frustrations in the past, and we have been working to attempt to improve the user experience.

If there is a specific use case for sandboxes that cannot be replicated with local env files, please file a ticket about it directly.

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

No branches or pull requests

6 participants