-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathapi.nix
138 lines (127 loc) · 4.14 KB
/
api.nix
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
{ lib, stdenv, pkgs, makeSetupHook, opam2nix }:
with builtins;
with lib;
let
isPseudo = impl: elem (typeOf impl) ["null" "bool"];
nonPseudoList = filter (impl: !isPseudo impl);
nonPseudoAttrs = filterAttrs (name: impl: !isPseudo impl);
noopOverride = {}: {};
in
rec {
resolve = {
ocaml,
selection,
# NOTE: these aren't used, but are explicitly allowed for compatibility with `build` / `buildInputs`
override ? null,
builtinOverride ? null,
src ? null,
}: args: let
in pkgs.mkShell {
buildInputs = [ opam2nix ];
shellHook = ''
opam2nix resolve \
--dest ${builtins.toString selection} \
--ocaml-version ${ocaml.version} \
${lib.concatStringsSep " " (map (arg: "'${builtins.toString arg}'") args)}
{ exit $?; } 2>/dev/null
'';
};
build = { selection, ocaml,
override ? noopOverride,
builtinOverride ? ./overrides,
src ? false
}: let
# src can either be a plain attribute set, in which case we lookup each
# direct source by name. If it's a plain object (path or derivation),
# we use it for all (presumably just one) direct sources.
directSrc = name:
let
validate = src: if src == false
then abort "Source for direct package `${name}` not provided in `src` argument"
else src;
getAttrOrNull = name: attrs: if hasAttr name attrs then getAttr name attrs else null;
isDrv = hasAttr "outPath"; # builtins.fetchgit isn't a true derivation but has outPath
in
validate (if isAttrs src && !isDrv src
then getAttrOrNull name src
else src);
self = {
inherit lib pkgs repoPath directSrc;
selection = finalSelection;
};
depFn = if isFunction selection then selection else import selection;
imported = let raw = depFn self; in
if raw.ocaml-version != ocaml.version then
warn ("Dependencies were selected for ocaml version ${raw.ocaml-version}" +
" but you are building with ${ocaml.version}") raw
else raw;
repoPath = repo: { package, hash }:
stdenv.mkDerivation {
outputHash = hash;
outputHashMode = "recursive";
name = "opam";
buildCommand = ''
cp -r "${repo}/${package}" "$out";
chmod u+w "$out"
'';
};
initOverride = pkgs.newScope {
inherit opam2nix ocaml;
selection = finalSelection;
};
applyOverride = override: selection:
let overrideAttrs = initOverride override {}; in
mapAttrs (name: base:
if hasAttr name overrideAttrs
then (getAttr name overrideAttrs) base
else base
) selection;
opam2nixHooks = makeSetupHook { name = "ocaml-path-hooks"; } (pkgs.writeText "setupHook.sh" ''
function ocamlPathSetup {
local libPath="lib/ocaml/${ocaml.version}/site-lib"
local libdir="$1/$libPath"
if test -d "$libdir"; then
export OCAMLPATH="''${OCAMLPATH:+$OCAMLPATH:}$libdir"
if test -d "$libdir/stublibs"; then
export CAML_LD_LIBRARY_PATH="''${CAML_LD_LIBRARY_PATH:+$CAML_LD_LIBRARY_PATH:}$libdir/stublibs"
else
export CAML_LD_LIBRARY_PATH="''${CAML_LD_LIBRARY_PATH:+$CAML_LD_LIBRARY_PATH:}$libdir"
fi
fi
export OCAMLFIND_DESTDIR="$out/$libPath"
}
addEnvHooks "$targetOffset" ocamlPathSetup
'');
invoke = "${opam2nix}/bin/opam2nix invoke";
builtSelection = ({ inherit ocaml; }) // (mapAttrs (name: args:
if isPseudo args then args else stdenv.mkDerivation (
{
inherit (args) pname version src opamSrc;
propagatedBuildInputs = [ocaml opam2nix opam2nixHooks] ++ (
nonPseudoList ((args.buildInputs or []) ++ (attrValues args.opamInputs))
);
prePatch = "${invoke} patch";
buildPhase = "${invoke} build";
configurePhase = "true";
installPhase = "${invoke} install";
opamEnv = builtins.toJSON {
inherit (args) version;
name = args.pname;
deps = mapAttrs (name: impl:
if isPseudo impl then impl else {
path = impl;
inherit (impl) version;
}
) ({ inherit ocaml; } // args.opamInputs);
};
}
// (if args.src == null then { unpackPhase = "true"; } else {})
// (args.drvAttrs or {})
)) imported.selection);
finalSelection = applyOverride override (
applyOverride ./overrides builtSelection
);
in
nonPseudoAttrs finalSelection;
buildInputs = args: attrValues (build args);
}