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

stack_snapshot: Precise extra dependencies #1068

Merged
merged 4 commits into from Sep 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Expand Up @@ -6,7 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).

## Upcoming release

nothing yet
### Changed

* The `deps` attribute to `stack_snapshot` has been replaced by the
`extra_deps` attribute. It no longer takes a list of dependencies to be added
to all packages, but instead a dictionary specifying additional dependencies
to select packages. See `stack_snapshot` API docs for an example. See
[#1068](https://github.com/tweag/rules_haskell/pull/1068).

## [0.10.0] - 2019-09-03

Expand Down
2 changes: 1 addition & 1 deletion WORKSPACE
Expand Up @@ -75,9 +75,9 @@ stack_snapshot(
# In a separate repo because not all platforms support zlib.
stack_snapshot(
name = "stackage-zlib",
extra_deps = {"zlib": ["@zlib.win//:zlib" if is_windows else "@zlib.dev//:zlib"]},
packages = ["zlib"],
snapshot = "lts-13.15",
deps = ["@zlib.win//:zlib" if is_windows else "@zlib.dev//:zlib"],
)

load(
Expand Down
2 changes: 1 addition & 1 deletion examples/WORKSPACE
Expand Up @@ -77,6 +77,7 @@ load("@rules_haskell//haskell:cabal.bzl", "stack_snapshot")

stack_snapshot(
name = "stackage",
extra_deps = {"zlib": ["@zlib.dev//:zlib"]},
flags = {
# Sets the default explicitly to demonstrate the flags attribute.
"zlib": [
Expand All @@ -96,7 +97,6 @@ stack_snapshot(
],
snapshot = "lts-14.0",
vendored_packages = {"split": "@split//:split"},
deps = ["@zlib.dev//:zlib"],
)

# For the rts example.
Expand Down
49 changes: 40 additions & 9 deletions haskell/cabal.bzl
Expand Up @@ -719,6 +719,31 @@ def _invert(d):
"""Invert a dictionary."""
return dict(zip(d.values(), d.keys()))

def _from_string_keyed_label_list_dict(d):
aherrmann marked this conversation as resolved.
Show resolved Hide resolved
"""Convert string_keyed_label_list_dict to label_keyed_string_dict."""

# TODO Remove _from_string_keyed_label_list_dict once following issue
# is resolved: https://github.com/bazelbuild/bazel/issues/7989.
out = {}
for (string_key, label_list) in d.items():
for label in label_list:
if label in out:
out[label] += " " + string_key
else:
out[label] = string_key
return out

def _to_string_keyed_label_list_dict(d):
"""Convert label_keyed_string_dict to string_keyed_label_list_dict."""

# TODO Remove _to_string_keyed_label_list_dict once following issue
# is resolved: https://github.com/bazelbuild/bazel/issues/7989.
out = {}
for (label, string_key_list) in d.items():
for string_key in string_key_list.split(" "):
out.setdefault(string_key, []).append(label)
return out

def _label_to_string(label):
return "@{}//{}:{}".format(label.workspace_name, label.package, label.name)

Expand Down Expand Up @@ -757,7 +782,7 @@ def _stack_snapshot_impl(repository_ctx):
vendored_packages,
)

extra_deps = [_label_to_string(label) for label in repository_ctx.attr.deps]
extra_deps = _to_string_keyed_label_list_dict(repository_ctx.attr.extra_deps)
tools = [_label_to_string(label) for label in repository_ctx.attr.tools]

# Write out dependency graph as importable Starlark value.
Expand Down Expand Up @@ -829,7 +854,10 @@ haskell_cabal_library(
version = package.version,
flags = package.flags,
dir = package.sdist,
deps = package.deps + extra_deps,
deps = package.deps + [
_label_to_string(label)
for label in extra_deps.get(package.name, [])
],
tools = tools,
visibility = visibility,
),
Expand All @@ -853,7 +881,7 @@ _stack_snapshot = repository_rule(
"packages": attr.string_list(),
"vendored_packages": attr.label_keyed_string_dict(),
"flags": attr.string_list_dict(),
"deps": attr.label_list(),
"extra_deps": attr.label_keyed_string_dict(),
"tools": attr.label_list(),
"stack": attr.label(),
},
Expand Down Expand Up @@ -932,7 +960,7 @@ _fetch_stack = repository_rule(
)
"""Find a suitably recent local Stack or download it."""

def stack_snapshot(stack = None, vendored_packages = {}, **kwargs):
def stack_snapshot(stack = None, extra_deps = {}, vendored_packages = {}, **kwargs):
"""Use Stack to download and extract Cabal source distributions.

Args:
Expand All @@ -945,7 +973,7 @@ def stack_snapshot(stack = None, vendored_packages = {}, **kwargs):
unpacked source distribution. Each package must contain a Cabal file
named `<package-name>.cabal` in the package root.
flags: A dict from package name to list of flags.
deps: Dependencies of the package set, e.g. system libraries or C/C++ libraries.
extra_deps: Extra dependencies of packages, e.g. system libraries or C/C++ libraries.
tools: Tool dependencies. They are built using the host configuration, since
the tools are executed as part of the build.
stack: The stack binary to use to enumerate package dependencies.
Expand All @@ -959,7 +987,7 @@ def stack_snapshot(stack = None, vendored_packages = {}, **kwargs):
vendored_packages = {"split": "//split:split"},
tools = ["@happy//:happy", "@c2hs//:c2hs"],
snapshot = "lts-13.15",
deps = ["@zlib.dev//:zlib"],
extra_deps = {"zlib": ["@zlib.dev//:zlib"]},
)
```
defines `@stackage//:conduit`, `@stackage//:lens`,
Expand All @@ -973,7 +1001,7 @@ def stack_snapshot(stack = None, vendored_packages = {}, **kwargs):
flags = {"zlib": ["-non-blocking-ffi"]},
tools = ["@happy//:happy", "@c2hs//:c2hs"],
local_Snapshot = "//:snapshot.yaml",
deps = ["@zlib.dev//:zlib"],
extra_deps = {"zlib": ["@zlib.dev//:zlib"]},
```
Does the same as the previous example, provided there is a
`snapshot.yaml`, at the root of the repository with content
Expand All @@ -987,8 +1015,8 @@ def stack_snapshot(stack = None, vendored_packages = {}, **kwargs):
This rule will use Stack to compute the transitive closure of the
subset of the given snapshot listed in the `packages` attribute, and
generate a dependency graph. If a package in the closure depends on
system libraries or other external libraries, use the `deps` attribute
to list them. This attribute works like the
system libraries or other external libraries, use the `extra_deps`
attribute to list them. This attribute works like the
`--extra-{include,lib}-dirs` flags for Stack and cabal-install do.

Packages that are in the snapshot need not have their versions
Expand All @@ -1010,6 +1038,9 @@ def stack_snapshot(stack = None, vendored_packages = {}, **kwargs):
stack = Label("@rules_haskell_stack//:stack")
_stack_snapshot(
stack = stack,
# TODO Remove _from_string_keyed_label_list_dict once following issue
# is resolved: https://github.com/bazelbuild/bazel/issues/7989.
extra_deps = _from_string_keyed_label_list_dict(extra_deps),
# TODO Remove _invert once following issue is resolved:
# https://github.com/bazelbuild/bazel/issues/7989.
vendored_packages = _invert(vendored_packages),
Expand Down