Coccinelle release-1.0.0-rc11
[bpt/coccinelle.git] / release.nix
1 # Hydra build file for coccinelle
2
3 { nixpkgs ? /etc/nixos/nixpkgs
4 , cocciSrc ? { outPath = ./.; revCount = 1234; gitTag = "abcdef"; }
5 , testsSrc ? { outPath = ../big-tests; rev = 1234; }
6 , officialRelease ? false
7 }:
8
9 let
10
11 # version information
12 version = builtins.readFile ./version;
13 versionSuffix = if officialRelease then "" else "pre${toString cocciSrc.revCount}-${cocciSrc.gitTag}";
14
15 # The source tarball taken from the repository.
16 # The tarball should actually be compilable using
17 # ./configure && make depend && make opt && make install
18 # on systems other than nix.
19 tarball =
20 let
21 pkgs = import nixpkgs {
22 # use ocaml 3.12
23 config.packageOverrides =
24 pkgs:
25 { ocaml = pkgs.ocaml_3_12_1;
26 ocamlPackages = pkgs.ocamlPackages_3_12_1;
27 };
28 };
29
30 in with pkgs; with ocamlPackages; releaseTools.sourceTarball {
31 name = "coccinelle-tarball";
32 src = cocciSrc;
33 inherit officialRelease;
34 inherit version;
35 inherit versionSuffix;
36
37 buildInputs = [
38 perl python texLiveFull
39 ocaml findlib menhir
40 ocaml_pcre ocaml_sexplib
41 ocaml_extlib pycaml
42 ];
43
44 configurePhase = ''
45 # explicitly run perl because the configure script references a perl outside the nix store
46 # substituting the path to perl is not a good idea as it would invalidate the tarball on
47 # non-nix machines.
48 perl -w ./configure
49
50 make depend
51 '';
52
53 preDist = ''
54 local PREVHOME=$HOME
55 export HOME=$TMPDIR # the latex installation needs to write to the $HOME directory, so rename it here
56 '';
57
58 dontCopyDist = 1; # we'll copy the tarball to the tarballs folder ourselves (and rename it)
59 postDist = ''
60 export HOME=$PREVHOME # restore the home directory
61
62 ensureDir "$out/tarballs"
63
64 # rename the tarball to give it a version-specific name
65 cp coccinelle-*.tar.gz "$out/tarballs/coccinelle-${version}${versionSuffix}.tar.gz"
66 '';
67 };
68
69
70 # builds coccinelle, given a ocaml selector function and an ocaml environment builder.
71 # the build procedure itself is largely the same as the coccinelle expression in nixpkgs.
72 # the result should be a usable nix-expression
73 mkBuild = { name, ocamlVer, mkEnv, inclPython }: { system ? builtins.currentSystem }:
74 let pkgs = import nixpkgs {
75 inherit system;
76 config.packageOverrides = ocamlVer;
77 };
78
79 ocamlEnv = mkEnv pkgs;
80 in with pkgs; releaseTools.nixBuild {
81 inherit name;
82 src = tarball;
83
84 # ocamlEnv contains the ocaml libraries in scope.
85 buildInputs =
86 lib.optional inclPython python
87 ++ [ perl texLiveFull ncurses makeWrapper ocamlEnv ];
88
89 # patch the files for use with nix
90 preConfigure = ''
91 sed -i "configure" -e's|/usr/bin/perl|${perl}/bin/perl|g'
92 sed -i "globals/config.ml.in" \
93 -e"s|/usr/local/share|$out/share|g"
94 '';
95
96 configureFlags = lib.optional (!inclPython) "--without-python";
97
98 buildPhase = ''
99 make depend 2> >(tee -a "$out/nix-support/make.log" >&2)
100 make all 2> >(tee -a "$out/nix-support/make.log" >&2)
101 make all.opt 2> >(tee -a "$out/nix-support/make.log" >&2)
102 '';
103
104 # run checking after installation.
105 # also, the test phase may require a yes/no input.
106 doCheck = false;
107 postInstall = ''
108 wrapProgram "$out/bin/spatch" \
109 --prefix "LD_LIBRARY_PATH" ":" "$out/lib" \
110 --prefix "PYTHONPATH" ":" "$out/share/coccinelle/python"
111
112 wrapProgram "$out/bin/spatch.opt" \
113 --prefix "LD_LIBRARY_PATH" ":" "$out/lib" \
114 --prefix "PYTHONPATH" ":" "$out/share/coccinelle/python"
115
116 yes | make test
117 '';
118 };
119
120
121 # selects which version of ocaml and ocamlPackages to use in nixpkgs.
122 selOcaml312 = pkgs:
123 { ocaml = pkgs.ocaml_3_12_1;
124 ocamlPackages = pkgs.ocamlPackages_3_12_1;
125 };
126 selOcaml311 = pkgs:
127 { ocaml = pkgs.ocaml_3_11_1;
128 ocamlPackages = pkgs.ocamlPackages_3_11_1;
129 };
130
131
132 # builds an environment with the ocaml packages needed to build coccinelle
133 # the mkList function selects which additional packages to include
134 mkOcamlEnv = mkList: pkgs:
135 pkgs.buildEnv {
136 name = "cocci-ocamlenv";
137 paths = with pkgs.ocamlPackages; [ pkgs.ocaml findlib menhir ] ++ mkList pkgs.ocamlPackages;
138 };
139
140 # selections of ocaml libraries
141 libs_full = mkOcamlEnv (libs: with libs; [ ocaml_pcre ocaml_sexplib ocaml_extlib pycaml ]);
142 libs_rse = mkOcamlEnv (libs: with libs; [ ocaml_pcre ocaml_sexplib ocaml_extlib ]);
143 libs_se = mkOcamlEnv (libs: with libs; [ ocaml_sexplib ocaml_extlib ]);
144 libs_null = mkOcamlEnv (libs: []);
145
146 # package builder for Debian-based OS'ses
147 makeDeb =
148 system: diskImageFun:
149
150 with import nixpkgs { inherit system; };
151 releaseTools.debBuild {
152 name = "coccinelle-deb";
153 src = tarball;
154 diskImage = diskImageFun vmTools.diskImageFuns {
155 extraPackages = [ "python" "python-support" "ocaml-nox" "ocaml-findlib" ];
156 };
157 debRequires = [ "python" "python-support" "ocaml-nox" "ocaml-findlib" ];
158 doCheck = false;
159
160 buildPhase = ''
161 make depend
162 make all
163 make all.opt
164 '';
165 };
166
167 makeDeb_i686 = makeDeb "i686-linux";
168 makeDeb_x86_64 = makeDeb "x86_64-linux";
169
170 mkTask =
171 argsfun: { system ? builtins.currentSystem }:
172 let pkgs = import nixpkgs { inherit system; };
173 args = argsfun pkgs system;
174 name = "${args.name}-${version}${versionSuffix}";
175 in pkgs.stdenv.mkDerivation ({
176 phases = [ "runPhase" ];
177
178 runPhase = ''
179 ensureDir "$out"
180 ensureDir "$out/nix-support"
181 touch "$TMPDIR/result.log"
182 exec > >(tee -a "$TMPDIR/result.log") 2> >(tee -a "$TMPDIR/result.log" >&2)
183 runHook execPhase
184 cp "$TMPDIR/result.log" "$out/"
185 echo "report log $out/result.log" >> "$out/nix-support/hydra-build-products"
186 echo "$name" > "$out/nix-support/hydra-release-name"
187 '';
188
189 meta = {
190 description = "Coccinelle post-build task";
191 schedulingPriority = 8;
192 };
193 } // args // { inherit name; });
194
195 mkReport = inputs: mkTask (pkgs: _: with pkgs; {
196 name = "report";
197 builds = map (i: i {}) inputs;
198
199 execPhase = ''
200 echo "collecting logs"
201 for build in $builds; do
202 echo "$build/nix-support/make.log"
203 cat "$build/nix-support/make.log"
204 done
205
206 echo "grepping OCaml warnings"
207 if grep -2 "Warning " "$TMPDIR/result.log"
208 then
209 echo "found warnings!"
210 false
211 else
212 echo "there are apparently no significant warnings"
213 fi
214 '';
215
216 meta = {
217 description = "Analysis of the coccinelle build reports";
218 schedulingPriority = 5;
219 };
220 });
221
222 # Produces regression test results, which can be positive or
223 # negative. The build should succeed regardless of the outcome
224 # of individual tests unless coccinelle is horribly broken.
225 # The resulting files are stored in a tarball so that it allows
226 # manual inspection.
227 mkRegress = cocciSelect: mkTask (pkgs: system: with pkgs;
228 let coccinelle = cocciSelect { inherit system; };
229 in {
230 name = "regression-${toString testsSrc.rev}";
231 buildInputs = [ coccinelle ];
232
233 execPhase = ''
234 # prepare a writeable tests directory
235 # as this directory contains large
236 # files, we'll create links to the
237 # individual files.
238 ensureDir "$TMPDIR/tests"
239 cp -rs ${testsSrc}/* "$TMPDIR/tests/"
240 chmod -R u+w "$TMPDIR/tests/"
241 cd "$TMPDIR/tests"
242
243 # initialize essential environment variables
244 # for the makefile
245 export COCCIDIR=$TMPDIR
246 export SPATCH=${coccinelle}/bin/spatch.opt
247 export ISO=${coccinelle}/share/coccinelle/standard.iso
248 export DEFS=${coccinelle}/share/coccinelle/standard.h
249
250 # generate the test outcomes
251 make -e all
252
253 # collect the results
254 # note: the tarball is likely to contain useless
255 # symbolic links to files in the nix store. So be it.
256 cd "$TMPDIR"
257 tar -czf "$out/results.tar.gz" ./tests
258 echo "file binary-dist $out/results.tar.gz" >> "$out/nix-support/hydra-build-products"
259 '';
260
261 meta = {
262 description = "Regression test of Coccinelle";
263 schedulingPriority = 8;
264 };
265 });
266
267 # Checks whether the regression tests meet our expectations.
268 # If the set of failed tests is different than specified in
269 # the tests repository, this check fails.
270 checkRegress = regressSelect: mkTask (pkgs: system: with pkgs;
271 let regress = regressSelect { inherit system; };
272 in {
273 name = "test-${toString testsSrc.rev}";
274
275 execPhase = ''
276 # prepare a writeable tests directory
277 # as this directory contains large
278 # files, we'll create links to the
279 # individual files.
280 ensureDir "$TMPDIR/tests"
281 cp -rs ${testsSrc}/* "$TMPDIR/tests/"
282 chmod -R u+w "$TMPDIR/tests/"
283
284 # extract the outcome of the regression test over it
285 echo "reconstructing regression directory"
286 cd "$TMPDIR"
287 tar xfz "${regress}/results.tar.gz"
288 cd "$TMPDIR/tests"
289
290 echo "analyzing results"
291 make failedlog
292
293 echo "verifying the outcome"
294 make check
295 '';
296
297 meta = {
298 description = "Regression test of Coccinelle";
299 schedulingPriority = 8;
300 };
301 });
302
303 in # list of jobs
304 rec {
305 inherit tarball;
306
307 # different configurations of coccinelle builds based on different ocamls/available libraries
308 build = mkBuild { name = "coccinelle"; ocamlVer = selOcaml312; mkEnv = libs_full; inclPython = true; };
309 build_rse = mkBuild { name = "coccinelle_config1"; ocamlVer = selOcaml312; mkEnv = libs_rse; inclPython = true; };
310 build_se = mkBuild { name = "coccinelle_config2"; ocamlVer = selOcaml312; mkEnv = libs_se; inclPython = true; };
311 build_null_12 = mkBuild { name = "coccinelle_config3"; ocamlVer = selOcaml312; mkEnv = libs_null; inclPython = true; };
312 build_null_11 = mkBuild { name = "coccinelle_config4"; ocamlVer = selOcaml311; mkEnv = libs_null; inclPython = true; };
313 build_null_12_np = mkBuild { name = "coccinelle_config5"; ocamlVer = selOcaml312; mkEnv = libs_null; inclPython = false; };
314 build_null_11_np = mkBuild { name = "coccinelle_config6"; ocamlVer = selOcaml311; mkEnv = libs_null; inclPython = false; };
315 build_rse_np = mkBuild { name = "coccinelle_config7"; ocamlVer = selOcaml312; mkEnv = libs_rse; inclPython = false; };
316
317 report = mkReport [ build build_rse build_se build_null_12 build_null_11 build_null_12_np build_null_11_np build_rse_np ];
318
319 # different debian builds
320 # deb_ubuntu1010_i386 = makeDeb_i686 (disk: disk.ubuntu1010i386);
321 # deb_ubuntu1010_x86_64 = makeDeb_x86_64 (disk: disk.ubuntu1010x86_64);
322
323 # extensive tests
324 regress = mkRegress build;
325 test = checkRegress regress;
326 }