diff --git a/haskell/import.bzl b/haskell/import.bzl deleted file mode 100644 index a79a9cff7..000000000 --- a/haskell/import.bzl +++ /dev/null @@ -1,118 +0,0 @@ -"""Importing prebuilt packages into bazel""" - -load("@bazel_skylib//lib:paths.bzl", "paths") -load( - "@io_tweag_rules_haskell//haskell:providers.bzl", - "HaddockInfo", - "HaskellInfo", - "HaskellLibraryInfo", - "empty_HaskellCcInfo", -) -load(":private/context.bzl", "haskell_context") -load(":private/path_utils.bzl", "copy_all", "link_forest", "ln") -load(":private/set.bzl", "set") -load(":private/version_macros.bzl", "generate_version_macros") - -def _haskell_import_impl(ctx): - hs = haskell_context(ctx) - - package_cache = ctx.actions.declare_file( - paths.join("package.conf.d", "package.cache"), - ) - - local_package_confs = link_forest( - ctx = ctx, - srcs = ctx.attr.package_confs.files, - sibling = package_cache, - ) - - local_haddock_html = ctx.actions.declare_directory("haddock-html") - copy_all( - ctx = ctx, - srcs = ctx.attr.haddock_html.files, - dest = local_haddock_html, - ) - - ctx.actions.run( - outputs = [package_cache], - inputs = local_package_confs, - mnemonic = "HaskellCreatePackageCache", - executable = hs.tools.ghc_pkg, - arguments = [ - "recache", - "--package-db", - package_cache.dirname, - ], - ) - ln(ctx, package_cache, ctx.outputs.cache) - - dependencies_caches = set.singleton(package_cache) - for dep in ctx.attr.deps: - if HaskellInfo in dep: - set.mutable_union(dependencies_caches, dep[HaskellInfo].package_databases) - - deps_ids = [ - dep[HaskellLibraryInfo].package_id - for dep in ctx.attr.deps - if HaskellLibraryInfo in dep - ] - - version_macros = set.empty() - if ctx.attr.version != None: - version_macros = set.singleton( - generate_version_macros(ctx, hs.name, ctx.attr.version), - ) - - libInfo = HaskellLibraryInfo( - package_id = ctx.attr.package_id, - version = ctx.attr.version, - ) - buildInfo = HaskellInfo( - package_ids = set.from_list([ctx.attr.package_id] + deps_ids), - package_databases = dependencies_caches, - version_macros = version_macros, - import_dirs = [], - source_files = set.empty(), - extra_source_files = set.empty(), - static_libraries = [], - static_libraries_prof = [], - dynamic_libraries = set.empty(), - interface_dirs = set.empty(), - compile_flags = [], - prebuilt_dependencies = set.empty(), - direct_prebuilt_deps = set.empty(), - cc_dependencies = empty_HaskellCcInfo(), - transitive_cc_dependencies = empty_HaskellCcInfo(), - ) - html_files = ctx.attr.haddock_html.files.to_list() - transitive_html = {ctx.attr.package_id: local_haddock_html} if html_files != [] else {} - interface_files = ctx.attr.haddock_interfaces.files.to_list() - transitive_haddocks = {ctx.attr.package_id: interface_files[0]} if interface_files != [] else {} - - haddockInfo = HaddockInfo( - package_id = ctx.attr.package_id, - transitive_html = transitive_html, - transitive_haddocks = transitive_haddocks, - ) - return [buildInfo, libInfo, haddockInfo] - -haskell_import = rule( - _haskell_import_impl, - attrs = dict( - package_id = attr.string(doc = "Workspace unique package identifier"), - deps = attr.label_list(doc = "Haskell dependencies for the package"), - version = attr.string(doc = "Package version."), - haddock_interfaces = attr.label(doc = "List of haddock interfaces"), - haddock_html = attr.label(doc = "List of haddock html dirs"), - package_confs = attr.label(doc = "List of ghc-pkg package.conf files"), - _version_macros = attr.label( - executable = True, - cfg = "host", - default = Label("@io_tweag_rules_haskell//haskell:version_macros"), - ), - ), - outputs = { - "cache": "%{name}-cache", - }, - toolchains = ["@io_tweag_rules_haskell//haskell:toolchain"], -) diff --git a/haskell/nix/default.nix b/haskell/nix/default.nix deleted file mode 100644 index d32f55862..000000000 --- a/haskell/nix/default.nix +++ /dev/null @@ -1,119 +0,0 @@ -/** - Generate a bazel-friendly nix package containing - - The haskell package itself - - Its documentation - - A bazel file ready to be loaded from the `BUILD` file and containing the - right call to `haskell_import` -*/ -{ runCommand, lib, writeTextDir, symlinkJoin }: -let - /* Generate the BUILD file for the package */ - genBuildFile = - { package_name, package, ghc }: - runCommand "${package_name}-BUILD" { - preferLocalBuild = true; - allowSubstitutes = false; - ghc_pkg = "${ghc}/bin/ghc-pkg --simple-output -v0"; - GHC_PACKAGE_PATH = "${package}/lib/${ghc.name}/package.conf.d"; - inherit package_name; - } '' - query_field () { - $ghc_pkg field ${package_name} "$@" - } - - query_haddock () { - echo -n '[' - for FIELD in $(query_field "$@"); do - echo -n "\"$(echo "$FIELD" | cut -d/ -f5-)*\"," - echo -n "\"$(echo "$FIELD" | cut -d/ -f5-)/*\"," - done - echo -n ']' - } - - query_list () { - echo -n '[' - for FIELD in $(query_field "$@"); do - echo -n '"' - echo -n $(echo "$FIELD" | cut -d/ -f5-) - echo -n '",' - done - echo -n ']' - } - - get_deps () { - echo -n '[' - for DEP in $(query_field depends); do - DEPNAME=$(echo $DEP | sed 's/-[0-9].*//') - # Because of cabal's "internal libraries", we may have a package - # apparently depending on itself, so we have to filter out this - # corner-case (see - # https://github.com/tweag/rules_haskell/pull/442#discussion_r219859467) - if [[ -n $DEPNAME && $DEPNAME != $(query_field name) ]]; then - echo -n "\"@hackage-$DEPNAME\"," - fi - done - echo -n ']' - } - - mkdir -p $out - cat < $out/BUILD.bzl - load("@io_tweag_rules_haskell//haskell:import.bzl", haskell_import_new = "haskell_import") - deps_repos = $(get_deps) - - def targets(): - - haskell_import_new( - name = "pkg", - deps = [ dep + "//:pkg" for dep in deps_repos], - package_id = "$(query_field id)", - version = "$(query_field version)", - package_confs = "//:package_conf", - haddock_interfaces = "//:interfaces", - haddock_html = "//:html", - ) - native.filegroup( - name = "html", - srcs = native.glob($(query_haddock haddock-html), exclude_directories=1), - ) - native.filegroup( - name = "interfaces", - srcs = native.glob($(query_haddock haddock-interfaces), exclude_directories=0), - ) - native.filegroup( - name = "bin", - srcs = native.glob(["bin/*"]), - ) - native.filegroup( - name = "package_conf", - srcs = native.glob(["lib*/${ghc.name}/package.conf.d/$(query_field name)*.conf"]), - ) - EOF - ''; - genAllBuilds = pkgSet: - let newSet = - lib.mapAttrs (package_name: package: - let - # Some nix packages are actually `null` because the haskell package is - # bundled with ghc (so it doesn't have a custom derivation of its own). - # For these, we simply pass the ghc derivation instead of theirs. - real_package = if builtins.isNull package then pkgSet.ghc else package; - buildFile = genBuildFile { - inherit (pkgSet) ghc; - inherit package_name; - package = real_package; - }; - in - symlinkJoin { - name = package_name + "-bazel"; - paths = [ real_package (real_package.doc or null) buildFile ]; - } - ) - pkgSet; - in - newSet // { - packageNames = writeTextDir - "all-haskell-packages.bzl" - ("packages =" + builtins.toJSON (builtins.attrNames newSet)); - }; -in -genAllBuilds diff --git a/haskell/nixpkgs.bzl b/haskell/nixpkgs.bzl index bb505de39..23b350b27 100644 --- a/haskell/nixpkgs.bzl +++ b/haskell/nixpkgs.bzl @@ -1,235 +1,10 @@ """Workspace rules (Nixpkgs)""" -load("@bazel_skylib//lib:dicts.bzl", "dicts") load( "@io_tweag_rules_nixpkgs//nixpkgs:nixpkgs.bzl", "nixpkgs_package", ) -def haskell_nixpkgs_package( - name, - attribute_path, - nix_file_deps = [], - repositories = {}, - build_file_content = None, - build_file = None, - **kwargs): - """Load a single haskell package. - The package is expected to be in the form of the packages generated by - `genBazelBuild.nix` - """ - repositories = dicts.add( - {"bazel_haskell_wrapper": "@io_tweag_rules_haskell//haskell:nix/default.nix"}, - repositories, - ) - - nixpkgs_args = dict( - name = name, - attribute_path = attribute_path, - build_file_content = build_file_content, - nix_file_deps = nix_file_deps + ["@io_tweag_rules_haskell//haskell:nix/default.nix"], - repositories = repositories, - **kwargs - ) - - if build_file_content: - nixpkgs_args["build_file_content"] = build_file_content - elif build_file: - nixpkgs_args["build_file"] = build_file - else: - nixpkgs_args["build_file_content"] = """ -package(default_visibility = ["//visibility:public"]) -load("@io_tweag_rules_haskell//haskell:import.bzl", haskell_import_new = "haskell_import") - -load(":BUILD.bzl", "targets") -targets() -""" - - nixpkgs_package( - **nixpkgs_args - ) - -def _bundle_impl(repository_ctx): - build_file_content = """ -package(default_visibility = ["//visibility:public"]) - """ - for package in repository_ctx.attr.packages: - build_file_content += """ -alias( - name = "{package}", - actual = "@{base_repo}-{package}//:pkg", -) - """.format( - package = package, - base_repo = repository_ctx.attr.base_repository, - ) - repository_ctx.file("BUILD", build_file_content) - -_bundle = repository_rule( - attrs = { - "packages": attr.string_list(), - "base_repository": attr.string(), - }, - implementation = _bundle_impl, -) -""" -Generate an alias from `@base_repo//:package` to `@base_repo-package//:pkg` for -each one of the input package -""" - -def haskell_nixpkgs_packages(name, base_attribute_path, packages, **kwargs): - """Import a set of haskell packages from nixpkgs. - - This takes as input the same arguments as - [nixpkgs_package](https://github.com/tweag/rules_nixpkgs#nixpkgs_package), - expecting the `attribute_path` to resolve to a set of haskell packages - (such as `haskellPackages` or `haskell.packages.ghc822`) preprocessed by - the `genBazelBuild` function. It also takes as input a list of packages to - import (which can be generated by the `gen_packages_list` function). - """ - for package in packages: - haskell_nixpkgs_package( - name = name + "-" + package, - attribute_path = base_attribute_path + "." + package, - **kwargs - ) - _bundle( - name = name, - packages = packages, - base_repository = name, - ) - -def _is_nix_platform(repository_ctx): - return repository_ctx.which("nix-build") != None - -def _gen_imports_impl(repository_ctx): - repository_ctx.file("BUILD", "") - extra_args_raw = "" - for foo, bar in repository_ctx.attr.extra_args.items(): - extra_args_raw += foo + " = " + bar + ", " - bzl_file_content = """ -load("{repo_name}", "packages") -load("@io_tweag_rules_haskell//haskell:nixpkgs.bzl", "haskell_nixpkgs_packages") - -def import_packages(name): - haskell_nixpkgs_packages( - name = name, - packages = packages, - {extra_args_raw} - ) - """.format( - repo_name = repository_ctx.attr.packages_list_file, - extra_args_raw = extra_args_raw, - ) - - # A dummy 'packages.bzl' file with a no-op 'import_packages()' on unsupported platforms - bzl_file_content_unsupported_platform = """ -def import_packages(name): - return - """ - if _is_nix_platform(repository_ctx): - repository_ctx.file("packages.bzl", bzl_file_content) - else: - repository_ctx.file("packages.bzl", bzl_file_content_unsupported_platform) - -_gen_imports_str = repository_rule( - implementation = _gen_imports_impl, - attrs = dict( - packages_list_file = attr.label(doc = "A list containing the list of packages to import"), - # We pass the extra arguments to `haskell_nixpkgs_packages` as strings - # since we can't forward arbitrary arguments in a rule and they will be - # converted to strings anyways. - extra_args = attr.string_dict(doc = "Extra arguments for `haskell_nixpkgs_packages`"), - ), -) -""" -Generate a repository containing a file `packages.bzl` which imports the given -packages list. -""" - -def _gen_imports(name, packages_list_file, extra_args): - """ - A wrapper around `_gen_imports_str` which allows passing an arbitrary set of - `extra_args` instead of a set of strings - """ - extra_args_str = {label: repr(value) for (label, value) in extra_args.items()} - _gen_imports_str( - name = name, - packages_list_file = packages_list_file, - extra_args = extra_args_str, - ) - -def haskell_nixpkgs_packageset(name, base_attribute_path, repositories = {}, **kwargs): - """Import all the available haskell packages. - The arguments are the same as the arguments of ``nixpkgs_package``, except - for the ``base_attribute_path`` which should point to an `haskellPackages` - set in the nix expression - - Example: - - In `haskellPackages.nix`: - - ```nix - with import {}; - - let wrapPackages = callPackage { }; in - { haskellPackages = wrapPackages haskell.packages.ghc822; } - ``` - - In your `WORKSPACE` - - ```bazel - # Define a nix repository to fetch the packages from - load("@io_tweag_rules_nixpkgs//nixpkgs:nixpkgs.bzl", - "nixpkgs_git_repository") - nixpkgs_git_repository( - name = "nixpkgs", - revision = "9a787af6bc75a19ac9f02077ade58ddc248e674a", - ) - - load("@io_tweag_rules_haskell//haskell:nixpkgs.bzl", - "haskell_nixpkgs_packageset", - - # Generate a list of all the available haskell packages - haskell_nixpkgs_packageset( - name = "hackage-packages", - repositories = {"@nixpkgs": "nixpkgs"}, - nix_file = "//haskellPackages.nix", - base_attribute_path = "haskellPackages", - ) - load("@hackage-packages//:packages.bzl", "import_packages") - import_packages(name = "hackage") - ``` - - Then in your `BUILD` files, you can access to the whole of hackage as - `@hackage//:{your-package-name}` - """ - - repositories = dicts.add( - {"bazel_haskell_wrapper": "@io_tweag_rules_haskell//haskell:nix/default.nix"}, - repositories, - ) - - nixpkgs_package( - name = name + "-packages-list", - attribute_path = base_attribute_path + ".packageNames", - repositories = repositories, - build_file_content = """ -exports_files(["all-haskell-packages.bzl"]) - """, - fail_not_supported = False, - **kwargs - ) - _gen_imports( - name = name, - packages_list_file = "@" + name + "-packages-list//:all-haskell-packages.bzl", - extra_args = dict( - repositories = repositories, - base_attribute_path = base_attribute_path, - **kwargs - ), - ) - def _ghc_nixpkgs_haskell_toolchain_impl(repository_ctx): compiler_flags_select = "select({})".format( repository_ctx.attr.compiler_flags_select or {