-
Notifications
You must be signed in to change notification settings - Fork 81
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_install #887
Add stack_install #887
Conversation
With `haskell_cabal_library` (added in #882), we have the ability to make one-shot calls to Cabal, assuming, 1. that the sdist for the Cabal package has been fetched and unpacked, and 2. that dependencies have been declared correctly. Declaring these dependencies by hand for all packages on Hackage is a fool's errand. This commit uses Stack to, 1. resolve package names to package versions using the given snapshot, 2. fetch the sdist and unpack it, 3. find out the dependency graph and generate a `BUILD` file encoding it. Stack only outputs dependency information in GraphViz format. So have to parse that. This assumes Stack is in the `PATH` (hence build is non-hermetic). But it's pretty unreasonable to build our own Stack inside a workspace rule (Bazel's build engine doesn't work there). The best we can do is download prebuilt binaries, which we can do in the future (after figuring out how to seamlessly work on NixOS). Closes #874.
This commit removes all use of the "new" `haskell_import` based mechanism and the Nixpkgs code to support it. This is effectively a revert of #442. The new stack_install mechanism is not Nixpkgs specific and has better performance characteristics.
2984010
to
7912560
Compare
haskell/cabal.bzl
Outdated
_execute_or_fail_loudly(repository_ctx, stack + ["unpack"] + unversioned_packages) | ||
exec_result = _execute_or_fail_loudly(repository_ctx, ["ls"]) | ||
unpacked_sdists = exec_result.stdout.splitlines() | ||
stack_yaml_content = "\n".join(["resolver: none", "packages:"]) + "\n" + "\n".join([ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be cleaner and easier to read to use to_json rather than writing the yaml file by hand?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea. Will try that.
It seems that even at the 5th point release, GHC still has packaging bugs on Windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
I have absolutely zero objection to the removal of haskell_import_new
, I don't think we could reasonably make it work efficiently enough (and I don't think there's any user of it left now that I've switched back to a plain ghcWithPackages
).
I just have two (minor) concerns:
- With this approach, we still have to explicitely list all our dependencies in the
WORKSPACE
file (though I assume any attempt at lifting this would result in a need of a "load a generated file" thing in the workspace which is always painful) - The external dependencies are shared amongst all the packages, which means that adding a new one will require rebuilding the whole dependency set
|
||
haskell_nixpkgs_package( | ||
nixpkgs_package( | ||
name = "ghc", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ghc.nix
file pinned the ghc version regardless of the nixpkgs version used, which we don't do anymore by using whichever ghc nixpkgs
provides us. Is that intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is hard to achive in practice: Nixpkgs is pretty aggressive about prunning old minor releases when a new one comes out. Either way we're still just as reproducible.
import TH (foo) | ||
|
||
-- | Doc for 'x' using 'f' and 'a' and 'Int'. | ||
x :: Int | ||
x = const f a | ||
|
||
-- | This uses a type from an undocumented package |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we remove a potentially useful test here?
I assume that's because we can't easily extend the stackage snapshot whith some lib which isn't on hackage but maybe we could use an existing library with no documentation instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are. But the value of the test needs to be measured against the cost of migrating it. It's quite difficult.
maybe we could use an existing library with no documentation instead
Good idea. If you can find one then we could revive this test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
I have added a number of questions. But they're mostly about future direction of this feature, and out of scope for this PR.
) | ||
""", | ||
repository = "@nixpkgs", | ||
) | ||
|
||
nixpkgs_package( | ||
name = "c2hs", | ||
attribute_path = "haskellPackages.c2hs", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why pull these from nixpkgs rather than stackage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we don't yet have haskell_cabal_binary
.
"time", | ||
"transformers", | ||
"unix", | ||
"xhtml", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interestingly hazel/packages.bzl
does not list xhtml
as a core-package. Did this change between stackage releases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
xhtml has been a core library for a long time. Probably an omission in Hazel. Or maybe an omission in Stackage.
stack = [stack_cmd, "--no-nix", "--skip-ghc-check", "--system-ghc"] | ||
if versioned_packages: | ||
_execute_or_fail_loudly(repository_ctx, stack + ["unpack"] + versioned_packages) | ||
stack = [stack_cmd, "--no-nix", "--skip-ghc-check", "--system-ghc", "--resolver", repository_ctx.attr.snapshot] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is a repository rule this just picks whatever ghc
is in $PATH
, correct? Does this have any impact on the generated dependency graph? E.g. conditional dependencies based on the ghc
version, or similar? If so then this seems like another iteration of FormationAI/hazel#80.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nice thing about using Stackage is that in principle they deal with this for us, provided we stick to using the same GHC version as Stackage does for any given snapshot.
tokens = [w.strip('";') for w in line.split(" ")] | ||
|
||
# All lines of the form `"foo" -> "bar";` declare edges of the | ||
# dependency graph in the Graphviz format. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great if stack could spit this out in a more robust and easier parseable format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. I'll file a ticket upstream.
|
||
def _compute_dependency_graph(repository_ctx, versioned_packages, unversioned_packages): | ||
"""Given a list of root packages, compute a dependency graph. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understand it this does not just return the dependency graph of the transitive closure of the requested packages, but of all of Stackage, correct? That's probably fine, but not very clear from the docstring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No not all of Stackage. It computes only the transitive closure.
@@ -16,6 +16,9 @@ mkShell { | |||
perl | |||
python3 | |||
bazel | |||
# For stack_install. TODO Remove ghc when move to Stack 2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does Stack 2 improve in this respect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It generates the dependency graph without the spurious requirement that GHC be in the environment.
build_file_content = "\n".join(build_file_builder) | ||
repository_ctx.file("BUILD.bazel", build_file_content, executable = False) | ||
|
||
stack_install = repository_rule( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comparing to Hazel, here are a few things that come to mind which stack_install
and haskell_cabal_library
don't seem to offer, yet. Those might be good future extensions.
- Override individual packages with custom Bazel builds. Probably easiest by injecting a mapping from package name to Bazel targets.
- Stack's
extra-deps
feature to override a package version or just it's source repository. Also to add additional Hackage packages, or packages from other sources. - Apply source patches. This is very useful if a package just requires minor adjustment to build within Bazel. E.g. file paths to embedded data files. In such cases a full fork imposes a lot of overhead.
- Overriding cabal flags. E.g.
integer-simpl
vs.integer-gmp
. - Binary targets. As I understand
haskell_cabal_library
does currently not expose any binary targets. I suspect this has two consequences. A) Users cannot use e.g. a Stackage providedc2hs
. B) Stackage packages that depend on other Stackage packages' binaries, e.g.happy
, will probably not work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Override individual packages with custom Bazel builds.
Not currently possible, but it's possible to override the version at least.
Stack's extra-deps feature to override a package version or just it's source repository.
See above. Not possible to override with one's own source repository. Good future feature.
Also to add additional Hackage packages, or packages from other sources.
Outside of the cases listed above, these wouldn't be part of the transitive closure, right? So don't need to be part of the stackage
external repository?
Apply source patches ... Overriding cabal flags ... Binary targets
Agreed. Let's create tickets about those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stack's extra-deps feature [...]
I haven't tested any of these new features yet, however in practice one can make a custom snapshot file, host it remotely, and point stack
to it (e.g. stack build --resolver=<link_to_snapshot.>
).
Depending on how rules_haskell
and stack
interact here, this could be a neat workaround for extra-deps
at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, so you're saying #910 could be unnecessary? It hasn't been merged yet. Not too late to block it. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I can't say for sure, since I've been unable to get the quickstart instructions for rules_haskell
working on macOS; I'm basing this purely off of my knowledge of how stack
treats resolvers.
I do think that having something like #910 would probably be useful, regardless of this, though. I just wanted to suggest it just in case it actually did work, and could help unblock someone in the meantime 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a singular point missing in our CI matrix currently, which I guess is the point you're in: macOS + ghc bindists (as opposed to GHC-from-Nixpkgs).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, either what you mention (à la Hazel), or we could just download all packages in the snapshot. In fact I'm pondering making it so that if no
That's true. See discussion with @aherrmann above. This seems inevitable to me given a design flaw in Cabal. But we could consider trying to do better. I'm just not sure it'll pan out all that well. |
With
haskell_cabal_library
(added in #882), we have the ability to makeone-shot calls to Cabal, assuming,
Declaring these dependencies by hand for all packages on Hackage is a
fool's errand. This commit uses Stack to,
BUILD
file encoding it.Stack only outputs dependency information in GraphViz format. So have to
parse that.
This assumes Stack is in the
PATH
(hence build is non-hermetic). But it'spretty unreasonable to build our own Stack inside a workspace rule (Bazel's
build engine doesn't work there). The best we can do is download prebuilt
binaries, which we can do in the future (after figuring out how to
seamlessly work on NixOS).
BTW @snoyberg: I noticed the upcoming
--global-hints
feature ofStack is marked as "experimental" and "could be removed". Just FTR
that will be a very useful feature for us (we'll be able to generate
a dependency graph without first downloading a GHC toolchain).
@regnat this PR removes the "new-style"
haskell_import
rule. We nowno longer need that rule in the tests and I believe no one else is
using it either.
Closes #874.