haskell-language-server icon indicating copy to clipboard operation
haskell-language-server copied to clipboard

Pin versions of libraries used by plugins

Open mitchellwrosen opened this issue 3 years ago • 11 comments

Problem: it is unclear which versions of plugins (the Haskell ones, anyway - I'm not sure if any plugins are not bundled Haskell libraries, but are instead communicated with via subprocess) my HLS has installed.

Describe the solution you'd like

Plugins pin their dependency on the underlying tool (e.g. hls-ormolu-plugin-1.0.2.1 could depend on ormolu == 0.4.0.0 rather than ormolu >= 0.1.2 && < 0.5)

Additional context

This (I think) would make it easier for different people on a team to end up installing a version of HLS that has the same underlying formatter (and other plugins).

Currently, someone I'm collaborating with has managed to install haskell-language-server-1.7.0.0 with a version of ormolu less than the latest 0.4.0.0, which is what my haskell-language-server-1.7.0.0 seems to have picked. So, we're getting some formatting diffs when we trade pull requests. 🥲

mitchellwrosen avatar May 03 '22 23:05 mitchellwrosen

Can't you just use cabal freeze and check in the freeze file?

pepeiborra avatar May 04 '22 08:05 pepeiborra

If there was a freeze file checked into this repo, that would effectively achieve the same result.

Just to clarify - by "you" do you mean "you, Mitchell", or "one"?

mitchellwrosen avatar May 04 '22 12:05 mitchellwrosen

It sounds like your underlying problem is a variant of https://github.com/haskell/haskell-language-server/issues/411 ?

michaelpj avatar May 04 '22 15:05 michaelpj

FWIW I solve this problem at work by building HLS from source and adding constraints: stylish-haskell==<whatever>. So then you know your team is all using the same stuff.

michaelpj avatar May 04 '22 15:05 michaelpj

I think pinning precise versions of underlying tools is a good idea. It may make it harder to get build plans for all GHCs, though...

michaelpj avatar May 04 '22 15:05 michaelpj

@michaelpj Thanks, that's what I started to do, but then I got a little bit stuck and scared due to the requirement to use a different version of HLS for different versions of GHC, all tied together with the haskell-language-server-wrapper.

I'm happy to build everything from source, too, but I could use a bit of guidance :)

I see that after some usage of ghcup to install ghc and hls, I've accumulate these variants:

haskell-language-server-8.10.7
haskell-language-server-8.10.7~1.7.0.0
haskell-language-server-8.6.5
haskell-language-server-8.6.5~1.7.0.0
haskell-language-server-8.8.4
haskell-language-server-8.8.4~1.7.0.0
haskell-language-server-9.0.2
haskell-language-server-9.0.2~1.7.0.0
haskell-language-server-9.2.1
haskell-language-server-9.2.1~1.7.0.0
haskell-language-server-9.2.2
haskell-language-server-9.2.2~1.7.0.0
haskell-language-server-wrapper
haskell-language-server-wrapper-1.7.0.0

Were I to ditch ghcup to install hls, and instead build from source in order to constrain the version of ormolu it depends on, do you happen to know all of the steps required to end up with the right binaries with the right names? Perhaps there is a shell script somewhere in this repo I could run?

Thanks.

mitchellwrosen avatar May 04 '22 16:05 mitchellwrosen

I think ghcup can compile HLS from source with additions to the project file (we use Nix at work, but it depends a lot on your setup).

michaelpj avatar May 04 '22 16:05 michaelpj

If there was a freeze file checked into this repo, that would effectively achieve the same result.

Just to clarify - by "you" do you mean "you, Mitchell", or "one"?

I mean you Mitchell. We cannot use a single freeze file since we want to support a range of ghc versions, and libraries like ghc-lib, ghc-exactprint or retrie are versioned following ghc versions.

We do maintain a selection of stack files that provide deterministic builds, and you can use cabal freeze to "roll your own". But I don't think that we should take it any further than that: deterministic builds are hard and expensive to maintain.

pepeiborra avatar May 04 '22 16:05 pepeiborra

I mean you Mitchell. We cannot use a single freeze file since we want to support a range of ghc versions, and libraries like ghc-lib, ghc-exactprint or retrie are versioned following ghc versions.

We do maintain a selection of stack files that provide deterministic builds, and you can use cabal freeze to "roll your own". But I don't think that we should take it any further than that: deterministic builds are hard and expensive to maintain.

I admit I don't fully grasp what is expensive or hard to maintain about deterministic builds - but I take your word for it. FWIW, in case this changes anything, I am only imagining a frozen set of dependencies for the released version(s) of HLS. That way, everyone using HLS version 1.7.0.0, for example, need look no further than that version string to know whether their software has the same set of transitive dependencies as another user's, no matter if they built from source, or acquired hls from ghcup, or nix, or however else one might go about installing it.

But if that doesn't work, then (just reiterating my previous comment) I think it would be valuable to have some documentation somewhere about how intrepid users might go about getting a working HLS "suite". Because as I mentioned, it's simple enough to to just cabal build this package with a --constraint flag or two, but I'm a bit lost when it comes to building HLS once per GHC version, and getting everything aligned correctly for use via the haskell-language-server-wrapper executable.

mitchellwrosen avatar May 04 '22 21:05 mitchellwrosen

We already produce cabal.project.freeze files in CI, although they are only ephemeral. It would be trivial to output them as CI artifacts, and then they can be bundled with HLS binary releases or similar.

If this is something that would be useful to you, by all means send a PR! This is where CI calls cabal freeze:

https://github.com/haskell/haskell-language-server/blob/9195eb636d6a40d36129bce948bdee58a89eeae8/.github/actions/setup-build/action.yml#L122-L129

pepeiborra avatar May 04 '22 23:05 pepeiborra

We already produce cabal.project.freeze files in CI, although they are only ephemeral. It would be trivial to output them as CI artifacts, and then they can be bundled with HLS binary releases or similar.

I'm currently trying to debug a plugin regression, and this would have been very useful to have!

georgefst avatar Sep 14 '22 18:09 georgefst

For most of the plugins that depend on external tools, you can now see which version using haskell-language-server --list-plugins.

michaelpj avatar Jan 16 '24 17:01 michaelpj