1{ lib
2, stdenv
3, python
4, buildPythonPackage
5, fetchFromGitHub
6, alembic
7, argcomplete
8, attrs
9, blinker
10, cached-property
11, cattrs
12, clickclick
13, colorlog
14, croniter
15, cryptography
16, dill
17, flask
18, flask-appbuilder
19, flask-caching
20, flask_login
21, flask_wtf
22, GitPython
23, graphviz
24, gunicorn
25, httpx
26, iso8601
27, importlib-resources
28, importlib-metadata
29, inflection
30, itsdangerous
31, jinja2
32, jsonschema
33, lazy-object-proxy
34, lockfile
35, markdown
36, markupsafe
37, marshmallow-oneofschema
38, numpy
39, openapi-spec-validator
40, pandas
41, pendulum
42, psutil
43, pygments
44, pyjwt
45, python-daemon
46, python-dateutil
47, python-nvd3
48, python-slugify
49, python3-openid
50, pyyaml
51, rich
52, setproctitle
53, sqlalchemy
54, sqlalchemy-jsonfield
55, swagger-ui-bundle
56, tabulate
57, tenacity
58, termcolor
59, unicodecsv
60, werkzeug
61, pytestCheckHook
62, freezegun
63, mkYarnPackage
64}:
65let
66
67 version = "2.1.4";
68
69 airflow-src = fetchFromGitHub rec {
70 owner = "apache";
71 repo = "airflow";
72 rev = version;
73 sha256 = "12nxjaz4afkq30s42x3rbsci8jiw2k5zjngsc8i190fasbacbnbs";
74 };
75
76 # airflow bundles a web interface, which is built using webpack by an undocumented shell script in airflow's source tree.
77 # This replicates this shell script, fixing bugs in yarn.lock and package.json
78
79 airflow-frontend = mkYarnPackage {
80 name = "airflow-frontend";
81
82 src = "${airflow-src}/airflow/www";
83 packageJSON = ./package.json;
84 yarnLock = ./yarn.lock;
85 yarnNix = ./yarn.nix;
86
87 distPhase = "true";
88
89 configurePhase = ''
90 cp -r $node_modules node_modules
91 '';
92
93 buildPhase = ''
94 yarn --offline build
95 find package.json yarn.lock static/css static/js -type f | sort | xargs md5sum > static/dist/sum.md5
96 '';
97
98 installPhase = ''
99 mkdir -p $out/static/
100 cp -r static/dist $out/static
101 '';
102 };
103
104in
105buildPythonPackage rec {
106 pname = "apache-airflow";
107 inherit version;
108 src = airflow-src;
109
110 propagatedBuildInputs = [
111 alembic
112 argcomplete
113 attrs
114 blinker
115 cached-property
116 cattrs
117 clickclick
118 colorlog
119 croniter
120 cryptography
121 dill
122 flask
123 flask-appbuilder
124 flask-caching
125 flask_login
126 flask_wtf
127 GitPython
128 graphviz
129 gunicorn
130 httpx
131 iso8601
132 importlib-resources
133 importlib-metadata
134 inflection
135 itsdangerous
136 jinja2
137 jsonschema
138 lazy-object-proxy
139 lockfile
140 markdown
141 markupsafe
142 marshmallow-oneofschema
143 numpy
144 openapi-spec-validator
145 pandas
146 pendulum
147 psutil
148 pygments
149 pyjwt
150 python-daemon
151 python-dateutil
152 python-nvd3
153 python-slugify
154 python3-openid
155 pyyaml
156 rich
157 setproctitle
158 sqlalchemy
159 sqlalchemy-jsonfield
160 swagger-ui-bundle
161 tabulate
162 tenacity
163 termcolor
164 unicodecsv
165 werkzeug
166 ];
167
168 buildInputs = [
169 airflow-frontend
170 ];
171
172 checkInputs = [
173 freezegun
174 pytestCheckHook
175 ];
176
177 INSTALL_PROVIDERS_FROM_SOURCES = "true";
178
179 postPatch = ''
180 substituteInPlace setup.cfg \
181 --replace "importlib_resources~=1.4" "importlib_resources" \
182 --replace "importlib_metadata~=1.7" "importlib_metadata" \
183 --replace "tenacity~=6.2.0" "tenacity" \
184 --replace "pyjwt<2" "pyjwt" \
185 --replace "flask>=1.1.0, <2.0" "flask" \
186 --replace "flask-login>=0.3, <0.5" "flask-login" \
187 --replace "flask-wtf>=0.14.3, <0.15" "flask-wtf" \
188 --replace "jinja2>=2.10.1, <2.12.0" "jinja2" \
189 --replace "attrs>=20.0, <21.0" "attrs" \
190 --replace "cattrs~=1.1, <1.7.0" "cattrs" \
191 --replace "markupsafe>=1.1.1, <2.0" "markupsafe" \
192 --replace "docutils<0.17" "docutils" \
193 --replace "sqlalchemy>=1.3.18, <1.4" "sqlalchemy" \
194 --replace "sqlalchemy_jsonfield~=1.0" "sqlalchemy-jsonfield" \
195 --replace "werkzeug~=1.0, >=1.0.1" "werkzeug" \
196 --replace "itsdangerous>=1.1.0, <2.0" "itsdangerous" \
197 --replace "python-slugify>=3.0.0,<5.0" "python-slugify" \
198 --replace "colorlog>=4.0.2, <6.0" "colorlog"
199
200 substituteInPlace tests/core/test_core.py \
201 --replace "/bin/bash" "${stdenv.shell}"
202 '' + lib.optionalString stdenv.isDarwin ''
203 # Fix failing test on Hydra
204 substituteInPlace airflow/utils/db.py \
205 --replace "/tmp/sqlite_default.db" "$TMPDIR/sqlite_default.db"
206 '';
207
208 # allow for gunicorn processes to have access to python packages
209 makeWrapperArgs = [ "--prefix PYTHONPATH : $PYTHONPATH" ];
210
211 preCheck = ''
212 export HOME=$(mktemp -d)
213 export AIRFLOW_HOME=$HOME
214 export AIRFLOW__CORE__UNIT_TEST_MODE=True
215 export AIRFLOW_DB="$HOME/airflow.db"
216 export PATH=$PATH:$out/bin
217
218 airflow version
219 airflow db init
220 airflow db reset -y
221 '';
222
223 pytestFlagsArray = [
224 "tests/core/test_core.py"
225 ];
226
227 disabledTests = lib.optionals stdenv.isDarwin [
228 "bash_operator_kill" # psutil.AccessDenied
229 ];
230
231 postInstall = ''
232 cp -rv ${airflow-frontend}/static/dist $out/lib/${python.libPrefix}/site-packages/airflow/www/static
233 '';
234
235 meta = with lib; {
236 description = "Programmatically author, schedule and monitor data pipelines";
237 homepage = "http://airflow.apache.org/";
238 license = licenses.asl20;
239 maintainers = with maintainers; [ bhipple costrouc ingenieroariel ];
240 };
241}