summary refs log tree commit diff
path: root/third_party/bazel/rules_haskell/haskell/nix/default.nix
blob: d32f558625c4926b2a12ac9ecd97f80befee2bd5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
  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 <<EOF > $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