1# Generic builder for lua packages
2{ lib
3, lua
4, wrapLua
5, luarocks
6
7# Whether the derivation provides a lua module or not.
8, luarocksCheckHook
9, luaLib
10}:
11
12{ pname
13, version
14# we need rockspecVersion to find the .rockspec even when version changes
15, rockspecVersion ? version
16
17# by default prefix `name` e.g. "lua5.2-${name}"
18, namePrefix ? "${lua.pname}${lib.versions.majorMinor lua.version}-"
19
20# Dependencies for building the package
21, buildInputs ? []
22
23# Dependencies needed for running the checkPhase.
24# These are added to nativeBuildInputs when doCheck = true.
25, nativeCheckInputs ? []
26
27# propagate build dependencies so in case we have A -> B -> C,
28# C can import package A propagated by B
29, propagatedBuildInputs ? []
30
31# used to disable derivation, useful for specific lua versions
32# TODO move from this setting meta.broken to a 'disabled' attribute on the
33# package, then use that to skip/include in each lua${ver}Packages set?
34, disabled ? false
35
36# Additional arguments to pass to the makeWrapper function, which wraps
37# generated binaries.
38, makeWrapperArgs ? []
39
40# Skip wrapping of lua programs altogether
41, dontWrapLuaPrograms ? false
42, doCheck ? false
43# Non-Lua / system (e.g. C library) dependencies. Is a list of deps, where
44# each dep is either a derivation, or an attribute set like
45# { name = "rockspec external_dependencies key"; dep = derivation; }
46# The latter is used to work-around luarocks having a problem with
47# multiple-output derivations as external deps:
48# https://github.com/luarocks/luarocks/issues/766<Paste>
49, externalDeps ? []
50
51# Appended to the generated luarocks config
52, extraConfig ? ""
53# Inserted into the generated luarocks config in the "variables" table
54, extraVariables ? {}
55# The two above arguments have access to builder variables -- e.g. to $out
56
57# relative to srcRoot, path to the rockspec to use when using rocks
58, rockspecFilename ? null
59# relative to srcRoot, path to folder that contains the expected rockspec
60, rockspecDir ? "."
61
62# must be set for packages that don't have a rock
63, knownRockspec ? null
64
65, ... } @ attrs:
66
67
68# Keep extra attributes from `attrs`, e.g., `patchPhase', etc.
69
70let
71
72 # TODO fix warnings "Couldn't load rockspec for ..." during manifest
73 # construction -- from initial investigation, appears it will require
74 # upstream luarocks changes to fix cleanly (during manifest construction,
75 # luarocks only looks for rockspecs in the default/system tree instead of all
76 # configured trees)
77 luarocks_config = "luarocks-config.lua";
78
79 luarocksDrv = luaLib.toLuaModule ( lua.stdenv.mkDerivation (self: attrs // {
80
81 name = namePrefix + pname + "-" + self.version;
82 inherit rockspecVersion;
83
84 __structuredAttrs = true;
85 env = {
86 LUAROCKS_CONFIG="$PWD/${luarocks_config}";
87 } // attrs.env or {};
88
89 generatedRockspecFilename = "${rockspecDir}/${pname}-${rockspecVersion}.rockspec";
90
91 nativeBuildInputs = [
92 wrapLua
93 luarocks
94 ];
95
96 inherit doCheck extraVariables rockspecFilename knownRockspec externalDeps nativeCheckInputs;
97
98 buildInputs = let
99 # example externalDeps': [ { name = "CRYPTO"; dep = pkgs.openssl; } ]
100 externalDeps' = lib.filter (dep: !lib.isDerivation dep) self.externalDeps;
101 in [ lua.pkgs.luarocks ]
102 ++ buildInputs
103 ++ lib.optionals self.doCheck ([ luarocksCheckHook ] ++ self.nativeCheckInputs)
104 ++ (map (d: d.dep) externalDeps')
105 ;
106
107 # propagate lua to active setup-hook in nix-shell
108 propagatedBuildInputs = propagatedBuildInputs ++ [ lua ];
109
110 # @-patterns do not capture formal argument default values, so we need to
111 # explicitly inherit this for it to be available as a shell variable in the
112 # builder
113 rocksSubdir = "${self.pname}-${self.version}-rocks";
114 luarocks_content = let
115 externalDepsGenerated = lib.filter (drv: !drv ? luaModule)
116 (self.nativeBuildInputs ++ self.propagatedBuildInputs ++ self.buildInputs);
117 generatedConfig = luaLib.generateLuarocksConfig {
118 externalDeps = lib.unique (self.externalDeps ++ externalDepsGenerated);
119 # Filter out the lua derivation itself from the Lua module dependency
120 # closure, as it doesn't have a rock tree :)
121 # luaLib.hasLuaModule
122 requiredLuaRocks = lib.filter luaLib.hasLuaModule
123 (lua.pkgs.requiredLuaModules (self.nativeBuildInputs ++ self.propagatedBuildInputs));
124 inherit (self) extraVariables rocksSubdir;
125 };
126 in
127 ''
128 ${generatedConfig}
129 ${extraConfig}
130 '';
131
132 configurePhase = ''
133 runHook preConfigure
134
135 cat > ${luarocks_config} <<EOF
136 ${self.luarocks_content}
137 EOF
138 export LUAROCKS_CONFIG="$PWD/${luarocks_config}";
139 cat "$LUAROCKS_CONFIG"
140 ''
141 + lib.optionalString (self.rockspecFilename == null) ''
142 rockspecFilename="${self.generatedRockspecFilename}"
143 ''
144 + lib.optionalString (self.knownRockspec != null) ''
145 # prevents the following type of error:
146 # Inconsistency between rockspec filename (42fm1b3d7iv6fcbhgm9674as3jh6y2sh-luv-1.22.0-1.rockspec) and its contents (luv-1.22.0-1.rockspec)
147 rockspecFilename="$TMP/$(stripHash ${self.knownRockspec})"
148 cp ${self.knownRockspec} "$rockspecFilename"
149 ''
150 + ''
151 runHook postConfigure
152 '';
153
154 buildPhase = ''
155 runHook preBuild
156
157 nix_debug "Using LUAROCKS_CONFIG=$LUAROCKS_CONFIG"
158
159 LUAROCKS_EXTRA_ARGS=""
160 if (( ''${NIX_DEBUG:-0} >= 1 )); then
161 LUAROCKS_EXTRA_ARGS=" --verbose"
162 fi
163
164 runHook postBuild
165 '';
166
167 postFixup = lib.optionalString (!dontWrapLuaPrograms) ''
168 wrapLuaPrograms
169 '' + attrs.postFixup or "";
170
171 installPhase = ''
172 runHook preInstall
173
174 # work around failing luarocks test for Write access
175 mkdir -p $out
176
177 # luarocks make assumes sources are available in cwd
178 # After the build is complete, it also installs the rock.
179 # If no argument is given, it looks for a rockspec in the current directory
180 # but some packages have several rockspecs in their source directory so
181 # we force the use of the upper level since it is
182 # the sole rockspec in that folder
183 # maybe we could reestablish dependency checking via passing --rock-trees
184
185 nix_debug "ROCKSPEC $rockspecFilename"
186 luarocks $LUAROCKS_EXTRA_ARGS make --deps-mode=all --tree=$out ''${rockspecFilename}
187
188 runHook postInstall
189 '';
190
191 checkPhase = ''
192 runHook preCheck
193 luarocks test
194 runHook postCheck
195 '';
196
197 shellHook = ''
198 runHook preShell
199 export LUAROCKS_CONFIG="$PWD/${luarocks_config}";
200 runHook postShell
201 '';
202
203 passthru = {
204 inherit lua;
205 } // attrs.passthru or { };
206
207 meta = {
208 platforms = lua.meta.platforms;
209 # add extra maintainer(s) to every package
210 maintainers = (attrs.meta.maintainers or []) ++ [ ];
211 broken = disabled;
212 } // attrs.meta or {};
213}));
214in
215 luarocksDrv