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
|
/*
This is the library of nix builders. Some rules to follow:
- Keep this code as minimal as possible. I'd rather write Haskell than Nix,
wouldn't you?
- Try to reuse as much upstream Nix as possible.
*/
{ analysisJSON, nixpkgs ? import ../Bild.nix {} }:
with nixpkgs;
let
analysis = builtins.fromJSON analysisJSON;
build = _: target: let
name = target.out;
root = builtins.getEnv "BIZ_ROOT";
mainModule = target.mainModule;
compileLine =
lib.strings.concatStringsSep " " ([target.compiler] ++ target.compilerFlags);
allSources = target.srcs ++ [target.quapath];
isEmpty = x: x == null || x == [];
skip = ["_" ".direnv"];
filter = file: type:
if lib.lists.elem (builtins.baseNameOf file) skip then false
# TODO: this means any new directory will cause a rebuild. this bad. i
# should recurse into the directory and match against the srcs. for now I
# just use postUnpack to delete empty dirs
else if type == "directory" then true
else if type == "regular" then lib.trivial.pipe file
[ (f: lib.strings.removePrefix "${root}/" f)
(f: lib.lists.elem f allSources)
]
else false;
# clean up empty dirs
#postUnpack = "find $src -type d -empty -delete";
src = lib.sources.cleanSourceWith {inherit filter; src = lib.sources.cleanSource root;};
langdeps_ =
if isEmpty target.langdeps then
[]
else
lib.attrsets.attrVals
target.langdeps
(lib.attrsets.getAttrFromPath (lib.strings.splitString "." target.packageSet) bild);
sysdeps_ =
if isEmpty target.sysdeps then
[]
else
lib.attrsets.attrVals target.sysdeps pkgs;
BIZ_ROOT = ".";
builders = {
base = stdenv.mkDerivation rec {
inherit name src BIZ_ROOT;
buildInputs = langdeps_ ++ sysdeps_;
installPhase = "install -D ${name} $out/bin/${name}";
buildPhase = compileLine;
};
haskell = stdenv.mkDerivation rec {
inherit name src BIZ_ROOT;
buildInputs = sysdeps_ ++ [
(bild.haskell.ghcWith (p:
(lib.attrsets.attrVals target.langdeps p)
))
];
installPhase = "install -D ${name} $out/bin/${name}";
buildPhase = compileLine;
};
c = stdenv.mkDerivation rec {
inherit name src BIZ_ROOT;
buildInputs = langdeps_ ++ sysdeps_;
installPhase = "install -D ${name} $out/bin/${name}";
buildPhase = lib.strings.concatStringsSep " " [
compileLine
(if isEmpty langdeps_ then "" else
"$(pkg-config --cflags ${lib.strings.concatStringsSep " " target.langdeps})")
(if isEmpty sysdeps_ then "" else
"$(pkg-config --libs ${lib.strings.concatStringsSep " " target.sysdeps})")
];
};
python = bild.python.buildPythonApplication rec {
inherit name src BIZ_ROOT;
propagatedBuildInputs = [ (bild.python.pythonWith (_: langdeps_)) ] ++ sysdeps_;
buildInputs = sysdeps_;
checkInputs = [(bild.python.pythonWith (p: with p; [black mypy pylint]))];
checkPhase = ''
check() {
$@ || { echo "fail: $name: $3"; exit 1; }
}
check python -m black --quiet --exclude 'setup\.py$' --check .
check python -m pylint --errors-only .
check python -m mypy --strict --no-error-summary --exclude 'setup\.py$' .
check python -m ${mainModule} test
'';
preBuild = ''
# initialize possibly-empty subdirectories as python modules
find . -type d -exec touch {}/__init__.py \;
# generate a minimal setup.py
cat > setup.py << EOF
from setuptools import setup, find_packages
setup(
name='${name}',
entry_points={'console_scripts':['${name} = ${mainModule}:main']},
version='0.0.0',
url='git://simatime.com/biz.git',
author='dev',
author_email='dev@simatime.com',
description='nil',
packages=find_packages(),
install_requires=[],
)
EOF
'';
pythonImportsCheck = [mainModule]; # sanity check
};
};
in builders.${target.builder};
# the caller gives us the Analysis type, which is a hashmap, but i need to
# return a single drv, so just take the first one for now. ideally i would only
# pass Target, one at a time, (perhaps parallelized in haskell land) and then i
# wouldn't need all of this let nesting
in builtins.head (lib.attrsets.mapAttrsToList build analysis)
|