mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-06-06 13:23:41 +00:00
Compare commits
802 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c50a710dd | ||
|
|
ae717416fd | ||
|
|
e63e3510a3 | ||
|
|
39712f4237 | ||
|
|
c380dc08e6 | ||
|
|
82f1b82cd2 | ||
|
|
1a9673de83 | ||
|
|
f1f0a90e32 | ||
|
|
32fe9f8cd8 | ||
|
|
2ee7a48270 | ||
|
|
5df5a25ad5 | ||
|
|
0565b9bdc5 | ||
|
|
e93a273b1a | ||
|
|
80d5912728 | ||
|
|
595f093d6b | ||
|
|
2329cf0c0f | ||
|
|
198ebc1547 | ||
|
|
4c3975adad | ||
|
|
72ed9ece4d | ||
|
|
a9a2f57213 | ||
|
|
cc683f249d | ||
|
|
72fd08b93f | ||
|
|
a061b460d3 | ||
|
|
eddd5cc0a5 | ||
|
|
7ffc523f69 | ||
|
|
7587644979 | ||
|
|
cc8609d47c | ||
|
|
2eb01a542f | ||
|
|
b49d8de8ee | ||
|
|
b381e29a3c | ||
|
|
6751dd6836 | ||
|
|
b6583ed594 | ||
|
|
6002ccf982 | ||
|
|
545f264912 | ||
|
|
b1da8f7266 | ||
|
|
73b63a1840 | ||
|
|
2d110ab9ef | ||
|
|
dbca4e84de | ||
|
|
8d0c4e117b | ||
|
|
4c9f0c9415 | ||
|
|
51834a0509 | ||
|
|
bd154320bf | ||
|
|
382d19cbfe | ||
|
|
36da57041e | ||
|
|
dcfab359e1 | ||
|
|
87b1a7e6e9 | ||
|
|
9a32911ada | ||
|
|
eca4745b97 | ||
|
|
a56b24f8d8 | ||
|
|
d36ad44302 | ||
|
|
085a72b077 | ||
|
|
01746262da | ||
|
|
abc6505905 | ||
|
|
846af8382e | ||
|
|
80c79ee3a8 | ||
|
|
be8020d408 | ||
|
|
b138336bec | ||
|
|
fcf9006e23 | ||
|
|
5c10ee7158 | ||
|
|
47f525d427 | ||
|
|
627e056b6d | ||
|
|
4041d4304c | ||
|
|
fff9a69a14 | ||
|
|
f4f0ce8511 | ||
|
|
5c40e92742 | ||
|
|
6038b92f4e | ||
|
|
257de32294 | ||
|
|
f8fda9583d | ||
|
|
f55b79048f | ||
|
|
b1608ab20c | ||
|
|
489041ceea | ||
|
|
0027f7f92a | ||
|
|
295cee7871 | ||
|
|
f73301795d | ||
|
|
9b82faa938 | ||
|
|
bb6e9ff99d | ||
|
|
dc4e8b7543 | ||
|
|
fcd6dd28fc | ||
|
|
f0629402f7 | ||
|
|
75f22aaeaa | ||
|
|
4e61b81b3e | ||
|
|
571a81dc39 | ||
|
|
925fc1eda2 | ||
|
|
6e5a848ad8 | ||
|
|
d757b5d092 | ||
|
|
af76a16a02 | ||
|
|
56b4980d8c | ||
|
|
eb50eae849 | ||
|
|
646f3698e1 | ||
|
|
f0af141b32 | ||
|
|
54d277eb6b | ||
|
|
38a28556af | ||
|
|
5e75a734ac | ||
|
|
dc4c7d5403 | ||
|
|
36ba5a16c8 | ||
|
|
5b63e61da0 | ||
|
|
168f475676 | ||
|
|
2b986401be | ||
|
|
6141debf9a | ||
|
|
898a43b91c | ||
|
|
83be6f21f0 | ||
|
|
676cc844a9 | ||
|
|
9103ffc9e0 | ||
|
|
0c894a9bdc | ||
|
|
d5c220575c | ||
|
|
fad7d17433 | ||
|
|
0306430d28 | ||
|
|
662f1e622f | ||
|
|
5148ff353b | ||
|
|
76575a23ce | ||
|
|
0dd3d96623 | ||
|
|
278f82a5d0 | ||
|
|
d25c3202b1 | ||
|
|
3d2d2e85e3 | ||
|
|
e9cd3787ec | ||
|
|
966e117bcf | ||
|
|
9cae56a1fa | ||
|
|
0ad1c04346 | ||
|
|
2130c97a6c | ||
|
|
63aec6daef | ||
|
|
282bc8530e | ||
|
|
6f4d835574 | ||
|
|
51f30d5560 | ||
|
|
d49bbfdf30 | ||
|
|
9f3fbdebc9 | ||
|
|
ba22692228 | ||
|
|
dd51397f22 | ||
|
|
f6d63cecde | ||
|
|
bdb1bd6114 | ||
|
|
9c7186464b | ||
|
|
f4215d1c99 | ||
|
|
70ba751c60 | ||
|
|
02348a6bc2 | ||
|
|
8ab24dc538 | ||
|
|
2c26f9b9c9 | ||
|
|
e8e446a361 | ||
|
|
9c57e8dde2 | ||
|
|
e4bd3958f9 | ||
|
|
1d84ac4414 | ||
|
|
a2c881b2fd | ||
|
|
c5b3df2ef9 | ||
|
|
8fdcbe1246 | ||
|
|
ba2260f4c7 | ||
|
|
14b2626ea7 | ||
|
|
4b0db36abd | ||
|
|
c01aa2b1bb | ||
|
|
67b859a1fd | ||
|
|
513eab96e0 | ||
|
|
afaa1e9941 | ||
|
|
11bc4f0115 | ||
|
|
7808e72111 | ||
|
|
b82dc19c10 | ||
|
|
41cc72fd94 | ||
|
|
23363ea584 | ||
|
|
c85dc29a9b | ||
|
|
d669d597f5 | ||
|
|
8f72f1dec8 | ||
|
|
071b0d8523 | ||
|
|
038d4f43e3 | ||
|
|
045d09d3f4 | ||
|
|
cb0ad9e216 | ||
|
|
4d87331c27 | ||
|
|
fa08af56e4 | ||
|
|
dc09c1655c | ||
|
|
2fd826550f | ||
|
|
bee22226fb | ||
|
|
45d46aef15 | ||
|
|
0a5c99add2 | ||
|
|
57a58cb97e | ||
|
|
33fc755767 | ||
|
|
2700478faf | ||
|
|
a7d993bba7 | ||
|
|
08ee4f278e | ||
|
|
bb22b237eb | ||
|
|
5e560b69d5 | ||
|
|
0b5e03d43f | ||
|
|
07b2a6cde8 | ||
|
|
e755565475 | ||
|
|
f8bb4852b0 | ||
|
|
97852de5fa | ||
|
|
59f1da01ad | ||
|
|
174f12335a | ||
|
|
ea262e4380 | ||
|
|
820ce7d303 | ||
|
|
805a45fe92 | ||
|
|
b91bd8766d | ||
|
|
8420d8d19a | ||
|
|
abb378034d | ||
|
|
f957fe70cd | ||
|
|
0a2f69320b | ||
|
|
3f554c010f | ||
|
|
f3156ab0a0 | ||
|
|
ec942ba042 | ||
|
|
1e8aeb2f77 | ||
|
|
21aa1b5dec | ||
|
|
74dd899517 | ||
|
|
0e829cfa01 | ||
|
|
94519887cb | ||
|
|
90eb6c5540 | ||
|
|
02088a3f8b | ||
|
|
7b108a0f7a | ||
|
|
aa3f0aa551 | ||
|
|
c7775ede84 | ||
|
|
343964b5a1 | ||
|
|
e8db22aee1 | ||
|
|
6848e31194 | ||
|
|
f7a7eec83f | ||
|
|
04281c6fbf | ||
|
|
84460b65f9 | ||
|
|
adf1867414 | ||
|
|
dd689bfc16 | ||
|
|
d3c64ecbb5 | ||
|
|
711735a851 | ||
|
|
cf4cb9a166 | ||
|
|
8d4a938401 | ||
|
|
b739a5d6d2 | ||
|
|
d44f5aa98d | ||
|
|
84e5858728 | ||
|
|
cb5b261021 | ||
|
|
70a8482d86 | ||
|
|
672ef6274b | ||
|
|
e85be5731f | ||
|
|
40e812eeea | ||
|
|
30454a5b63 | ||
|
|
0ea771a19d | ||
|
|
b476551b7a | ||
|
|
8d17759d0e | ||
|
|
a5d0c86795 | ||
|
|
2d32735e59 | ||
|
|
d01282e09d | ||
|
|
b9e4730dee | ||
|
|
a0e70a9d91 | ||
|
|
b831ff6f14 | ||
|
|
25a37541ef | ||
|
|
7b0c12f420 | ||
|
|
b534faced5 | ||
|
|
a67dc02f03 | ||
|
|
4940084bff | ||
|
|
8d2b13b41c | ||
|
|
40c6436513 | ||
|
|
601732ceb5 | ||
|
|
73b30875cd | ||
|
|
e898225914 | ||
|
|
41158df9ab | ||
|
|
6229beed42 | ||
|
|
759f33b6ce | ||
|
|
1878b8943d | ||
|
|
2d3e3eecc8 | ||
|
|
1e0f951c2b | ||
|
|
0e11e4ef47 | ||
|
|
c80226c424 | ||
|
|
ea99d29d34 | ||
|
|
1ce38c1d14 | ||
|
|
1eb4733f58 | ||
|
|
ab35d8b57a | ||
|
|
68bfb20566 | ||
|
|
923d852840 | ||
|
|
a850fbbc71 | ||
|
|
a1dd22216d | ||
|
|
9df5c6a2a0 | ||
|
|
014a311fef | ||
|
|
d3425f3bda | ||
|
|
0dbe92f4d6 | ||
|
|
26c9e1dd65 | ||
|
|
157a942887 | ||
|
|
4f1742f1bd | ||
|
|
6ec76b678a | ||
|
|
d3b41ceaf2 | ||
|
|
b28ed0c87d | ||
|
|
d8b97a63f9 | ||
|
|
255103898a | ||
|
|
8594958d8e | ||
|
|
5ede757685 | ||
|
|
7a55590207 | ||
|
|
a0252785ea | ||
|
|
6fefc7cc19 | ||
|
|
9b7dc789ca | ||
|
|
65f5d22619 | ||
|
|
4bff5d284f | ||
|
|
36598bcf49 | ||
|
|
eca36e4374 | ||
|
|
da06ce0147 | ||
|
|
f70c0a4cbb | ||
|
|
f2513f069b | ||
|
|
f9928938a6 | ||
|
|
ba8efbb42b | ||
|
|
60eaa38f4b | ||
|
|
850d000d00 | ||
|
|
ee220bf480 | ||
|
|
2a56605ab1 | ||
|
|
1bab1397c0 | ||
|
|
2f3e6779d3 | ||
|
|
31f8371c17 | ||
|
|
ddfd13ac90 | ||
|
|
d7430ff4f4 | ||
|
|
e0d74c6906 | ||
|
|
61c6be594b | ||
|
|
90381dc2af | ||
|
|
638de81183 | ||
|
|
96187d7d4e | ||
|
|
a7d9e04f3a | ||
|
|
0ce502e774 | ||
|
|
e81d553fd5 | ||
|
|
70f3f87ca7 | ||
|
|
2b134a8fea | ||
|
|
e842d5cb7f | ||
|
|
13b979d756 | ||
|
|
75436e1d55 | ||
|
|
fad42bedaf | ||
|
|
e7be25e617 | ||
|
|
9ae1c8233e | ||
|
|
17afae0268 | ||
|
|
3b63ed363b | ||
|
|
174b0d0afc | ||
|
|
c8a3fa3084 | ||
|
|
ed1fdb4766 | ||
|
|
99011e674e | ||
|
|
4acf48b2b6 | ||
|
|
35ee486b4f | ||
|
|
899b40ceb0 | ||
|
|
a76ae2dcfc | ||
|
|
64ee1fe246 | ||
|
|
f426a0a151 | ||
|
|
abedc5cdc7 | ||
|
|
11d823ef22 | ||
|
|
73f7fa84f6 | ||
|
|
05f4885600 | ||
|
|
b87f577e95 | ||
|
|
c686adf961 | ||
|
|
9e649b4d77 | ||
|
|
ff0d179490 | ||
|
|
0851e70d9c | ||
|
|
70d7ddf85a | ||
|
|
dbfdf9cd0c | ||
|
|
4481e80f31 | ||
|
|
74fe587af7 | ||
|
|
90c54eeb85 | ||
|
|
967edda59b | ||
|
|
63e3952d1f | ||
|
|
8193eb6f3e | ||
|
|
f66ebcfba1 | ||
|
|
2973d2ebae | ||
|
|
659c7f088f | ||
|
|
1a76d54453 | ||
|
|
8bbcfa1b00 | ||
|
|
03a8cf1316 | ||
|
|
bf7b3158b9 | ||
|
|
9c9a58d149 | ||
|
|
dad03392cd | ||
|
|
b3fae191b5 | ||
|
|
73c771cef2 | ||
|
|
5c5ef4b520 | ||
|
|
eee7b3e24b | ||
|
|
398f17d7c6 | ||
|
|
3f8016807c | ||
|
|
1cd74962e1 | ||
|
|
d28dad7577 | ||
|
|
2f00f9d6f1 | ||
|
|
3b9599a13d | ||
|
|
8d49b1947e | ||
|
|
2a451d74ee | ||
|
|
1d5b973fe4 | ||
|
|
6e6a50bcb1 | ||
|
|
7386ebeda4 | ||
|
|
299e70af76 | ||
|
|
92f4a739a4 | ||
|
|
334d1973fa | ||
|
|
c89e4ac282 | ||
|
|
6b8a22fb3b | ||
|
|
634627ffcc | ||
|
|
75225ee8c0 | ||
|
|
7c81f43ed4 | ||
|
|
59c867174a | ||
|
|
c981866397 | ||
|
|
0895daecb6 | ||
|
|
959041ceb1 | ||
|
|
490fd7f31b | ||
|
|
ed6d9c93f3 | ||
|
|
e6cda3ecd0 | ||
|
|
8878bfe827 | ||
|
|
b4b9c8f6fa | ||
|
|
c8b332ba4f | ||
|
|
11ada9c063 | ||
|
|
d0b64f5c9e | ||
|
|
04f1170f5e | ||
|
|
0c2f5e4c31 | ||
|
|
101f3b55c5 | ||
|
|
df864ac331 | ||
|
|
ecd15da62e | ||
|
|
0601d867a9 | ||
|
|
770ec36f45 | ||
|
|
40b4cb9eeb | ||
|
|
5692452170 | ||
|
|
eafcb0c234 | ||
|
|
0d052627a4 | ||
|
|
c331fb6f1d | ||
|
|
a2836c188f | ||
|
|
96a72fbaed | ||
|
|
60b9e1dc3c | ||
|
|
1135c0f766 | ||
|
|
ab8312e2d5 | ||
|
|
e7f04f94b4 | ||
|
|
2bffcb8989 | ||
|
|
f5f814139c | ||
|
|
7f0d3a844d | ||
|
|
6ef2dfbb97 | ||
|
|
232872cf59 | ||
|
|
13bcbeb89d | ||
|
|
2c8590c277 | ||
|
|
9a1524f0a3 | ||
|
|
6876f432c2 | ||
|
|
5e23ac95f1 | ||
|
|
9c104004c9 | ||
|
|
1e1294a640 | ||
|
|
0d1936c8c0 | ||
|
|
15bb2dbda5 | ||
|
|
3aceba606e | ||
|
|
6723eb42c3 | ||
|
|
fd9e0e2a14 | ||
|
|
594a718819 | ||
|
|
221d3819c1 | ||
|
|
327f16f847 | ||
|
|
0e0ca99858 | ||
|
|
4f17aa01c1 | ||
|
|
c34b067aa1 | ||
|
|
454271cb7d | ||
|
|
153866bfe2 | ||
|
|
0f2774f80a | ||
|
|
52ddaa37a1 | ||
|
|
3a5811a964 | ||
|
|
b3720aa01e | ||
|
|
30dbdee6e3 | ||
|
|
902d19f7e2 | ||
|
|
1948b0d114 | ||
|
|
87070ced98 | ||
|
|
4ac7d8e47e | ||
|
|
36582c3341 | ||
|
|
5fa68180ec | ||
|
|
fa3884c0e3 | ||
|
|
5aa0e33e6f | ||
|
|
2ae8f80a7a | ||
|
|
53d282aed5 | ||
|
|
d54f68253a | ||
|
|
7b304d5b29 | ||
|
|
a175342a9f | ||
|
|
bf51a9c2de | ||
|
|
27a614a5ce | ||
|
|
1b5b4b0404 | ||
|
|
dda7625e77 | ||
|
|
34bec04d13 | ||
|
|
b9f5c1e419 | ||
|
|
31ff1cf723 | ||
|
|
cf7b308a25 | ||
|
|
b5b6f0ccb0 | ||
|
|
27bc1e0a1f | ||
|
|
f39f6df443 | ||
|
|
deec732956 | ||
|
|
b9419538ef | ||
|
|
760ee4df33 | ||
|
|
def8ae4d4a | ||
|
|
3f06aa825f | ||
|
|
836b59c280 | ||
|
|
39dfa7bc79 | ||
|
|
0e8b8ecf89 | ||
|
|
9699ff7370 | ||
|
|
bfd65e9a21 | ||
|
|
bb0550d2a4 | ||
|
|
1730cf98dc | ||
|
|
45ce5b1fba | ||
|
|
bc68793f57 | ||
|
|
0521704373 | ||
|
|
087e5b630c | ||
|
|
4e6aad3d71 | ||
|
|
80b58151da | ||
|
|
6c61841def | ||
|
|
54b9bb7668 | ||
|
|
a34b19c925 | ||
|
|
d53d306c0a | ||
|
|
3a75bdbb4a | ||
|
|
140b61c984 | ||
|
|
66d1276b57 | ||
|
|
8e1367a936 | ||
|
|
845e295cdd | ||
|
|
682104475a | ||
|
|
c763e2327a | ||
|
|
b1ec51efd8 | ||
|
|
9b8e0b12cd | ||
|
|
e96bdf6ed7 | ||
|
|
ed88353018 | ||
|
|
21135470b4 | ||
|
|
b2a1d9207d | ||
|
|
ccba28dd47 | ||
|
|
323dfd4232 | ||
|
|
d9ec6a3f24 | ||
|
|
4b2e906049 | ||
|
|
cbe752c149 | ||
|
|
89692a46b8 | ||
|
|
89f482e666 | ||
|
|
04de8ffd1d | ||
|
|
1b0a83cc7d | ||
|
|
331eb8035d | ||
|
|
e9413dda55 | ||
|
|
a4464ae19c | ||
|
|
081aca7aeb | ||
|
|
5f775d7ea3 | ||
|
|
dab389d7b6 | ||
|
|
b2eada3a05 | ||
|
|
6a1ecb18ab | ||
|
|
09d2088fea | ||
|
|
9929c7e9e4 | ||
|
|
612cc9ae5e | ||
|
|
d84405d974 | ||
|
|
68a93745d3 | ||
|
|
d0444f46f9 | ||
|
|
6aeccf8562 | ||
|
|
887789e977 | ||
|
|
cb6554026c | ||
|
|
149e7fb745 | ||
|
|
8b2a452dd5 | ||
|
|
231c6d79dd | ||
|
|
bbb918b1f6 | ||
|
|
5619af9d05 | ||
|
|
3c8909d356 | ||
|
|
9e111f94a8 | ||
|
|
52463989a1 | ||
|
|
4d63832378 | ||
|
|
4b19988c94 | ||
|
|
5888ab115d | ||
|
|
ab905305b5 | ||
|
|
4df567a2f1 | ||
|
|
b997463fc2 | ||
|
|
11e32c793e | ||
|
|
f009f2d3a9 | ||
|
|
7e41cf4173 | ||
|
|
0c739c2565 | ||
|
|
c57fe4bc08 | ||
|
|
f7b9110ef4 | ||
|
|
106b28babf | ||
|
|
1941fa2ce5 | ||
|
|
4ae09cbfdd | ||
|
|
2ad81b95e9 | ||
|
|
41d5cd7e7e | ||
|
|
fec5bcf841 | ||
|
|
a090168385 | ||
|
|
6ecc9c6467 | ||
|
|
b3277c7dcc | ||
|
|
9e008ca2a4 | ||
|
|
362844e8d7 | ||
|
|
5447a68e1c | ||
|
|
36d3b814e6 | ||
|
|
a4e57357d6 | ||
|
|
07be792e52 | ||
|
|
bf8cc53bb8 | ||
|
|
f587b4798a | ||
|
|
11169ea95f | ||
|
|
e9181fae4e | ||
|
|
26976edf65 | ||
|
|
18fc9349b7 | ||
|
|
bb58603cf8 | ||
|
|
c4d62d97d1 | ||
|
|
c0ff8c5ea5 | ||
|
|
e713b4f218 | ||
|
|
e8b485c354 | ||
|
|
27c6fb79cf | ||
|
|
14bd57aedd | ||
|
|
c14d877ac6 | ||
|
|
7f7385c363 | ||
|
|
c1b5ed33c8 | ||
|
|
cbe69277cf | ||
|
|
55f0fdf30b | ||
|
|
8897ef8dfb | ||
|
|
636542dce1 | ||
|
|
cec5ecbe39 | ||
|
|
ca57ca7d33 | ||
|
|
abae498e43 | ||
|
|
f0ddca605d | ||
|
|
b85031e3b9 | ||
|
|
e25f81495e | ||
|
|
093a53d7ad | ||
|
|
14e686e1c3 | ||
|
|
7aa3948eab | ||
|
|
f8290a6360 | ||
|
|
1bfa2844d7 | ||
|
|
8a727e5615 | ||
|
|
b74795eb8c | ||
|
|
1713d3aa03 | ||
|
|
06faf434dd | ||
|
|
94e656c187 | ||
|
|
3bf9dfe2ea | ||
|
|
dde36afcea | ||
|
|
89f35aab25 | ||
|
|
5ee9ad1b7c | ||
|
|
a778ae0abd | ||
|
|
4d9189447a | ||
|
|
65ab15fdd5 | ||
|
|
196fe731e7 | ||
|
|
f6ebec3edc | ||
|
|
0936562f09 | ||
|
|
612a2e73cf | ||
|
|
04e78b4065 | ||
|
|
8e5c732a6c | ||
|
|
49943a6043 | ||
|
|
375a836bdb | ||
|
|
da778ea3df | ||
|
|
88e7af78ca | ||
|
|
91ff8d91dc | ||
|
|
763d6e189a | ||
|
|
6204830f7b | ||
|
|
db933900f0 | ||
|
|
1d207fc18d | ||
|
|
f06baa4b12 | ||
|
|
6a131d5e10 | ||
|
|
b7f6ae77f4 | ||
|
|
b85bf0189f | ||
|
|
3ecffaa913 | ||
|
|
edb670c9a4 | ||
|
|
746bf9e72e | ||
|
|
7141e726cf | ||
|
|
f352236954 | ||
|
|
4c323a3a09 | ||
|
|
40b20ce2fe | ||
|
|
548109cb5c | ||
|
|
5892eeb5c6 | ||
|
|
7b47888eed | ||
|
|
bfa198d3cb | ||
|
|
3ed77f6be2 | ||
|
|
efae21db94 | ||
|
|
c7813fbe8c | ||
|
|
161b8c8d92 | ||
|
|
0cb195e653 | ||
|
|
aac45e7c5d | ||
|
|
1f84a84fd8 | ||
|
|
50e9abd4d5 | ||
|
|
4ea4af20af | ||
|
|
29824d0819 | ||
|
|
4e926c69c2 | ||
|
|
9ce5dd3a61 | ||
|
|
61ea2bb237 | ||
|
|
71698205b8 | ||
|
|
9dde6d6888 | ||
|
|
1675be7358 | ||
|
|
e35e0188ba | ||
|
|
e94c35b322 | ||
|
|
ec9eeb85c3 | ||
|
|
085b1395e9 | ||
|
|
8d4f54dc55 | ||
|
|
7b5f224cf8 | ||
|
|
6a5409cb98 | ||
|
|
8072d62389 | ||
|
|
82065d16f0 | ||
|
|
7fcb458a06 | ||
|
|
a0d03c9ddc | ||
|
|
ee3f02e689 | ||
|
|
8d3fb58c90 | ||
|
|
8f84d93eea | ||
|
|
4d87df77fe | ||
|
|
8ed0934a96 | ||
|
|
8d2eaa762a | ||
|
|
45aa6e3456 | ||
|
|
88aeab524d | ||
|
|
5cc04113ec | ||
|
|
b8d260dd14 | ||
|
|
9b87281b89 | ||
|
|
29598a7627 | ||
|
|
97b4b665f9 | ||
|
|
59e94373e8 | ||
|
|
67de202206 | ||
|
|
34bf125ce3 | ||
|
|
01ba43d795 | ||
|
|
15e630ca35 | ||
|
|
d8fb34e72f | ||
|
|
944a00877a | ||
|
|
99cbef2888 | ||
|
|
19b722db14 | ||
|
|
3c2cac77ea | ||
|
|
dc6361e63e | ||
|
|
3dc9d7878d | ||
|
|
e7680378ae | ||
|
|
f336998635 | ||
|
|
1b60b62749 | ||
|
|
8f4f8924be | ||
|
|
3eb2a1b52a | ||
|
|
cf143940f9 | ||
|
|
221ecd7001 | ||
|
|
182cfbd047 | ||
|
|
632e240fd5 | ||
|
|
aec8047ca6 | ||
|
|
1aa63e4f5f | ||
|
|
b1619a4ef0 | ||
|
|
3dc0105541 | ||
|
|
f6ebb8c223 | ||
|
|
7596362959 | ||
|
|
4af760ff20 | ||
|
|
ab0df422bd | ||
|
|
b968491899 | ||
|
|
953cc572a3 | ||
|
|
50aea46f4f | ||
|
|
a909cc52ed | ||
|
|
571318a88f | ||
|
|
00e44259f4 | ||
|
|
95521573a4 | ||
|
|
a81e27cbbd | ||
|
|
d5ca66cf88 | ||
|
|
955b98c8eb | ||
|
|
0496d850d3 | ||
|
|
864d6f3032 | ||
|
|
df3a038f6d | ||
|
|
44e4222a59 | ||
|
|
6eac63c88a | ||
|
|
3c0ec23127 | ||
|
|
50e5328693 | ||
|
|
cfd88eaba1 | ||
|
|
86a3bb014d | ||
|
|
bbde42c80f | ||
|
|
0d3b353aaf | ||
|
|
7d28e0e202 | ||
|
|
5009939ae3 | ||
|
|
94a342c366 | ||
|
|
3f913b77ef | ||
|
|
24797747de | ||
|
|
810dae540a | ||
|
|
95f9aff0d9 | ||
|
|
f3d2476517 | ||
|
|
69f605171d | ||
|
|
c345638ec7 | ||
|
|
79b46bcf71 | ||
|
|
fd04332791 | ||
|
|
d6db5aabf7 | ||
|
|
f20c9d6a13 | ||
|
|
cf73e8d78d | ||
|
|
8c25e6bdc0 | ||
|
|
f851b430ce | ||
|
|
22bff227a1 | ||
|
|
9e308aa8c0 | ||
|
|
4bffbfab77 | ||
|
|
d5797cb22d | ||
|
|
36dd490504 | ||
|
|
7acb2d19b5 | ||
|
|
297b2d795b | ||
|
|
a820ef2699 | ||
|
|
31e79603d1 | ||
|
|
bb48016b3b | ||
|
|
08544ba5cb | ||
|
|
2bb3bae9d6 | ||
|
|
287ff70762 | ||
|
|
88ce442adc | ||
|
|
981e7ce009 | ||
|
|
38e2454f01 | ||
|
|
9545cb0146 | ||
|
|
3930a2c1cc | ||
|
|
77d41323e7 | ||
|
|
9a0a0c0d8b | ||
|
|
6081b0320c | ||
|
|
614cdd7b0e | ||
|
|
4f5a6cb074 | ||
|
|
fd3e3d317f | ||
|
|
fadc6cb95d | ||
|
|
1b741c8b22 | ||
|
|
b8b34804b5 | ||
|
|
ebd63f6886 | ||
|
|
978486f839 | ||
|
|
5909aede31 | ||
|
|
2df4274007 | ||
|
|
891d109b27 | ||
|
|
4b682b2ce7 | ||
|
|
51cbf2738d | ||
|
|
56adf3a77f | ||
|
|
be4b75107f | ||
|
|
995debc65c | ||
|
|
321284d69f | ||
|
|
622109b905 | ||
|
|
4bd0192e93 | ||
|
|
621d246e27 | ||
|
|
f32d36ae38 | ||
|
|
353aa7f888 | ||
|
|
ebdb5acac5 | ||
|
|
40cd680020 | ||
|
|
5c1be16756 | ||
|
|
239fd9e7ad | ||
|
|
3d68ffd154 | ||
|
|
f8e3d3bd26 | ||
|
|
7c24763f98 | ||
|
|
3ad8c3222d | ||
|
|
148c1057f2 | ||
|
|
9f9c38223a | ||
|
|
15c6cd83d5 | ||
|
|
9c1ff69fc2 | ||
|
|
9eb740507b | ||
|
|
f48e2500ce | ||
|
|
a57d3837bb | ||
|
|
4c0cad3482 | ||
|
|
d1319eeba0 | ||
|
|
9ffe8b6b6e | ||
|
|
0d1aeb93c0 | ||
|
|
1fa88c7c27 | ||
|
|
ef21843689 | ||
|
|
ff6703771d | ||
|
|
688915f6e4 | ||
|
|
bd507c09ea | ||
|
|
679a8a401e | ||
|
|
c4413a5097 | ||
|
|
705e992991 |
6
.github/ISSUE_TEMPLATE.md
vendored
Normal file
6
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<!--
|
||||
Please note: This blank issue template is meant for extraordinary issues
|
||||
that do not fit the templates. Unless you know your issue is relevant to
|
||||
Nixpkgs and requires the free-form blank issue, please use the issue
|
||||
templates instead.
|
||||
-->
|
||||
4
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
@@ -35,8 +35,8 @@ body:
|
||||
If you are using an older version, please update to the latest stable version and check if the issue persists before continuing this bug report.
|
||||
options:
|
||||
- "Please select a version."
|
||||
- "- Unstable (26.11)"
|
||||
- "- Stable (26.05)"
|
||||
- "- Unstable (26.05)"
|
||||
- "- Stable (25.11)"
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -35,8 +35,8 @@ body:
|
||||
If you are using an older version, please update to the latest stable version and check if the issue persists before continuing this bug report.
|
||||
options:
|
||||
- "Please select a version."
|
||||
- "- Unstable (26.11)"
|
||||
- "- Stable (26.05)"
|
||||
- "- Unstable (26.05)"
|
||||
- "- Stable (25.11)"
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
@@ -99,7 +99,7 @@ body:
|
||||
attributes:
|
||||
label: "Are you using nix-darwin?"
|
||||
description: |
|
||||
[`nix-darwin`](https://github.com/nix-darwin/nix-darwin) is a set of NixOS-like modules for macOS systems. Depending on your issue, this information may be relevant.
|
||||
[`nix-darwin`](https://github.com/LnL7/nix-darwin) is a set of NixOS-like modules for macOS systems. Depending on your issue, this information may be relevant.
|
||||
options:
|
||||
- "Yes, I am using nix-darwin."
|
||||
- "No, I am not using nix-darwin."
|
||||
|
||||
@@ -35,8 +35,8 @@ body:
|
||||
If you are using an older version, please update to the latest stable version and check if the issue persists before continuing this bug report.
|
||||
options:
|
||||
- "Please select a version."
|
||||
- "- Unstable (26.11)"
|
||||
- "- Stable (26.05)"
|
||||
- "- Unstable (26.05)"
|
||||
- "- Stable (25.11)"
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/04_build_failure.yml
vendored
4
.github/ISSUE_TEMPLATE/04_build_failure.yml
vendored
@@ -37,8 +37,8 @@ body:
|
||||
If you are purposefully trying to build an ancient version of a package in an older Nixpkgs, please coordinate with the [NixOS Archivists](https://matrix.to/#/#archivists:nixos.org).
|
||||
options:
|
||||
- "Please select a version."
|
||||
- "- Unstable (26.11)"
|
||||
- "- Stable (26.05)"
|
||||
- "- Unstable (26.05)"
|
||||
- "- Stable (25.11)"
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/05_update_request.yml
vendored
4
.github/ISSUE_TEMPLATE/05_update_request.yml
vendored
@@ -37,8 +37,8 @@ body:
|
||||
If the package has been updated in unstable, but you believe the update should be backported to the stable release of Nixpkgs, please file the '**Request: backport to stable**' form instead.
|
||||
options:
|
||||
- "Please select a version."
|
||||
- "- Unstable (26.11)"
|
||||
- "- Stable (26.05)"
|
||||
- "- Unstable (26.05)"
|
||||
- "- Stable (25.11)"
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/06_module_request.yml
vendored
4
.github/ISSUE_TEMPLATE/06_module_request.yml
vendored
@@ -35,8 +35,8 @@ body:
|
||||
If you are using an older or stable version, please update to the latest **unstable** version and check if the module still does not exist before continuing this request.
|
||||
options:
|
||||
- "Please select a version."
|
||||
- "- Unstable (26.11)"
|
||||
- "- Stable (26.05)"
|
||||
- "- Unstable (26.05)"
|
||||
- "- Stable (25.11)"
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
2
.github/workflows/backport.yml
vendored
2
.github/workflows/backport.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
permission-pull-requests: write
|
||||
permission-workflows: write
|
||||
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
2
.github/workflows/bot.yml
vendored
2
.github/workflows/bot.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
# https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -52,7 +52,7 @@ jobs:
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
6
.github/workflows/check.yml
vendored
6
.github/workflows/check.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
runs-on: ubuntu-slim
|
||||
timeout-minutes: 3
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: trusted
|
||||
@@ -95,7 +95,7 @@ jobs:
|
||||
runs-on: ubuntu-slim
|
||||
timeout-minutes: 3
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: trusted
|
||||
@@ -137,7 +137,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
2
.github/workflows/comment.yml
vendored
2
.github/workflows/comment.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
timeout-minutes: 2
|
||||
if: contains(github.event.comment.body, '@NixOS/nixpkgs-merge-bot merge')
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
|
||||
10
.github/workflows/eval.yml
vendored
10
.github/workflows/eval.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
ciPinBumpCommit: ${{ steps.find-pinned-commit.outputs.ciPinBumpCommit }}
|
||||
ciPinBumpCommitShort: ${{ steps.find-pinned-commit.outputs.ciPinBumpCommitShort }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: trusted
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
ci/supportedVersions.nix
|
||||
|
||||
- name: Check out the PR at the test merge commit
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ inputs.mergedSha }}
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
sudo mkswap /swap
|
||||
sudo swapon /swap
|
||||
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
@@ -256,7 +256,7 @@ jobs:
|
||||
statuses: write # creating 'Eval Summary' commit statuses
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
@@ -471,7 +471,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
|
||||
8
.github/workflows/lint.yml
vendored
8
.github/workflows/lint.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/actions
|
||||
@@ -134,7 +134,7 @@ jobs:
|
||||
runs-on: ubuntu-slim
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: true # Needed to run git fetch for large PRs.
|
||||
path: trusted
|
||||
|
||||
2
.github/workflows/merge-group.yml
vendored
2
.github/workflows/merge-group.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
targetSha: ${{ steps.prepare.outputs.targetSha }}
|
||||
systems: ${{ steps.prepare.outputs.systems }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
|
||||
2
.github/workflows/periodic-merge.yml
vendored
2
.github/workflows/periodic-merge.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
permission-contents: write
|
||||
permission-pull-requests: write
|
||||
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
2
.github/workflows/pull-request-target.yml
vendored
2
.github/workflows/pull-request-target.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
systems: ${{ steps.prepare.outputs.systems }}
|
||||
touched: ${{ steps.prepare.outputs.touched }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout-cone-mode: true # default, for clarity
|
||||
|
||||
2
.github/workflows/review.yml
vendored
2
.github/workflows/review.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
runs-on: ubuntu-slim
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
|
||||
2
.github/workflows/teams.yml
vendored
2
.github/workflows/teams.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
permission-pull-requests: write
|
||||
|
||||
- name: Fetch source
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
push: ${{ steps.files.outputs.push }}
|
||||
targetSha: ${{ steps.prepare.outputs.targetSha }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout-cone-mode: true # default, for clarity
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<a href="https://opencollective.com/nixos"><img src="https://opencollective.com/nixos/tiers/supporter/badge.svg?label=supporters&color=brightgreen" alt="Open Collective supporters" /></a>
|
||||
</p>
|
||||
|
||||
[Nixpkgs](https://github.com/nixos/nixpkgs) is a collection of over 140,000 software packages that can be installed with the [Nix](https://nixos.org/nix/) package manager.
|
||||
[Nixpkgs](https://github.com/nixos/nixpkgs) is a collection of over 120,000 software packages that can be installed with the [Nix](https://nixos.org/nix/) package manager.
|
||||
It also implements [NixOS](https://nixos.org/nixos/), a purely-functional Linux distribution.
|
||||
|
||||
# Manuals
|
||||
@@ -47,9 +47,9 @@ Here are some of the main ones:
|
||||
Nixpkgs and NixOS are built and tested by our continuous integration system, [Hydra](https://hydra.nixos.org/).
|
||||
|
||||
* [Continuous package builds for unstable/master](https://hydra.nixos.org/jobset/nixos/trunk-combined)
|
||||
* [Continuous package builds for the NixOS 26.05 release](https://hydra.nixos.org/jobset/nixos/release-26.05)
|
||||
* [Continuous package builds for the NixOS 25.11 release](https://hydra.nixos.org/jobset/nixos/release-25.11)
|
||||
* [Tests for unstable/master](https://hydra.nixos.org/job/nixos/trunk-combined/tested#tabs-constituents)
|
||||
* [Tests for the NixOS 26.05 release](https://hydra.nixos.org/job/nixos/release-26.05/tested#tabs-constituents)
|
||||
* [Tests for the NixOS 25.11 release](https://hydra.nixos.org/job/nixos/release-25.11/tested#tabs-constituents)
|
||||
|
||||
Artifacts successfully built with Hydra are published to cache at https://cache.nixos.org/.
|
||||
When successful build and test criteria are met, the Nixpkgs expressions are distributed via [Nix channels](https://nix.dev/manual/nix/stable/command-ref/nix-channel.html).
|
||||
|
||||
22
ci/OWNERS
22
ci/OWNERS
@@ -56,12 +56,6 @@
|
||||
/pkgs/top-level/splice.nix @Ericson2314
|
||||
/pkgs/top-level/release-cross.nix @Ericson2314
|
||||
/pkgs/top-level/by-name-overlay.nix @infinisil @philiptaron
|
||||
/pkgs/top-level/config.nix @jopejoe1
|
||||
/pkgs/top-level/make-tarball.nix @jopejoe1
|
||||
/pkgs/top-level/packages-config.nix @jopejoe1
|
||||
/pkgs/top-level/packages-info.nix @jopejoe1
|
||||
/pkgs/top-level/release-lib.nix @jopejoe1
|
||||
/pkgs/top-level/release.nix @jopejoe1
|
||||
/pkgs/stdenv @philiptaron @NixOS/stdenv
|
||||
/pkgs/stdenv/generic @Ericson2314 @NixOS/stdenv
|
||||
/pkgs/stdenv/generic/problems.nix @infinisil
|
||||
@@ -79,7 +73,6 @@
|
||||
|
||||
## Format generators/serializers
|
||||
/pkgs/pkgs-lib @Stunkymonkey @h7x4
|
||||
/pkgs/pkgs-lib/formats/json2x @Stunkymonkey @h7x4 @figsoda
|
||||
|
||||
# Nixpkgs build-support
|
||||
/pkgs/build-support/writers @lassulus
|
||||
@@ -131,7 +124,6 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @Artturin @Ericson2314 @lo
|
||||
|
||||
# NixOS integration test driver
|
||||
/nixos/lib/test-driver @tfc
|
||||
/nixos/lib/testing @tfc
|
||||
|
||||
# NixOS QEMU virtualisation
|
||||
/nixos/modules/virtualisation/qemu-vm.nix @raitobezarius
|
||||
@@ -277,15 +269,15 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
|
||||
/lib/licenses @alyssais @emilazy @jopejoe1
|
||||
|
||||
# Qt
|
||||
/pkgs/development/libraries/qt-5 @K900 @NickCao @SuperSandro2000
|
||||
/pkgs/development/libraries/qt-6 @K900 @NickCao @SuperSandro2000
|
||||
/pkgs/development/libraries/qt-5 @K900 @NickCao @SuperSandro2000 @ttuegel
|
||||
/pkgs/development/libraries/qt-6 @K900 @NickCao @SuperSandro2000 @ttuegel
|
||||
|
||||
# KDE Frameworks 5
|
||||
/pkgs/development/libraries/kde-frameworks @K900 @NickCao @SuperSandro2000
|
||||
/pkgs/development/libraries/kde-frameworks @K900 @NickCao @SuperSandro2000 @ttuegel
|
||||
|
||||
# KDE / Plasma 6
|
||||
/pkgs/kde @K900 @NickCao @SuperSandro2000
|
||||
/maintainers/scripts/kde @K900 @NickCao @SuperSandro2000
|
||||
/pkgs/kde @K900 @NickCao @SuperSandro2000 @ttuegel
|
||||
/maintainers/scripts/kde @K900 @NickCao @SuperSandro2000 @ttuegel
|
||||
|
||||
# PostgreSQL and related stuff
|
||||
/pkgs/by-name/po/postgresqlTestHook @NixOS/postgres
|
||||
@@ -445,7 +437,6 @@ nixos/tests/forgejo.nix @adamcstephens @bendlas @christoph-heiss @
|
||||
/doc/languages-frameworks/javascript.section.md @winterqt
|
||||
/pkgs/development/tools/pnpm @Scrumplex @gepbird
|
||||
/pkgs/build-support/node/fetch-pnpm-deps @Scrumplex @gepbird
|
||||
/pkgs/test/pnpm @Scrumplex @gepbird
|
||||
|
||||
# OCaml
|
||||
/pkgs/build-support/ocaml @ulrikstrid
|
||||
@@ -533,6 +524,3 @@ pkgs/by-name/wa/warp-terminal/ @emilytrau @imadnyc @FlameFlag @johnrtitor
|
||||
# Radicle
|
||||
/pkgs/build-support/fetchradicle/ @NixOS/radicle
|
||||
/pkgs/build-support/fetchradiclepatch/ @NixOS/radicle
|
||||
|
||||
# Zellij plugins
|
||||
/pkgs/by-name/ze/zellij/plugins/ @PerchunPak
|
||||
|
||||
@@ -207,8 +207,6 @@ When needed, each convention explains why it exists, so you can make a decision
|
||||
Note that these conventions are about the **structure** of the manual (and its source files), not about the content that goes in it.
|
||||
You, as the writer of documentation, are still in charge of its content.
|
||||
|
||||
**For prose style, see the [documentation styleguide](./styleguide.md).**
|
||||
|
||||
### One sentence per line
|
||||
|
||||
Put each sentence in its own line.
|
||||
@@ -221,16 +219,17 @@ When changing existing content, update formatting if possible, but avoid excessi
|
||||
|
||||
### Examples first
|
||||
|
||||
Put examples before detailed explanations (see the [styleguide](./styleguide.md) for the rationale).
|
||||
Readers look at examples first: an example communicates what something does faster than a description.
|
||||
Put examples before detailed explanations.
|
||||
|
||||
Use this structure for each documented item:
|
||||
Prefer this structure for each documented item:
|
||||
|
||||
1. Title
|
||||
2. Abstract (optional, one sentence max)
|
||||
2. Abstract (optional, one sentence max, the example often speaks for itself)
|
||||
3. Example
|
||||
4. Explanation (details, edge cases, types, defaults)
|
||||
|
||||
Rendered example:
|
||||
For instance:
|
||||
|
||||
````markdown
|
||||
## `lib.toUpper`
|
||||
@@ -282,9 +281,11 @@ Returns the difference as a number.
|
||||
|
||||
Use the [admonition syntax](#admonitions) for callouts and examples.
|
||||
|
||||
### `callPackage`-compatible examples
|
||||
### Provide self-contained examples
|
||||
|
||||
Provide at least one example per function.
|
||||
Provide at least one example per function, and make examples self-contained.
|
||||
This is easier to understand for beginners.
|
||||
It also helps with testing that it actually works – especially once we introduce automation.
|
||||
|
||||
Example code should be such that it can be passed to `pkgs.callPackage`.
|
||||
Instead of something like:
|
||||
|
||||
@@ -37,7 +37,6 @@ npm-install-hook.section.md
|
||||
patch-rc-path-hooks.section.md
|
||||
perl.section.md
|
||||
pkg-config.section.md
|
||||
pnpm.section.md
|
||||
postgresql-test-hook.section.md
|
||||
premake.section.md
|
||||
python.section.md
|
||||
@@ -49,7 +48,6 @@ unzip.section.md
|
||||
validatePkgConfig.section.md
|
||||
versionCheckHook.section.md
|
||||
waf.section.md
|
||||
writable-tmpdir-as-home-hook.section.md
|
||||
zig.section.md
|
||||
xcbuild.section.md
|
||||
xfce4-dev-tools.section.md
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
# pnpmBuildHook {#pnpm-build-hook}
|
||||
|
||||
[pnpm](https://pnpm.io/) is a an NPM-compatible package manager focused on increasing managment speeds, and reducing disk space.
|
||||
|
||||
The `pnpmBuildHook` in Nixpkgs overrides the default build phase for building packages that use pnpm.
|
||||
|
||||
:::{.example #ex-pnpm-build-hook}
|
||||
## pnpmBuildHook example code snippet {#pnpm-build-hook-code-snippet}
|
||||
|
||||
```
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
fetchPnpmDeps,
|
||||
pnpmConfigHook,
|
||||
pnpmBuildHook,
|
||||
makeBinaryWrapper,
|
||||
pnpm_10,
|
||||
}:
|
||||
let
|
||||
pnpm = pnpm_10;
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "coolPackages";
|
||||
version = "1.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "JaneCool";
|
||||
repo = "coolpackage";
|
||||
tag = finalAttrs.version;
|
||||
hash = lib.fakeHash;
|
||||
};
|
||||
|
||||
__structuredAttrs = true;
|
||||
strictDeps = true;
|
||||
|
||||
pnpmDeps = fetchPnpmDeps {
|
||||
inherit (finalAttrs) pname version src;
|
||||
inherit pnpm;
|
||||
fetcherversion = 4;
|
||||
hash = lib.fakeHash;
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
pnpmConfigHook
|
||||
pnpmBuildHook
|
||||
makeBinaryWrapper
|
||||
];
|
||||
|
||||
pnpmBuildScript = "build";
|
||||
pnpmBuildFlags = [
|
||||
"--mode"
|
||||
"production"
|
||||
];
|
||||
pnpmWorkspaces = [
|
||||
"test"
|
||||
];
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir "$out"
|
||||
cp -r dist/. "$out"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "very cool package that does cool things";
|
||||
mainProgram = "cool";
|
||||
};
|
||||
})
|
||||
```
|
||||
:::
|
||||
|
||||
## Variables controlling pnpmBuildHook {#pnpm-build-hook-variables}
|
||||
|
||||
### pnpm Exclusive Variables {#pnpm-build-hook-exclusive-variables}
|
||||
|
||||
#### `pnpmBuildScript` {#pnpm-build-hook-script}
|
||||
|
||||
Controls the script ran to build the package, by default the script is `build`.
|
||||
|
||||
#### `pnpmFlags` {#pnpm-build-hook-flags}
|
||||
|
||||
Controls flags used for all invocations of pnpm across all hooks local to this derivation.
|
||||
|
||||
#### `pnpmBuildFlags` {#pnpm-build-hook-build-flags}
|
||||
|
||||
Controls the flags pass only to the pnpm build script invocation.
|
||||
|
||||
#### `dontPnpmBuild` {#pnpm-build-hook-dont}
|
||||
|
||||
Disables automatically running `pnpmBuildHook`. The build can still be run manually if needed, for example:
|
||||
|
||||
```
|
||||
{
|
||||
lib,
|
||||
rustPlatform,
|
||||
pnpmBuildHook,
|
||||
pnpmConfigHook,
|
||||
fetchPnpmDeps,
|
||||
emptyDirectory,
|
||||
pnpm_10,
|
||||
}:
|
||||
let
|
||||
pnpm = pnpm_10;
|
||||
in
|
||||
rustPlatform.buildRustPackage (finalAttrs: {
|
||||
pname = "super-fast-application";
|
||||
version = "1.0";
|
||||
|
||||
src = emptyDirectory;
|
||||
|
||||
cargoHash = lib.fakeHash;
|
||||
|
||||
nativeBuildInputs = [
|
||||
pnpmBuildHook
|
||||
pnpmConfigHook
|
||||
];
|
||||
|
||||
pnpmDeps = fetchPnpmDeps {
|
||||
inherit (finalAttrs) pname version src;
|
||||
inherit pnpm;
|
||||
fetcherversion = 3;
|
||||
hash = lib.fakeHash;
|
||||
}
|
||||
|
||||
dontPnpmBuild = true;
|
||||
postBuild = ''
|
||||
pnpmBuildHook
|
||||
'';
|
||||
})
|
||||
```
|
||||
|
||||
### Honored Variables {#pnpm-build-hook-honored-variables}
|
||||
|
||||
The following variables are honored by `pnpmBuildHook`.
|
||||
|
||||
* [`pnpmRoot`](#javascript-pnpm-sourceRoot)
|
||||
* [`pnpmWorkspaces`](#javascript-pnpm-workspaces)
|
||||
@@ -1,5 +0,0 @@
|
||||
# writableTmpDirAsHomeHook {#writableTmpDirAsHomeHook}
|
||||
|
||||
This setup hook provides a writable home directory for packages that require it.
|
||||
|
||||
To use, just add the hook to the `nativeBuildInputs` of the package.
|
||||
@@ -309,8 +309,6 @@ pnpm is available as the top-level package `pnpm`. Additionally, there are varia
|
||||
|
||||
When packaging an application that includes a `pnpm-lock.yaml`, you need to fetch the pnpm store for that project using a fixed-output-derivation. The function `fetchPnpmDeps` can create this pnpm store derivation. In conjunction, the setup hook `pnpmConfigHook` will prepare the build environment to install the pre-fetched dependencies store. Here is an example for a package that contains `package.json` and a `pnpm-lock.yaml` files using the fetcher and setup hook above:
|
||||
|
||||
There is also the [`pnpmBuildHook`](#pnpm-build-hook) for building packages with `pnpm`, as seen in [](#ex-pnpm-build-hook).
|
||||
|
||||
```nix
|
||||
{
|
||||
fetchPnpmDeps,
|
||||
@@ -366,7 +364,7 @@ It is highly recommended to use a pinned version of pnpm (i.e., `pnpm_9` or `pnp
|
||||
+let
|
||||
+ # Optionally override pnpm to use a custom nodejs version
|
||||
+ # Make sure that the same nodejs version is referenced in nativeBuildInputs
|
||||
+ # pnpm = pnpm_10.override { nodejs-slim = nodejs-slim_22; };
|
||||
+ # pnpm = pnpm_10.override { nodejs = nodejs-slim_22; };
|
||||
+in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "foo";
|
||||
@@ -513,10 +511,10 @@ Changes can include workarounds or bug fixes to existing PNPM issues.
|
||||
|
||||
##### Version history {#javascript-pnpm-fetcherVersion-versionHistory}
|
||||
|
||||
Version 3 is the minimum supported value. Versions 1 and 2 were removed in the 26.11 release; packages that still use them fail to evaluate and must migrate to `fetcherVersion = 3` (or later) and regenerate their hashes.
|
||||
Version 3 is the recommended value for new packages. Versions 1 and 2 are deprecated and scheduled for removal in the 26.11 release; existing packages must migrate.
|
||||
|
||||
- 1: Initial version, nothing special. (removed in 26.11)
|
||||
- 2: [Ensure consistent permissions](https://github.com/NixOS/nixpkgs/pull/422975) (removed in 26.11)
|
||||
- 1: Initial version, nothing special.
|
||||
- 2: [Ensure consistent permissions](https://github.com/NixOS/nixpkgs/pull/422975)
|
||||
- 3: [Build a reproducible tarball](https://github.com/NixOS/nixpkgs/pull/469950)
|
||||
- 4: [Dump SQLite database to an SQL file](https://github.com/NixOS/nixpkgs/pull/522703)
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ The following is an example:
|
||||
vyp
|
||||
lblasc
|
||||
];
|
||||
license = lib.licenses.mit;
|
||||
license.fullName = "MIT/X11";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ Based on the packages defined in `pkgs/top-level/python-packages.nix` an
|
||||
attribute set is created for each available Python interpreter. The available
|
||||
sets are
|
||||
|
||||
* `pkgs.python27Packages`
|
||||
* `pkgs.python3Packages`
|
||||
* `pkgs.python311Packages`
|
||||
* `pkgs.python312Packages`
|
||||
@@ -59,7 +60,9 @@ sets are
|
||||
|
||||
and the aliases
|
||||
|
||||
* `pkgs.python2Packages` pointing to `pkgs.python27Packages`
|
||||
* `pkgs.python3Packages` pointing to `pkgs.python313Packages`
|
||||
* `pkgs.pythonPackages` pointing to `pkgs.python2Packages`
|
||||
* `pkgs.pypy2Packages` pointing to `pkgs.pypy27Packages`
|
||||
* `pkgs.pypy3Packages` pointing to `pkgs.pypy310Packages`
|
||||
* `pkgs.pypyPackages` pointing to `pkgs.pypy2Packages`
|
||||
@@ -284,27 +287,29 @@ because their behaviour is different:
|
||||
The `buildPythonPackage` function has a `overridePythonAttrs` method that can be
|
||||
used to override the package. In the following example we create an environment
|
||||
where we have the `blaze` package using an older version of `pandas`. We
|
||||
first override the Python package set, then instantiate an interpreter with
|
||||
that package set.
|
||||
override first the Python interpreter and pass `packageOverrides` which contains
|
||||
the overrides for packages in the package set.
|
||||
|
||||
```nix
|
||||
with import <nixpkgs> { };
|
||||
|
||||
let
|
||||
pythonPackages = python3Packages.overrideScope (
|
||||
final: prev: {
|
||||
pandas = prev.pandas.overridePythonAttrs (old: rec {
|
||||
version = "0.19.1";
|
||||
src = fetchPypi {
|
||||
pname = "pandas";
|
||||
inherit version;
|
||||
hash = "sha256-JQn+rtpy/OA2deLszSKEuxyttqBzcAil50H+JDHUdCE=";
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
python = pkgs.python3.override {
|
||||
packageOverrides = self: super: {
|
||||
pandas = super.pandas.overridePythonAttrs (
|
||||
finalAttrs: prevAttrs: {
|
||||
version = "0.19.1";
|
||||
src = fetchPypi {
|
||||
pname = "pandas";
|
||||
inherit (finalAttrs) version;
|
||||
hash = "sha256-JQn+rtpy/OA2deLszSKEuxyttqBzcAil50H+JDHUdCE=";
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
in
|
||||
(pythonPackages.python.withPackages (ps: [ ps.blaze ])).env
|
||||
(python.withPackages (ps: [ ps.blaze ])).env
|
||||
```
|
||||
|
||||
The next example shows a non trivial overriding of the `blas` implementation to
|
||||
@@ -312,16 +317,15 @@ be used through out all of the Python package set:
|
||||
|
||||
```nix
|
||||
{
|
||||
python3PackagesWithBlas = python3Packages.overrideScope (
|
||||
final: prev: {
|
||||
python3MyBlas = pkgs.python3.override {
|
||||
packageOverrides = self: super: {
|
||||
# We need toPythonModule for the package set to evaluate this
|
||||
blas = final.toPythonModule (prev.blas.override { blasProvider = final.mkl; });
|
||||
lapack = final.toPythonModule (prev.lapack.override { lapackProvider = final.mkl; });
|
||||
}
|
||||
);
|
||||
blas = super.toPythonModule (super.pkgs.blas.override { blasProvider = super.pkgs.mkl; });
|
||||
lapack = super.toPythonModule (super.pkgs.lapack.override { lapackProvider = super.pkgs.mkl; });
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
This will create a new Python package set with the blas and lapack implementation set to Intel MKL.
|
||||
|
||||
This is particularly useful for numpy and scipy users who want to gain speed with other blas implementations.
|
||||
Note that using `scipy = super.scipy.override { blas = super.pkgs.mkl; };` will likely result in
|
||||
@@ -453,10 +457,11 @@ Note that overriding packages deeper in the dependency graph _can_ work, but it'
|
||||
let
|
||||
pyproject = pkgs.lib.importTOML ./pyproject.toml;
|
||||
|
||||
myPython3Packages = pkgs.python3Packages.overrideScope (
|
||||
final: _: {
|
||||
myPython = pkgs.python.override {
|
||||
self = myPython;
|
||||
packageOverrides = pyfinal: pyprev: {
|
||||
# An editable package with a script that loads our mutable location
|
||||
my-editable = final.mkPythonEditablePackage {
|
||||
my-editable = pyfinal.mkPythonEditablePackage {
|
||||
# Inherit project metadata from pyproject.toml
|
||||
pname = pyproject.project.name;
|
||||
inherit (pyproject.project) version;
|
||||
@@ -467,10 +472,10 @@ let
|
||||
# Inject a script (other PEP-621 entrypoints are also accepted)
|
||||
inherit (pyproject.project) scripts;
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
pythonEnv = myPython3Packages.python.withPackages (ps: [ ps.my-editable ]);
|
||||
pythonEnv = myPython.withPackages (ps: [ ps.my-editable ]);
|
||||
|
||||
in
|
||||
pkgs.mkShell { packages = [ pythonEnv ]; }
|
||||
@@ -570,6 +575,9 @@ In contrast to [`python.buildEnv`](#python.buildenv-function), [`python.withPack
|
||||
more advanced options such as `ignoreCollisions = true` or `postBuild`. If you
|
||||
need them, you have to use [`python.buildEnv`](#python.buildenv-function).
|
||||
|
||||
Python 2 namespace packages may provide `__init__.py` that collide. In that case
|
||||
[`python.buildEnv`](#python.buildenv-function) should be used with `ignoreCollisions = true`.
|
||||
|
||||
#### Setup hooks {#setup-hooks}
|
||||
|
||||
The following are setup hooks specifically for Python packages. Most of these
|
||||
@@ -621,9 +629,10 @@ buildPythonPackage.override { stdenv = customStdenv; } {
|
||||
|
||||
Several versions of the Python interpreter are available on Nix, as well as a
|
||||
high amount of packages. The attribute `python3` refers to the default
|
||||
interpreter, which is currently CPython 3.13. It is also possible to refer to
|
||||
specific versions, e.g., `python313` refers to CPython 3.13, and `pypy` refers
|
||||
to the default PyPy interpreter.
|
||||
interpreter, which is currently CPython 3.13. The attribute `python` refers to
|
||||
CPython 2.7 for backwards compatibility. It is also possible to refer to
|
||||
specific versions, e.g., `python313` refers to CPython 3.13, and `pypy` refers to
|
||||
the default PyPy interpreter.
|
||||
|
||||
Python is used a lot, and in different ways. This affects also how it is
|
||||
packaged. In the case of Python on Nix, an important distinction is made between
|
||||
@@ -635,6 +644,14 @@ In the Nixpkgs tree Python applications can be found throughout, depending on
|
||||
what they do, and are called from the main package set. Python libraries,
|
||||
however, are in separate sets, with one set per interpreter version.
|
||||
|
||||
The interpreters have several common attributes. One of these attributes is
|
||||
`pkgs`, which is a package set of Python libraries for this specific
|
||||
interpreter. E.g., the `toolz` package corresponding to the default interpreter
|
||||
is `python3.pkgs.toolz`, and the CPython 3.13 version is `python313.pkgs.toolz`.
|
||||
The main package set contains aliases to these package sets, e.g.
|
||||
`pythonPackages` refers to `python.pkgs` and `python313Packages` to
|
||||
`python313.pkgs`.
|
||||
|
||||
#### Installing Python and packages {#installing-python-and-packages}
|
||||
|
||||
The Nix and NixOS manuals explain how packages are generally installed. In the
|
||||
@@ -1004,7 +1021,7 @@ information. The output of the function is a derivation.
|
||||
|
||||
An expression for `toolz` can be found in the Nixpkgs repository. As explained
|
||||
in the introduction of this Python section, a derivation of `toolz` is available
|
||||
for each interpreter version, e.g. `python313Packages.toolz` refers to the `toolz`
|
||||
for each interpreter version, e.g. `python313.pkgs.toolz` refers to the `toolz`
|
||||
derivation corresponding to the CPython 3.13 interpreter.
|
||||
|
||||
The above example works when you're directly working on
|
||||
@@ -1019,7 +1036,7 @@ with import <nixpkgs> { };
|
||||
|
||||
(
|
||||
let
|
||||
my_toolz = python313Packages.buildPythonPackage (finalAttrs: {
|
||||
my_toolz = python313.pkgs.buildPythonPackage (finalAttrs: {
|
||||
pname = "toolz";
|
||||
version = "0.10.0";
|
||||
pyproject = true;
|
||||
@@ -1029,7 +1046,7 @@ with import <nixpkgs> { };
|
||||
hash = "sha256-CP3V73yWSArRHBLUct4hrNMjWZlvaaUlkpm1QP66RWA=";
|
||||
};
|
||||
|
||||
build-system = [ python313Packages.setuptools ];
|
||||
build-system = [ python313.pkgs.setuptools ];
|
||||
|
||||
# has no tests
|
||||
doCheck = false;
|
||||
@@ -1042,7 +1059,7 @@ with import <nixpkgs> { };
|
||||
});
|
||||
|
||||
in
|
||||
python313Packages.python.withPackages (
|
||||
python313.withPackages (
|
||||
ps: with ps; [
|
||||
numpy
|
||||
my_toolz
|
||||
@@ -1063,11 +1080,6 @@ of [`withPackages`](#python.withpackages-function) we used a `let` expression. Y
|
||||
`toolz` from the Nixpkgs package set this time, but instead took our own version
|
||||
that we introduced with the `let` expression.
|
||||
|
||||
There is also a legacy API that can be accessed via `python3.pkgs`, which will also give access to
|
||||
the Python package set for a given interpreter. This API is not recommended to be used anymore
|
||||
because the package set at `python3.pkgs` is not spliced, while the package set at `python3Packages`
|
||||
is. This can lead to strange errors during cross-compilation, or if Python is used at build time.
|
||||
|
||||
#### Handling dependencies {#handling-dependencies}
|
||||
|
||||
Our example, `toolz`, does not have any dependencies on other Python packages or system libraries.
|
||||
@@ -1705,22 +1717,27 @@ should also be done when packaging `A`.
|
||||
|
||||
### How to override a Python package? {#how-to-override-a-python-package}
|
||||
|
||||
We can override the Python package set, then instantiate an interpreter with it.
|
||||
In the following example we rename the `pandas` package and build it.
|
||||
We can override the interpreter and pass `packageOverrides`. In the following
|
||||
example we rename the `pandas` package and build it.
|
||||
|
||||
```nix
|
||||
with import <nixpkgs> { };
|
||||
|
||||
let
|
||||
pythonPackages = python3Packages.overrideScope (
|
||||
final: prev: {
|
||||
pandas = prev.pandas.overridePythonAttrs {
|
||||
name = "foo";
|
||||
};
|
||||
}
|
||||
);
|
||||
in
|
||||
(pythonPackages.python.withPackages (ps: [ ps.pandas ])).env
|
||||
(
|
||||
let
|
||||
python =
|
||||
let
|
||||
packageOverrides = self: super: {
|
||||
pandas = super.pandas.overridePythonAttrs (old: {
|
||||
name = "foo";
|
||||
});
|
||||
};
|
||||
in
|
||||
pkgs.python313.override { inherit packageOverrides; };
|
||||
|
||||
in
|
||||
python.withPackages (ps: [ ps.pandas ])
|
||||
).env
|
||||
```
|
||||
|
||||
Using `nix-build` on this expression will build an environment that contains the
|
||||
@@ -1736,10 +1753,12 @@ the updated `scipy` version.
|
||||
```nix
|
||||
with import <nixpkgs> { };
|
||||
|
||||
let
|
||||
pythonPackages = python313Packages.overrideScope (_: prev: { scipy = prev.scipy_0_17; });
|
||||
in
|
||||
(pythonPackages.python.withPackages (ps: [ ps.blaze ])).env
|
||||
(
|
||||
let
|
||||
packageOverrides = self: super: { scipy = super.scipy_0_17; };
|
||||
in
|
||||
(pkgs.python313.override { inherit packageOverrides; }).withPackages (ps: [ ps.blaze ])
|
||||
).env
|
||||
```
|
||||
|
||||
The requested package `blaze` depends on `pandas` which itself depends on `scipy`.
|
||||
@@ -1753,16 +1772,14 @@ let
|
||||
pkgs = import <nixpkgs> { };
|
||||
newpkgs = import pkgs.path {
|
||||
overlays = [
|
||||
(_: prev: {
|
||||
(self: super: {
|
||||
python313 =
|
||||
let
|
||||
pythonPackages = prev.python313Packages.overrideScope (
|
||||
_: prev: {
|
||||
numpy = prev.numpy_1_18;
|
||||
}
|
||||
);
|
||||
packageOverrides = python-self: python-super: {
|
||||
numpy = python-super.numpy_1_18;
|
||||
};
|
||||
in
|
||||
pythonPackages.python3;
|
||||
super.python313.override { inherit packageOverrides; };
|
||||
})
|
||||
];
|
||||
};
|
||||
@@ -1903,8 +1920,9 @@ pkgs.mkShell rec {
|
||||
}
|
||||
```
|
||||
|
||||
In case the supplied venvShellHook is insufficient, you can define your own
|
||||
shell hook and adapt to your needs like in the following example:
|
||||
In case the supplied venvShellHook is insufficient, or when Python 2 support is
|
||||
needed, you can define your own shell hook and adapt to your needs like in the
|
||||
following example:
|
||||
|
||||
```nix
|
||||
with import <nixpkgs> { };
|
||||
@@ -1917,6 +1935,8 @@ pkgs.mkShell rec {
|
||||
name = "impurePythonEnv";
|
||||
buildInputs = [
|
||||
pythonPackages.python
|
||||
# Needed when using python 2.7
|
||||
# pythonPackages.virtualenv
|
||||
# ...
|
||||
];
|
||||
|
||||
@@ -1929,6 +1949,8 @@ pkgs.mkShell rec {
|
||||
echo "Skipping venv creation, '${venvDir}' already exists"
|
||||
else
|
||||
echo "Creating new venv environment in path: '${venvDir}'"
|
||||
# Note that the module venv was only introduced in python 3, so for 2.7
|
||||
# this needs to be replaced with a call to virtualenv
|
||||
${pythonPackages.python.interpreter} -m venv "${venvDir}"
|
||||
fi
|
||||
|
||||
@@ -1955,17 +1977,19 @@ If you need to change a package's attribute(s) from `configuration.nix` you coul
|
||||
|
||||
```nix
|
||||
{
|
||||
nixpkgs.config.packageOverrides = final: _: {
|
||||
python3Packages = super.python3Packages.overrideScope (pySuper: {
|
||||
twisted = pySuper.twisted.overridePythonAttrs {
|
||||
src = final.fetchPypi {
|
||||
pname = "Twisted";
|
||||
version = "19.10.0";
|
||||
hash = "sha256-c5S6fycq5yKnTz2Wnc9Zm8TvCTvDkgOHSKSQ8XJKUV0=";
|
||||
extension = "tar.bz2";
|
||||
};
|
||||
nixpkgs.config.packageOverrides = super: {
|
||||
python3 = super.python3.override {
|
||||
packageOverrides = python-self: python-super: {
|
||||
twisted = python-super.twisted.overridePythonAttrs (oldAttrs: {
|
||||
src = super.fetchPypi {
|
||||
pname = "Twisted";
|
||||
version = "19.10.0";
|
||||
hash = "sha256-c5S6fycq5yKnTz2Wnc9Zm8TvCTvDkgOHSKSQ8XJKUV0=";
|
||||
extension = "tar.bz2";
|
||||
};
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
@@ -1981,7 +2005,7 @@ this snippet:
|
||||
|
||||
```nix
|
||||
{
|
||||
myPythonPackages = python3Packages.overrideScope (final: super: { twisted = <...>; });
|
||||
myPythonPackages = python3Packages.override { overrides = self: super: { twisted = <...>; }; };
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1990,17 +2014,19 @@ this snippet:
|
||||
Use the following overlay template:
|
||||
|
||||
```nix
|
||||
self: _: {
|
||||
python3Packages = super.python3Packages.overrideScope (pySuper: {
|
||||
twisted = pySuper.twisted.overrideAttrs {
|
||||
src = final.fetchPypi {
|
||||
pname = "Twisted";
|
||||
version = "19.10.0";
|
||||
hash = "sha256-c5S6fycq5yKnTz2Wnc9Zm8TvCTvDkgOHSKSQ8XJKUV0=";
|
||||
extension = "tar.bz2";
|
||||
};
|
||||
self: super: {
|
||||
python = super.python.override {
|
||||
packageOverrides = python-self: python-super: {
|
||||
twisted = python-super.twisted.overrideAttrs (oldAttrs: {
|
||||
src = super.fetchPypi {
|
||||
pname = "Twisted";
|
||||
version = "19.10.0";
|
||||
hash = "sha256-c5S6fycq5yKnTz2Wnc9Zm8TvCTvDkgOHSKSQ8XJKUV0=";
|
||||
extension = "tar.bz2";
|
||||
};
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ Note that if the builder is running and you have created the above ssh conf file
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-22.11-darwin";
|
||||
darwin.url = "github:nix-darwin/nix-darwin/master";
|
||||
darwin.url = "github:lnl7/nix-darwin/master";
|
||||
darwin.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
|
||||
@@ -113,9 +113,6 @@
|
||||
"ex-pkgs-replace-vars-with": [
|
||||
"index.html#ex-pkgs-replace-vars-with"
|
||||
],
|
||||
"ex-pnpm-build-hook": [
|
||||
"index.html#ex-pnpm-build-hook"
|
||||
],
|
||||
"ex-shfmt": [
|
||||
"index.html#ex-shfmt"
|
||||
],
|
||||
@@ -349,33 +346,6 @@
|
||||
"pkgs.treefmt.withConfig": [
|
||||
"index.html#pkgs.treefmt.withConfig"
|
||||
],
|
||||
"pnpm-build-hook": [
|
||||
"index.html#pnpm-build-hook"
|
||||
],
|
||||
"pnpm-build-hook-build-flags": [
|
||||
"index.html#pnpm-build-hook-build-flags"
|
||||
],
|
||||
"pnpm-build-hook-code-snippet": [
|
||||
"index.html#pnpm-build-hook-code-snippet"
|
||||
],
|
||||
"pnpm-build-hook-dont": [
|
||||
"index.html#pnpm-build-hook-dont"
|
||||
],
|
||||
"pnpm-build-hook-exclusive-variables": [
|
||||
"index.html#pnpm-build-hook-exclusive-variables"
|
||||
],
|
||||
"pnpm-build-hook-flags": [
|
||||
"index.html#pnpm-build-hook-flags"
|
||||
],
|
||||
"pnpm-build-hook-script": [
|
||||
"index.html#pnpm-build-hook-script"
|
||||
],
|
||||
"pnpm-build-hook-variables": [
|
||||
"index.html#pnpm-build-hook-variables"
|
||||
],
|
||||
"pnpm-build-hook-honored-variables": [
|
||||
"index.html#pnpm-build-hook-honored-variables"
|
||||
],
|
||||
"preface": [
|
||||
"index.html#preface"
|
||||
],
|
||||
@@ -442,9 +412,6 @@
|
||||
"sec-meta-identifiers-cpe": [
|
||||
"index.html#sec-meta-identifiers-cpe"
|
||||
],
|
||||
"sec-meta-identifiers-purl": [
|
||||
"index.html#sec-meta-identifiers-purl"
|
||||
],
|
||||
"sec-modify-via-packageOverrides": [
|
||||
"index.html#sec-modify-via-packageOverrides"
|
||||
],
|
||||
@@ -466,30 +433,6 @@
|
||||
"chap-overlays": [
|
||||
"index.html#chap-overlays"
|
||||
],
|
||||
"sec-nixpkgs-release-26.11": [
|
||||
"release-notes.html#sec-nixpkgs-release-26.11"
|
||||
],
|
||||
"sec-nixpkgs-release-26.11-highlights": [
|
||||
"release-notes.html#sec-nixpkgs-release-26.11-highlights"
|
||||
],
|
||||
"sec-nixpkgs-release-26.11-incompatibilities": [
|
||||
"release-notes.html#sec-nixpkgs-release-26.11-incompatibilities"
|
||||
],
|
||||
"sec-nixpkgs-release-26.11-lib": [
|
||||
"release-notes.html#sec-nixpkgs-release-26.11-lib"
|
||||
],
|
||||
"sec-nixpkgs-release-26.11-lib-breaking": [
|
||||
"release-notes.html#sec-nixpkgs-release-26.11-lib-breaking"
|
||||
],
|
||||
"sec-nixpkgs-release-26.11-lib-deprecations": [
|
||||
"release-notes.html#sec-nixpkgs-release-26.11-lib-deprecations"
|
||||
],
|
||||
"sec-nixpkgs-release-26.11-lib-additions-improvements": [
|
||||
"release-notes.html#sec-nixpkgs-release-26.11-lib-additions-improvements"
|
||||
],
|
||||
"sec-nixpkgs-release-26.11-notable-changes": [
|
||||
"release-notes.html#sec-nixpkgs-release-26.11-notable-changes"
|
||||
],
|
||||
"sec-nixpkgs-release-26.05": [
|
||||
"release-notes.html#sec-nixpkgs-release-26.05"
|
||||
],
|
||||
@@ -968,15 +911,6 @@
|
||||
"var-meta-identifiers-possibleCPEs": [
|
||||
"index.html#var-meta-identifiers-possibleCPEs"
|
||||
],
|
||||
"var-meta-identifiers-purl": [
|
||||
"index.html#var-meta-identifiers-purl"
|
||||
],
|
||||
"var-meta-identifiers-purlParts": [
|
||||
"index.html#var-meta-identifiers-purlParts"
|
||||
],
|
||||
"var-meta-identifiers-purls": [
|
||||
"index.html#var-meta-identifiers-purls"
|
||||
],
|
||||
"var-meta-teams": [
|
||||
"index.html#var-meta-teams"
|
||||
],
|
||||
@@ -1085,9 +1019,6 @@
|
||||
"tar-files": [
|
||||
"index.html#tar-files"
|
||||
],
|
||||
"writableTmpDirAsHomeHook": [
|
||||
"index.html#writableTmpDirAsHomeHook"
|
||||
],
|
||||
"x86_64-darwin-26.05": [
|
||||
"release-notes.html#x86_64-darwin-26.05"
|
||||
],
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
This section lists the release notes for each stable version of Nixpkgs and the current unstable revision.
|
||||
|
||||
```{=include=} sections
|
||||
rl-2611.section.md
|
||||
rl-2605.section.md
|
||||
rl-2511.section.md
|
||||
rl-2505.section.md
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Nixpkgs 26.11 ("Zokor", 2026.11/??) {#sec-nixpkgs-release-26.11}
|
||||
# Nixpkgs 26.11 (2026.11/??) {#sec-nixpkgs-release-26.11}
|
||||
|
||||
## Highlights {#sec-nixpkgs-release-26.11-highlights}
|
||||
|
||||
@@ -10,41 +10,13 @@
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
|
||||
- `databricks-cli` has been updated from `0.290.2` to `1.x.x`, the first major release. OAuth tokens for interactive logins (`auth_type = databricks-cli`) are now stored in the OS-native secure store by default (Secret Service on Linux) instead of `~/.databricks/token-cache.json`; cached tokens from older versions are not migrated, so run `databricks auth login` once per profile after upgrading. To keep the previous file-backed storage, set `DATABRICKS_AUTH_STORAGE=plaintext` or add `auth_storage = plaintext` under `[__settings__]` in `~/.databrickscfg`. Additionally, the `vector_search_endpoints` DABs resource renamed `min_qps` to `target_qps` (and the `vector-search-endpoints` command renamed `--min-qps` to `--target-qps`). See the [upstream changelog](https://github.com/databricks/cli/blob/main/CHANGELOG.md) for details.
|
||||
|
||||
- `hurl` has been updated to `8.x.x` which has some breaking changes. See [upstream changelog](https://github.com/Orange-OpenSource/hurl/releases/tag/8.0.0) for details.
|
||||
- `python3Packages.django-health-check` has been updated to major version 4. See its [migration guide](https://codingjoe.dev/django-health-check/migrate-to-v4/) and [changelog](https://github.com/codingjoe/django-health-check/releases/tag/4.0.0) for breaking changes.
|
||||
|
||||
- `libgdata` has been removed, as it was archived upstream and relied on the insecure libsoup 2.4.
|
||||
|
||||
- `uhttpmock` providing 0.0 ABI was removed. `uhttpmock_1_0` providing 1.0 ABI was renamed to `uhttpmock` and `uhttpmock_1_0` was kept as an alias.
|
||||
|
||||
- The ARMv5 Linux kernel build now uses a standard configuration and generates a standard compressed image instead of the deprecated legacy U‐Boot image format.
|
||||
`lib.systems.{examples,platforms}.{sheevaplug,pogoplug4}` have been unified into `lib.systems.examples.armv5tel-multiplatform`.
|
||||
Note that there is no official support for ARMv5 and it is not possible to build even a simple NixOS configuration out of the box.
|
||||
|
||||
- Support for the legacy U‐Boot image format has been removed from the Linux kernel builders, as it is deprecated upstream and no longer used by any platform in Nixpkgs.
|
||||
|
||||
- `requireFile` now sets `meta.license = lib.licenses.unfree` by default. Users of `requireFile`-based derivations that preserve this default will need to explicitly allow their evaluation as described in [](#sec-allow-unfree).
|
||||
|
||||
- `librest` providing 0.7 ABI was removed. `librest_1_0` providing 1.0 ABI was renamed to `librest` and `librest_1_0` was kept as an alias.
|
||||
|
||||
- `fetchPnpmDeps`' `fetcherVersion = 1` and `fetcherVersion = 2` have been
|
||||
removed, as announced in the 26.05 release. Packages still using them now
|
||||
throw an evaluation error and must migrate to `fetcherVersion = 3` (or later)
|
||||
and regenerate their hashes. See the
|
||||
[pnpm `fetcherVersion` section](#javascript-pnpm-fetcherVersion) of the manual
|
||||
for details.
|
||||
- Create the first release note entry in this section!
|
||||
|
||||
## Other Notable Changes {#sec-nixpkgs-release-26.11-notable-changes}
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
|
||||
- Package-URL (PURL, https://github.com/package-url/purl-spec) metadata identifier has been added for `fetchgit`, `fetchpypi` and `fetchFromGithub` fetchers.
|
||||
`mkDerivation` has been adjusted to reuse this information.
|
||||
Package-URLs allow reliably identifying and locating software packages.
|
||||
Maintainers of derivations using the adapted fetchers should rely on the `drv.src.meta.identifiers.v1.purl` default identifier and can enhance their `drv.meta.identifiers.v1.purls` list once they would like to have additional identifiers.
|
||||
Maintainers using `fetchurl` for `drv.src` are urged to adapt their `drv.meta.identifiers.purlParts` for proper identification.
|
||||
- Create the first release note entry in this section!
|
||||
|
||||
## Nixpkgs Library {#sec-nixpkgs-release-26.11-lib}
|
||||
|
||||
|
||||
@@ -157,8 +157,6 @@ The list of Nix platform types for which the [Hydra](https://github.com/nixos/hy
|
||||
}
|
||||
```
|
||||
|
||||
Note that this does not affect whether reverse dependencies of the package are built on Hydra.
|
||||
|
||||
### `broken` {#var-meta-broken}
|
||||
|
||||
If set to `true`, the package is marked as "broken", meaning that it won’t show up in [search.nixos.org](https://search.nixos.org/packages), and cannot be built or installed unless [explicitly allowed](#sec-allow-broken).
|
||||
@@ -342,30 +340,3 @@ A readonly attribute that concatenates all CPE parts in one string.
|
||||
#### `meta.identifiers.possibleCPEs` {#var-meta-identifiers-possibleCPEs}
|
||||
|
||||
A readonly attribute containing the list of guesses for what CPE for this package can look like. It includes all variants of version handling mentioned above. Each item is an attrset with attributes `cpeParts` and `cpe` for each guess.
|
||||
|
||||
### Package URL {#sec-meta-identifiers-purl}
|
||||
|
||||
[Package-URL](https://github.com/package-url/purl-spec) (PURL) is a specification to reliably identify and locate software packages.
|
||||
Through identification of software packages, additional (non-major) use cases are e.g. software license cross-verification via third party databases or initial vulnerability response management.
|
||||
Package-URLs shall default to the `mkDerivation.src`, as the original consumed software package is the single source of truth.
|
||||
|
||||
#### `meta.identifiers.purlParts` {#var-meta-identifiers-purlParts}
|
||||
|
||||
This attribute contains an attribute set of all parts of the PURL for this package.
|
||||
|
||||
* `type` mandatory [type](https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/docs/standard/summary.md) which needs to be provided
|
||||
* `spec` specify the PURL in accordance with the [purl-spec](https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/purl-specification.md)
|
||||
|
||||
#### `meta.identifiers.purl` {#var-meta-identifiers-purl}
|
||||
|
||||
An extendable attribute which is built based on `purlParts`.
|
||||
This is the main identifier of the software package.
|
||||
For handling edge cases, consider using the list interface [`meta.identifiers.purls`](#var-meta-identifiers-purls).
|
||||
|
||||
#### `meta.identifiers.purls` {#var-meta-identifiers-purls}
|
||||
|
||||
An extendable list attribute which defaults to a single element equal to [`meta.identifiers.purl`](#var-meta-identifiers-purl).
|
||||
It provides an interface for additional identifiers of `mkDerivation.src` or for identifiers of vendored dependencies inside `mkDerivation.src`, which maintainers may carefully consider to specify as well.
|
||||
|
||||
Additional identifiers are generally not recommended, as they might cause maintenance overhead or diverge.
|
||||
For example, a source distribution `pkg:github` may be hard to keep correctly aligned with the corresponding binary distribution `pkg:pypi`.
|
||||
|
||||
@@ -1,420 +0,0 @@
|
||||
# Styleguide
|
||||
|
||||
## Writing Principles
|
||||
|
||||
A consistent style greatly increases the usability of all documentation and communication.
|
||||
|
||||
Use this page as a reference and style guide for our internal and external documentation.
|
||||
|
||||
### Knowledge Expectations
|
||||
|
||||
**Assume competence, not familiarity.**
|
||||
|
||||
Write for someone who knows a great deal — up to but not including this project.
|
||||
|
||||
**What readers know:**
|
||||
|
||||
- Basic computer operation
|
||||
- Command line familiarity
|
||||
- General interest in systems configuration
|
||||
|
||||
**What readers don't know:**
|
||||
|
||||
- NixOS-specific concepts
|
||||
- NixOS ecosystem details or grammar
|
||||
- NixOS workflows
|
||||
|
||||
If specific knowledge is required, mention it at the start of the page.
|
||||
|
||||
#### Show, Don't Tell
|
||||
|
||||
The fastest path to understanding is a working example.
|
||||
People learn by doing, not by reading about doing.
|
||||
|
||||
**Recommended structure:**
|
||||
|
||||
- Start with the minimal working code or command
|
||||
- Briefly explain what it does
|
||||
- Cover edge cases or variations
|
||||
- Link to further information instead of including it
|
||||
|
||||
#### Grammar and Style
|
||||
|
||||
**Sentence structure:**
|
||||
|
||||
- Use simple, direct sentences
|
||||
- Break complex ideas into multiple short sentences
|
||||
- Avoid nested clauses
|
||||
|
||||
**Bad:**
|
||||
|
||||
> The following command, which utilizes nixos-generate-config to produce a comprehensive hardware configuration, will write the results back into the respective configuration directory located on your local machine.
|
||||
|
||||
What the user does is hidden in the middle.
|
||||
`nixos-generate-config` is a leaked implementation detail.
|
||||
Users care about *detecting hardware*, not *the tool that does it*.
|
||||
|
||||
**Good:**
|
||||
|
||||
> This command detects your hardware and saves the configuration.
|
||||
|
||||
#### Content Organization
|
||||
|
||||
Lead with value. State what the reader will accomplish before explaining how.
|
||||
|
||||
**Bad:**
|
||||
|
||||
> To create a new NixOS configuration that you can later use as a webserver, first navigate to your project directory, then add a new host configuration file with the desired machine name.
|
||||
|
||||
**Good:**
|
||||
|
||||
Add a webserver configuration to your NixOS setup:
|
||||
|
||||
```nix
|
||||
# hosts/webserver/configuration.nix
|
||||
{ ... }:
|
||||
{
|
||||
services.nginx.enable = true;
|
||||
}
|
||||
```
|
||||
|
||||
Use **progressive disclosure**. Introduce concepts only when needed.
|
||||
|
||||
**Recommended structure:**
|
||||
|
||||
1. State the goal (one sentence)
|
||||
2. Show the simplest working example
|
||||
3. Explain concepts if needed
|
||||
4. Provide advanced options separately or link to the reference
|
||||
|
||||
#### No Meta-commentary
|
||||
|
||||
Don't describe what the documentation does. Just do it.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> This section explains how to configure networking.
|
||||
> The following guide walks you through setting up a web server.
|
||||
|
||||
**Do:**
|
||||
|
||||
> Configure networking by setting:
|
||||
> Set up a web server:
|
||||
|
||||
#### Code Examples
|
||||
|
||||
**Keep examples focused:**
|
||||
|
||||
- Show one concept at a time
|
||||
- Use realistic but simple scenarios
|
||||
- Avoid dependencies on other examples
|
||||
|
||||
**Minimal comments**
|
||||
|
||||
Let the code speak for itself.
|
||||
Paste code examples directly and without further alteration.
|
||||
|
||||
**Bad:**
|
||||
|
||||
```nix
|
||||
# This sets the hostname for the machine
|
||||
{
|
||||
networking.hostName = "webserver"; # Change this to your machine's hostname
|
||||
# This enables SSH access
|
||||
services.openssh.enable = true; # Required for remote deployment
|
||||
}
|
||||
```
|
||||
|
||||
**Good:**
|
||||
|
||||
```nix
|
||||
{
|
||||
networking.hostName = "webserver";
|
||||
services.openssh.enable = true;
|
||||
}
|
||||
```
|
||||
|
||||
#### Lead with Practical Examples
|
||||
|
||||
Don't front-load theory. Readers want to accomplish something first, then understand why it works.
|
||||
|
||||
- Show configuration as *what you want*, not *how the module system works*
|
||||
- Introduce Nix-specific concepts only when they are needed to complete the task
|
||||
- Defer language mechanics to reference pages or `nix.dev`
|
||||
|
||||
**Bad:**
|
||||
|
||||
> Before adding a service, you need to understand the NixOS module system and attribute set merging.
|
||||
|
||||
**Good:**
|
||||
|
||||
Enable nginx:
|
||||
|
||||
```nix
|
||||
{ services.nginx.enable = true; }
|
||||
```
|
||||
|
||||
This adds nginx to your system configuration. Rebuild to apply:
|
||||
|
||||
```bash
|
||||
sudo nixos-rebuild switch
|
||||
```
|
||||
|
||||
#### Teach Nix through examples, not theory
|
||||
|
||||
|
||||
Users learn the NixOS module system by seeing patterns first.
|
||||
|
||||
- Start with a working example
|
||||
- Explanation follows the code
|
||||
- Link deeper concepts instead of inlining them
|
||||
- Link to `nix.dev` for optional learning
|
||||
|
||||
#### General Rules
|
||||
|
||||
- Abbreviate keys like `ssh-ed25519 AAAAC3NzaC…`
|
||||
- Abbreviate IP addresses like `192.168.XXX.XXX`
|
||||
- Variables are capitalized and start with `$`, e.g. `$YOUR_HOSTNAME`
|
||||
- Variables should be directly usable during copy-paste
|
||||
- Do **not** describe missing code parts (`#elided`, `#omitted`)
|
||||
- **Machine vs Host**: use "machine" for the NixOS system identity, "host" for the physical or virtual hardware
|
||||
|
||||
#### Capitalization
|
||||
|
||||
- GB / RAM / HDD
|
||||
- bootable USB drive
|
||||
- Wi-Fi / DHCP / DNS
|
||||
- macOS / NixOS / Nix / Linux
|
||||
- Flakes
|
||||
- git
|
||||
|
||||
#### Headings
|
||||
|
||||
Use sentence case. A reader scanning only headings should understand the page.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> Getting Started
|
||||
> Overview
|
||||
> Configure The Database
|
||||
|
||||
**Do:**
|
||||
|
||||
> Set up a PostgreSQL database
|
||||
> Configure networking
|
||||
> Add a user to the system
|
||||
|
||||
#### Imperative Mood, Voice, and Person
|
||||
|
||||
Use imperative mood for instructions. Address the reader as "you", not "the user". Use active voice; in other words, make the subject do the action.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> The user should run the following command.
|
||||
> The configuration will need to be updated.
|
||||
> The key is generated by the system.
|
||||
|
||||
**Do:**
|
||||
|
||||
> Run the command.
|
||||
> Update the configuration.
|
||||
> The system generates the key.
|
||||
|
||||
#### Tense
|
||||
|
||||
Use present tense for descriptions. Future tense makes documentation feel tentative.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> This will create a new folder.
|
||||
> Running this command will install the package.
|
||||
|
||||
**Do:**
|
||||
|
||||
> This creates a new folder.
|
||||
> Running this command installs the package.
|
||||
|
||||
#### Be Confident
|
||||
|
||||
State facts. Don't hedge with "should," "might," "typically," or "usually" unless the behavior genuinely varies.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> This should create the configuration file.
|
||||
> The service will usually start automatically.
|
||||
|
||||
**Do:**
|
||||
|
||||
> This creates the configuration file.
|
||||
> The service starts automatically.
|
||||
|
||||
#### Avoid Nominalizations
|
||||
|
||||
A nominalization is a verb turned into a noun, often by adding *-tion*, *-meant*, or *-ance* (e.g. "explanation", "selection"). The fix: find the hidden verb and use it directly.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> Make a selection from the list.
|
||||
> Provide an explanation of the error.
|
||||
|
||||
**Do:**
|
||||
|
||||
> Select from the list.
|
||||
> Explain the error.
|
||||
|
||||
#### Plain Words
|
||||
|
||||
Technical precision for technical terms; plain language for everything else.
|
||||
|
||||
- "use" not "utilize"
|
||||
- "start" not "initiate"
|
||||
- "end" not "terminate"
|
||||
- "help" not "facilitate"
|
||||
- "send" not "transmit"
|
||||
- "set up" not "establish"
|
||||
- "find out" not "ascertain"
|
||||
|
||||
#### Filler Words and Weak Phrases
|
||||
|
||||
Cut words and phrases that add length without meaning.
|
||||
|
||||
Delete on sight:
|
||||
|
||||
- "simply", "just", "easily", "basically", "obviously"
|
||||
- "in order to" → use "to"
|
||||
- "allows you to" → use the verb directly
|
||||
- "it's worth noting that" → just say the thing
|
||||
- no exclamation marks in technical prose
|
||||
|
||||
**Don't:**
|
||||
|
||||
> Simply run `nixos-rebuild switch`.
|
||||
> In order to deploy, you first need to run the command, which allows you to push the config.
|
||||
> It's worth noting that this requires root access.
|
||||
|
||||
**Do:**
|
||||
|
||||
> Run `nixos-rebuild switch`.
|
||||
> To deploy, run:
|
||||
> This requires root access.
|
||||
|
||||
Every word must earn its place.
|
||||
|
||||
#### Writing Procedures
|
||||
|
||||
One instruction per sentence. Don't pack multiple actions into one sentence.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> Navigate to your project directory and run the command, then check the output.
|
||||
|
||||
**Do:**
|
||||
|
||||
1. Navigate to your project directory.
|
||||
2. Run the command.
|
||||
3. Check the output.
|
||||
|
||||
Don't bury the negative. Key limitations should be prominent, not a footnote after a positive description.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> This service supports multiple roles, integrates with existing modules, and works great for most setups (note that multiple instances are not supported).
|
||||
|
||||
**Do:**
|
||||
|
||||
> This service does not support multiple instances.
|
||||
|
||||
#### Consistent Terminology
|
||||
|
||||
Pick a term and stick to it. Don't swap synonyms to avoid repetition. In technical documentation, repetition is clarity.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> Create a machine... configure the host... deploy the node.
|
||||
|
||||
**Do:**
|
||||
|
||||
> Create a machine... configure the machine... deploy the machine.
|
||||
|
||||
#### Links
|
||||
|
||||
Use descriptive link text. Never use "click here" or "this link."
|
||||
|
||||
**Don't:**
|
||||
|
||||
> For more information, see `[this page](url)`.
|
||||
> Click `[here](url)` to read the reference.
|
||||
|
||||
**Do:**
|
||||
|
||||
> See the `[NixOS options reference](url)` for details.
|
||||
> Read the `[NixOS module system guide](url)`.
|
||||
|
||||
Only link when the destination is directly relevant, not for generic background context (sometimes known as "Wikipedia-style links"). Readers feel obligated to click links, fearing they'll miss something important. Don't send them to a generic article about a technology when they're looking for how *your* system uses it.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> Our software uses [SQLite](https://sqlite.org/) for storage.
|
||||
> *(Reader clicks expecting schema details — finds a generic product page instead.)*
|
||||
|
||||
(Note that in the above example, the SQLite link is the SQLite home page, which is likely not pertinent.)
|
||||
|
||||
**Do:**
|
||||
|
||||
> See `[database schema](url)` for the full table structure.
|
||||
|
||||
#### UI Language
|
||||
|
||||
Match UI element names exactly: wording, casing, and spacing (even if a label seems oddly worded).
|
||||
|
||||
**Don't:**
|
||||
|
||||
> Click the generator button.
|
||||
> Select the save option.
|
||||
|
||||
**Do:**
|
||||
|
||||
> Click **Generate a Key**.
|
||||
> Click **Save Changes**.
|
||||
|
||||
Someone will go looking for a button labeled "generator." They will not find it. They will be frustrated.
|
||||
|
||||
Consistency between documentation and interface builds confidence. Words are part of the interface.
|
||||
|
||||
:::{.tip}
|
||||
This can be tricky as UI changes; we don't yet have a policy in place for how to handle this. We welcome comments and suggestions.
|
||||
:::
|
||||
|
||||
#### Clean system discipline
|
||||
|
||||
Your machine has things new users don't: cached credentials, installed tools, environment variables, existing configuration. When writing or updating documentation:
|
||||
|
||||
**Don't:**
|
||||
|
||||
> Write steps from memory on your development machine, assuming what works there will work everywhere.
|
||||
|
||||
**Do:**
|
||||
|
||||
> - Start on a clean system — a fresh VM or new user account
|
||||
> - Take notes in real time as you work through the steps
|
||||
> - Document every warning, prompt, or unexpected output the system shows
|
||||
|
||||
Also think in combinations: WSL vs native Linux, with and without existing keys. You don't need to test every matrix square — but you need to know which ones diverge.
|
||||
|
||||
#### Never type code — always copy-paste
|
||||
|
||||
Always copy commands and code from a terminal where you just ran them successfully. Never retype from memory.
|
||||
|
||||
**Don't:**
|
||||
|
||||
> Retype a command from memory into the documentation.
|
||||
> Retype code into a code-block from memory
|
||||
|
||||
**Do:**
|
||||
|
||||
> Paste commands directly from the shell or IDE.
|
||||
> Paste code that has been successfully validated with nix-instantiate or nix-build
|
||||
|
||||
Replace sensitive values with placeholders: `<YOUR-KEY>`, `<YOUR-HOST>`, `<YOUR-TOKEN>`.
|
||||
|
||||
Typed-from-memory commands introduce subtle errors. Even the most experienced software developers have occasional typos.
|
||||
@@ -1 +1 @@
|
||||
26.11
|
||||
26.05
|
||||
@@ -400,25 +400,7 @@ rec {
|
||||
condition: passthru: drv:
|
||||
let
|
||||
commonAttrs =
|
||||
drv
|
||||
// listToAttrs (
|
||||
outputsList
|
||||
++ [
|
||||
{
|
||||
name = "all";
|
||||
value = map (x: x.value) outputsList;
|
||||
}
|
||||
]
|
||||
)
|
||||
// passthru
|
||||
// {
|
||||
drvPath =
|
||||
assert condition;
|
||||
drv.drvPath;
|
||||
outPath =
|
||||
assert condition;
|
||||
drv.outPath;
|
||||
};
|
||||
drv // (listToAttrs outputsList) // { all = map (x: x.value) outputsList; } // passthru;
|
||||
|
||||
outputsList = map (outputName: {
|
||||
name = outputName;
|
||||
@@ -440,7 +422,15 @@ rec {
|
||||
};
|
||||
}) (drv.outputs or [ "out" ]);
|
||||
in
|
||||
commonAttrs;
|
||||
commonAttrs
|
||||
// {
|
||||
drvPath =
|
||||
assert condition;
|
||||
drv.drvPath;
|
||||
outPath =
|
||||
assert condition;
|
||||
drv.outPath;
|
||||
};
|
||||
|
||||
/**
|
||||
Strip a derivation of all non-essential attributes, returning
|
||||
|
||||
@@ -23,12 +23,9 @@
|
||||
let
|
||||
inherit (lib)
|
||||
addErrorContext
|
||||
any
|
||||
assertMsg
|
||||
attrNames
|
||||
attrValues
|
||||
concatLists
|
||||
concatMap
|
||||
concatMapStringsSep
|
||||
concatStrings
|
||||
concatStringsSep
|
||||
@@ -55,7 +52,6 @@ let
|
||||
isString
|
||||
last
|
||||
length
|
||||
genAttrs
|
||||
mapAttrs
|
||||
mapAttrsToList
|
||||
optionals
|
||||
@@ -383,69 +379,55 @@ rec {
|
||||
See the [git-config documentation](https://git-scm.com/docs/git-config#_variables) for possible values.
|
||||
*/
|
||||
toGitINI =
|
||||
attrs:
|
||||
let
|
||||
mkSectionName =
|
||||
let
|
||||
containsQuote = hasInfix ''"'';
|
||||
in
|
||||
name:
|
||||
let
|
||||
containsQuote = hasInfix ''"'' name;
|
||||
sections = splitString "." name;
|
||||
section = head sections;
|
||||
subsections = tail sections;
|
||||
subsection = concatStringsSep "." subsections;
|
||||
in
|
||||
if containsQuote name || length sections == 1 then
|
||||
name
|
||||
else
|
||||
''${head sections} "${concatStringsSep "." (tail sections)}"'';
|
||||
if containsQuote || subsections == [ ] then name else ''${section} "${subsection}"'';
|
||||
|
||||
mkValueString =
|
||||
v:
|
||||
let
|
||||
escape = replaceStrings [ "\n" " " ''"'' "\\" ] [ "\\n" "\\t" ''\"'' "\\\\" ];
|
||||
escapedV = ''"${replaceStrings [ "\n" " " ''"'' "\\" ] [ "\\n" "\\t" ''\"'' "\\\\" ] v}"'';
|
||||
in
|
||||
v: mkValueStringDefault { } (if isString v then ''"${escape v}"'' else v);
|
||||
mkValueStringDefault { } (if isString v then escapedV else v);
|
||||
|
||||
# generation for multiple ini values
|
||||
mkKeyValue =
|
||||
k: v:
|
||||
let
|
||||
mkKeyValue = mkKeyValueDefault { inherit mkValueString; } " = ";
|
||||
attrToString = k: v: "\t" + mkKeyValue k v;
|
||||
mkKeyValue = mkKeyValueDefault { inherit mkValueString; } " = " k;
|
||||
in
|
||||
k: v: if isList v then concatStringsSep "\n" (map (attrToString k) v) else attrToString k v;
|
||||
concatStringsSep "\n" (map (kv: "\t" + mkKeyValue kv) (toList v));
|
||||
|
||||
# converts { a.b.c = 5; } to { "a.b".c = 5; } for toINI
|
||||
gitFlattenAttrs =
|
||||
let
|
||||
isNonDrvAttrs = value: isAttrs value && !isDerivation value;
|
||||
recurse =
|
||||
path: value:
|
||||
if isNonDrvAttrs value then
|
||||
concatMap (name: recurse ([ name ] ++ path) value.${name}) (attrNames value)
|
||||
if isAttrs value && !isDerivation value then
|
||||
mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value
|
||||
else if length path > 1 then
|
||||
[
|
||||
{
|
||||
${concatStringsSep "." (reverseList (tail path))}.${head path} = value;
|
||||
}
|
||||
]
|
||||
{
|
||||
${concatStringsSep "." (reverseList (tail path))}.${head path} = value;
|
||||
}
|
||||
else
|
||||
[
|
||||
{
|
||||
${head path} = value;
|
||||
}
|
||||
];
|
||||
{
|
||||
${head path} = value;
|
||||
};
|
||||
in
|
||||
attrs:
|
||||
let
|
||||
# Filter the names for any that contain nested attrsets. attrs that
|
||||
# don't contain nested attrsets can stay the same =
|
||||
namesToRewrite = filter (
|
||||
name: isAttrs attrs.${name} && any isNonDrvAttrs (attrValues attrs.${name})
|
||||
) (attrNames attrs);
|
||||
attrsToRewrite = genAttrs namesToRewrite (name: attrs.${name});
|
||||
in
|
||||
removeAttrs attrs namesToRewrite // foldl recursiveUpdate { } (recurse [ ] attrsToRewrite);
|
||||
attrs: foldl recursiveUpdate { } (flatten (recurse [ ] attrs));
|
||||
|
||||
toINI_ = toINI { inherit mkKeyValue mkSectionName; };
|
||||
in
|
||||
attrs: toINI_ (gitFlattenAttrs attrs);
|
||||
toINI_ (gitFlattenAttrs attrs);
|
||||
|
||||
/**
|
||||
`mkKeyValueDefault` wrapper that handles dconf INI quirks.
|
||||
|
||||
@@ -575,13 +575,6 @@ lib.mapAttrs mkLicense (
|
||||
free = false;
|
||||
};
|
||||
|
||||
enpl = {
|
||||
fullName = "Emmi AI Non-Production License";
|
||||
url = "https://github.com/Emmi-AI/noether/blob/main/LICENSE.txt";
|
||||
free = false;
|
||||
redistributable = true;
|
||||
};
|
||||
|
||||
epl10 = {
|
||||
spdxId = "EPL-1.0";
|
||||
fullName = "Eclipse Public License 1.0";
|
||||
@@ -1157,12 +1150,6 @@ lib.mapAttrs mkLicense (
|
||||
redistributable = true; # Only if used in Netdata products.
|
||||
};
|
||||
|
||||
netboxLimitedUse = {
|
||||
fullName = "NetBox Limited Use License 1.0";
|
||||
free = false;
|
||||
url = "https://github.com/netboxlabs/netbox-branching/blob/8465b9aee69ded23930cfe1a522695bfb8955a5a/LICENSE.md";
|
||||
};
|
||||
|
||||
ngpl = {
|
||||
spdxId = "NGPL";
|
||||
fullName = "Nethack General Public License";
|
||||
|
||||
@@ -1158,10 +1158,8 @@ let
|
||||
value = if opt ? apply then opt.apply res.mergedValue else res.mergedValue;
|
||||
|
||||
warnDeprecation =
|
||||
if (opt.type.deprecationMessage != null) then
|
||||
warn "The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}"
|
||||
else
|
||||
x: x;
|
||||
warnIf (opt.type.deprecationMessage != null)
|
||||
"The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}";
|
||||
|
||||
in
|
||||
warnDeprecation opt
|
||||
@@ -1600,28 +1598,6 @@ let
|
||||
inherit priority content;
|
||||
};
|
||||
|
||||
/**
|
||||
Applies a function to the value inside a definition,
|
||||
preserving all surrounding properties (`mkForce`, `mkOrder`, `mkIf`, etc.).
|
||||
*/
|
||||
mapDefinitionValue =
|
||||
f: def:
|
||||
if def ? _type then
|
||||
if def._type == "merge" then
|
||||
def // { contents = map (mapDefinitionValue f) def.contents; }
|
||||
else if def._type == "if" then
|
||||
def // { content = mapDefinitionValue f def.content; }
|
||||
else if def._type == "override" then
|
||||
def // { content = mapDefinitionValue f def.content; }
|
||||
else if def._type == "order" then
|
||||
def // { content = mapDefinitionValue f def.content; }
|
||||
else if def._type == "definition" then
|
||||
def // { value = mapDefinitionValue f def.value; }
|
||||
else
|
||||
f def
|
||||
else
|
||||
f def;
|
||||
|
||||
mkBefore = mkOrder 500;
|
||||
defaultOrderPriority = 1000;
|
||||
mkAfter = mkOrder 1500;
|
||||
@@ -2326,7 +2302,6 @@ private
|
||||
importApply
|
||||
importJSON
|
||||
importTOML
|
||||
mapDefinitionValue
|
||||
mergeDefinitions
|
||||
mergeAttrDefinitionsWithPrio
|
||||
mergeOptionDecls # should be private?
|
||||
|
||||
115
lib/sources.nix
115
lib/sources.nix
@@ -7,19 +7,12 @@ let
|
||||
match
|
||||
split
|
||||
storeDir
|
||||
escapeRegex
|
||||
removePrefix
|
||||
;
|
||||
inherit (lib)
|
||||
boolToString
|
||||
filter
|
||||
isString
|
||||
readFile
|
||||
concatStrings
|
||||
length
|
||||
elemAt
|
||||
isList
|
||||
any
|
||||
;
|
||||
inherit (lib.filesystem)
|
||||
pathIsRegularFile
|
||||
@@ -520,113 +513,6 @@ let
|
||||
else
|
||||
throw "repoRevToName: invalid kind";
|
||||
|
||||
/**
|
||||
Filter a source tree by a list of doublestar-style glob patterns,
|
||||
returning a source that only contains paths matching at least one
|
||||
pattern. `*` matches a single path component, and `**` matches any
|
||||
number of components.
|
||||
|
||||
# Inputs
|
||||
|
||||
`src`
|
||||
|
||||
: The source tree to filter.
|
||||
|
||||
`patterns`
|
||||
|
||||
: List of glob patterns to include, e.g. `[ "*.py" "src/**" ]`.
|
||||
A leading `**` (e.g. `**\/*.py` for all `.py` files at any depth)
|
||||
is also supported; the `\` here is just a Nix string escape used
|
||||
to avoid closing this comment.
|
||||
|
||||
# Examples
|
||||
:::{.example}
|
||||
## `sourceByGlobs` usage example
|
||||
|
||||
- Include everything under a subdirectory
|
||||
```nix
|
||||
src = sourceByGlobs ./. [ "src/**" "tests/**" ]
|
||||
```
|
||||
|
||||
- Include all .py files in root directory only
|
||||
```nix
|
||||
src = sourceByGlobs ./. [ "*.py" ]
|
||||
```
|
||||
|
||||
:::
|
||||
*/
|
||||
sourceByGlobs =
|
||||
let
|
||||
splitPath = path: filter isString (split "/" path);
|
||||
# Make component regex
|
||||
mkRe =
|
||||
s:
|
||||
if s == "**" then
|
||||
".*" # Has special handling below
|
||||
else
|
||||
concatStrings (map (tok: if isList tok then "[^/]*" else escapeRegex tok) (split "\\*+" s));
|
||||
|
||||
# Make a source filter function from pattern
|
||||
mkMatcher =
|
||||
pat:
|
||||
let
|
||||
globs = map mkRe (splitPath pat);
|
||||
glen = length globs;
|
||||
in
|
||||
path: type:
|
||||
let
|
||||
path' = splitPath path;
|
||||
plen = length path';
|
||||
|
||||
recurse =
|
||||
gi: pi:
|
||||
let
|
||||
g = elemAt globs gi;
|
||||
p = elemAt path' pi;
|
||||
m = match g p != null;
|
||||
in
|
||||
if pi >= plen then # Reached end of path
|
||||
gi >= glen || (type == "directory" || type == "symlink") # Only allow partial matches for directories
|
||||
else if gi >= glen then # Reached end of globs
|
||||
false
|
||||
else if g == ".*" then # Special handling for **
|
||||
(
|
||||
# Lookahead for next glob match
|
||||
if (gi + 1) == glen then
|
||||
true
|
||||
else if (match (elemAt globs (gi + 1)) p != null) then
|
||||
recurse (gi + 1) pi
|
||||
else if m then
|
||||
recurse gi (pi + 1)
|
||||
else
|
||||
false
|
||||
)
|
||||
else if m then
|
||||
recurse (gi + 1) (pi + 1)
|
||||
else
|
||||
false;
|
||||
|
||||
in
|
||||
recurse 0 0;
|
||||
|
||||
mkSourceFilter =
|
||||
root: patterns:
|
||||
let
|
||||
root' = "${toString root}/";
|
||||
matchers = map mkMatcher patterns;
|
||||
in
|
||||
name: type:
|
||||
let
|
||||
name' = removePrefix root' name;
|
||||
in
|
||||
any (m: m name' type) matchers;
|
||||
|
||||
in
|
||||
src: patterns:
|
||||
lib.cleanSourceWith {
|
||||
filter = mkSourceFilter src patterns;
|
||||
inherit src;
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit
|
||||
@@ -646,7 +532,6 @@ in
|
||||
|
||||
sourceByRegex
|
||||
sourceFilesBySuffices
|
||||
sourceByGlobs
|
||||
|
||||
trace
|
||||
;
|
||||
|
||||
@@ -40,9 +40,10 @@ rec {
|
||||
rust.rustcTarget = "powerpc-unknown-linux-gnu";
|
||||
};
|
||||
|
||||
armv5tel-multiplatform = {
|
||||
sheevaplug = {
|
||||
config = "armv5tel-unknown-linux-gnueabi";
|
||||
};
|
||||
}
|
||||
// platforms.sheevaplug;
|
||||
|
||||
raspberryPi = {
|
||||
config = "armv6l-unknown-linux-gnueabihf";
|
||||
@@ -98,6 +99,11 @@ rec {
|
||||
useLLVM = true;
|
||||
};
|
||||
|
||||
pogoplug4 = {
|
||||
config = "armv5tel-unknown-linux-gnueabi";
|
||||
}
|
||||
// platforms.pogoplug4;
|
||||
|
||||
ben-nanonote = {
|
||||
config = "mipsel-unknown-linux-uclibc";
|
||||
}
|
||||
@@ -149,6 +155,7 @@ rec {
|
||||
gnu64 = {
|
||||
config = "x86_64-unknown-linux-gnu";
|
||||
};
|
||||
gnu64_simplekernel = gnu64 // platforms.pc_simplekernel; # see test/cross/default.nix
|
||||
gnu32 = {
|
||||
config = "i686-unknown-linux-gnu";
|
||||
};
|
||||
|
||||
@@ -18,6 +18,10 @@ rec {
|
||||
};
|
||||
};
|
||||
|
||||
pc_simplekernel = lib.recursiveUpdate pc {
|
||||
linux-kernel.autoModules = false;
|
||||
};
|
||||
|
||||
##
|
||||
## POWER
|
||||
##
|
||||
@@ -46,15 +50,138 @@ rec {
|
||||
## ARM
|
||||
##
|
||||
|
||||
armv5tel-multiplatform = {
|
||||
pogoplug4 = {
|
||||
linux-kernel = {
|
||||
name = "armv5tel-multiplatform";
|
||||
name = "pogoplug4";
|
||||
|
||||
baseConfig = "multi_v5_defconfig";
|
||||
DTB = true;
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
target = "zImage";
|
||||
autoModules = false;
|
||||
extraConfig = ''
|
||||
# Ubi for the mtd
|
||||
MTD_UBI y
|
||||
UBIFS_FS y
|
||||
UBIFS_FS_XATTR y
|
||||
UBIFS_FS_ADVANCED_COMPR y
|
||||
UBIFS_FS_LZO y
|
||||
UBIFS_FS_ZLIB y
|
||||
UBIFS_FS_DEBUG n
|
||||
'';
|
||||
makeFlags = [ "LOADADDR=0x8000" ];
|
||||
target = "uImage";
|
||||
# TODO reenable once manual-config's config actually builds a .dtb and this is checked to be working
|
||||
#DTB = true;
|
||||
};
|
||||
gcc = {
|
||||
arch = "armv5te";
|
||||
};
|
||||
};
|
||||
|
||||
sheevaplug = {
|
||||
linux-kernel = {
|
||||
name = "sheevaplug";
|
||||
|
||||
baseConfig = "multi_v5_defconfig";
|
||||
autoModules = false;
|
||||
extraConfig = ''
|
||||
BLK_DEV_RAM y
|
||||
BLK_DEV_INITRD y
|
||||
BLK_DEV_CRYPTOLOOP m
|
||||
BLK_DEV_DM m
|
||||
DM_CRYPT m
|
||||
MD y
|
||||
BTRFS_FS m
|
||||
XFS_FS m
|
||||
JFS_FS m
|
||||
EXT4_FS m
|
||||
USB_STORAGE_CYPRESS_ATACB m
|
||||
|
||||
# mv cesa requires this sw fallback, for mv-sha1
|
||||
CRYPTO_SHA1 y
|
||||
# Fast crypto
|
||||
CRYPTO_TWOFISH y
|
||||
CRYPTO_TWOFISH_COMMON y
|
||||
CRYPTO_BLOWFISH y
|
||||
CRYPTO_BLOWFISH_COMMON y
|
||||
|
||||
IP_PNP y
|
||||
IP_PNP_DHCP y
|
||||
NFS_FS y
|
||||
ROOT_NFS y
|
||||
TUN m
|
||||
NFS_V4 y
|
||||
NFS_V4_1 y
|
||||
NFS_FSCACHE y
|
||||
NFSD m
|
||||
NFSD_V2_ACL y
|
||||
NFSD_V3 y
|
||||
NFSD_V3_ACL y
|
||||
NFSD_V4 y
|
||||
NETFILTER y
|
||||
IP_NF_IPTABLES y
|
||||
IP_NF_FILTER y
|
||||
IP_NF_MATCH_ADDRTYPE y
|
||||
IP_NF_TARGET_LOG y
|
||||
IP_NF_MANGLE y
|
||||
IPV6 m
|
||||
VLAN_8021Q m
|
||||
|
||||
CIFS y
|
||||
CIFS_XATTR y
|
||||
CIFS_POSIX y
|
||||
CIFS_FSCACHE y
|
||||
CIFS_ACL y
|
||||
|
||||
WATCHDOG y
|
||||
WATCHDOG_CORE y
|
||||
ORION_WATCHDOG m
|
||||
|
||||
ZRAM m
|
||||
NETCONSOLE m
|
||||
|
||||
# Disable OABI to have seccomp_filter (required for systemd)
|
||||
# https://github.com/raspberrypi/firmware/issues/651
|
||||
OABI_COMPAT n
|
||||
|
||||
# Fail to build
|
||||
DRM n
|
||||
SCSI_ADVANSYS n
|
||||
USB_ISP1362_HCD n
|
||||
SND_SOC n
|
||||
SND_ALI5451 n
|
||||
FB_SAVAGE n
|
||||
SCSI_NSP32 n
|
||||
ATA_SFF n
|
||||
SUNGEM n
|
||||
IRDA n
|
||||
ATM_HE n
|
||||
SCSI_ACARD n
|
||||
BLK_DEV_CMD640_ENHANCED n
|
||||
|
||||
FUSE_FS m
|
||||
|
||||
# systemd uses cgroups
|
||||
CGROUPS y
|
||||
|
||||
# Latencytop
|
||||
LATENCYTOP y
|
||||
|
||||
# Ubi for the mtd
|
||||
MTD_UBI y
|
||||
UBIFS_FS y
|
||||
UBIFS_FS_XATTR y
|
||||
UBIFS_FS_ADVANCED_COMPR y
|
||||
UBIFS_FS_LZO y
|
||||
UBIFS_FS_ZLIB y
|
||||
UBIFS_FS_DEBUG n
|
||||
|
||||
# Kdb, for kernel troubles
|
||||
KGDB y
|
||||
KGDB_SERIAL_CONSOLE y
|
||||
KGDB_KDB y
|
||||
'';
|
||||
makeFlags = [ "LOADADDR=0x0200000" ];
|
||||
target = "uImage";
|
||||
DTB = true; # Beyond 3.10
|
||||
};
|
||||
gcc = {
|
||||
arch = "armv5te";
|
||||
@@ -69,6 +196,11 @@ rec {
|
||||
DTB = true;
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
extraConfig = ''
|
||||
# Disable OABI to have seccomp_filter (required for systemd)
|
||||
# https://github.com/raspberrypi/firmware/issues/651
|
||||
OABI_COMPAT n
|
||||
'';
|
||||
target = "zImage";
|
||||
};
|
||||
gcc = {
|
||||
@@ -89,6 +221,15 @@ rec {
|
||||
};
|
||||
|
||||
zero-gravitas = {
|
||||
linux-kernel = {
|
||||
name = "zero-gravitas";
|
||||
|
||||
baseConfig = "zero-gravitas_defconfig";
|
||||
# Target verified by checking /boot on reMarkable 1 device
|
||||
target = "zImage";
|
||||
autoModules = false;
|
||||
DTB = true;
|
||||
};
|
||||
gcc = {
|
||||
fpu = "neon";
|
||||
cpu = "cortex-a9";
|
||||
@@ -96,6 +237,15 @@ rec {
|
||||
};
|
||||
|
||||
zero-sugar = {
|
||||
linux-kernel = {
|
||||
name = "zero-sugar";
|
||||
|
||||
baseConfig = "zero-sugar_defconfig";
|
||||
DTB = true;
|
||||
autoModules = false;
|
||||
preferBuiltin = true;
|
||||
target = "zImage";
|
||||
};
|
||||
gcc = {
|
||||
cpu = "cortex-a7";
|
||||
fpu = "neon-vfpv4";
|
||||
@@ -103,6 +253,49 @@ rec {
|
||||
};
|
||||
};
|
||||
|
||||
utilite = {
|
||||
linux-kernel = {
|
||||
name = "utilite";
|
||||
maseConfig = "multi_v7_defconfig";
|
||||
autoModules = false;
|
||||
extraConfig = ''
|
||||
# Ubi for the mtd
|
||||
MTD_UBI y
|
||||
UBIFS_FS y
|
||||
UBIFS_FS_XATTR y
|
||||
UBIFS_FS_ADVANCED_COMPR y
|
||||
UBIFS_FS_LZO y
|
||||
UBIFS_FS_ZLIB y
|
||||
UBIFS_FS_DEBUG n
|
||||
'';
|
||||
makeFlags = [ "LOADADDR=0x10800000" ];
|
||||
target = "uImage";
|
||||
DTB = true;
|
||||
};
|
||||
gcc = {
|
||||
cpu = "cortex-a9";
|
||||
fpu = "neon";
|
||||
};
|
||||
};
|
||||
|
||||
guruplug = lib.recursiveUpdate sheevaplug {
|
||||
# Define `CONFIG_MACH_GURUPLUG' (see
|
||||
# <http://kerneltrap.org/mailarchive/git-commits-head/2010/5/19/33618>)
|
||||
# and other GuruPlug-specific things. Requires the `guruplug-defconfig'
|
||||
# patch.
|
||||
linux-kernel.baseConfig = "guruplug_defconfig";
|
||||
};
|
||||
|
||||
beaglebone = lib.recursiveUpdate armv7l-hf-multiplatform {
|
||||
linux-kernel = {
|
||||
name = "beaglebone";
|
||||
baseConfig = "bb.org_defconfig";
|
||||
autoModules = false;
|
||||
extraConfig = ""; # TBD kernel config
|
||||
target = "zImage";
|
||||
};
|
||||
};
|
||||
|
||||
# https://developer.android.com/ndk/guides/abis#v7a
|
||||
armv7a-android = {
|
||||
linux-kernel.name = "armeabi-v7a";
|
||||
@@ -116,11 +309,32 @@ rec {
|
||||
armv7l-hf-multiplatform = {
|
||||
linux-kernel = {
|
||||
name = "armv7l-hf-multiplatform";
|
||||
baseConfig = "defconfig";
|
||||
Major = "2.6"; # Using "2.6" enables 2.6 kernel syscalls in glibc.
|
||||
baseConfig = "multi_v7_defconfig";
|
||||
DTB = true;
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
target = "zImage";
|
||||
extraConfig = ''
|
||||
# Serial port for Raspberry Pi 3. Wasn't included in ARMv7 defconfig
|
||||
# until 4.17.
|
||||
SERIAL_8250_BCM2835AUX y
|
||||
SERIAL_8250_EXTENDED y
|
||||
SERIAL_8250_SHARE_IRQ y
|
||||
|
||||
# Hangs ODROID-XU4
|
||||
ARM_BIG_LITTLE_CPUIDLE n
|
||||
|
||||
# Disable OABI to have seccomp_filter (required for systemd)
|
||||
# https://github.com/raspberrypi/firmware/issues/651
|
||||
OABI_COMPAT n
|
||||
|
||||
# >=5.12 fails with:
|
||||
# drivers/net/ethernet/micrel/ks8851_common.o: in function `ks8851_probe_common':
|
||||
# ks8851_common.c:(.text+0x179c): undefined reference to `__this_module'
|
||||
# See: https://lore.kernel.org/netdev/20210116164828.40545-1-marex@denx.de/T/
|
||||
KS8851_MLL y
|
||||
'';
|
||||
};
|
||||
gcc = {
|
||||
# Some table about fpu flags:
|
||||
@@ -153,6 +367,22 @@ rec {
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
extraConfig = ''
|
||||
# Raspberry Pi 3 stuff. Not needed for s >= 4.10.
|
||||
ARCH_BCM2835 y
|
||||
BCM2835_MBOX y
|
||||
BCM2835_WDT y
|
||||
RASPBERRYPI_FIRMWARE y
|
||||
RASPBERRYPI_POWER y
|
||||
SERIAL_8250_BCM2835AUX y
|
||||
SERIAL_8250_EXTENDED y
|
||||
SERIAL_8250_SHARE_IRQ y
|
||||
|
||||
# Cavium ThunderX stuff.
|
||||
PCI_HOST_THUNDER_ECAM y
|
||||
|
||||
# Nvidia Tegra stuff.
|
||||
PCI_TEGRA y
|
||||
|
||||
# The default (=y) forces us to have the XHCI firmware available in initrd,
|
||||
# which our initrd builder can't currently do easily.
|
||||
USB_XHCI_TEGRA m
|
||||
@@ -186,6 +416,74 @@ rec {
|
||||
};
|
||||
|
||||
fuloong2f_n32 = {
|
||||
linux-kernel = {
|
||||
name = "fuloong2f_n32";
|
||||
baseConfig = "lemote2f_defconfig";
|
||||
autoModules = false;
|
||||
extraConfig = ''
|
||||
MIGRATION n
|
||||
COMPACTION n
|
||||
|
||||
# nixos mounts some cgroup
|
||||
CGROUPS y
|
||||
|
||||
BLK_DEV_RAM y
|
||||
BLK_DEV_INITRD y
|
||||
BLK_DEV_CRYPTOLOOP m
|
||||
BLK_DEV_DM m
|
||||
DM_CRYPT m
|
||||
MD y
|
||||
EXT4_FS m
|
||||
USB_STORAGE_CYPRESS_ATACB m
|
||||
|
||||
IP_PNP y
|
||||
IP_PNP_DHCP y
|
||||
IP_PNP_BOOTP y
|
||||
NFS_FS y
|
||||
ROOT_NFS y
|
||||
TUN m
|
||||
NFS_V4 y
|
||||
NFS_V4_1 y
|
||||
NFS_FSCACHE y
|
||||
NFSD m
|
||||
NFSD_V2_ACL y
|
||||
NFSD_V3 y
|
||||
NFSD_V3_ACL y
|
||||
NFSD_V4 y
|
||||
|
||||
# Fail to build
|
||||
DRM n
|
||||
SCSI_ADVANSYS n
|
||||
USB_ISP1362_HCD n
|
||||
SND_SOC n
|
||||
SND_ALI5451 n
|
||||
FB_SAVAGE n
|
||||
SCSI_NSP32 n
|
||||
ATA_SFF n
|
||||
SUNGEM n
|
||||
IRDA n
|
||||
ATM_HE n
|
||||
SCSI_ACARD n
|
||||
BLK_DEV_CMD640_ENHANCED n
|
||||
|
||||
FUSE_FS m
|
||||
|
||||
# Needed for udev >= 150
|
||||
SYSFS_DEPRECATED_V2 n
|
||||
|
||||
VGA_CONSOLE n
|
||||
VT_HW_CONSOLE_BINDING y
|
||||
SERIAL_8250_CONSOLE y
|
||||
FRAMEBUFFER_CONSOLE y
|
||||
EXT2_FS y
|
||||
EXT3_FS y
|
||||
MAGIC_SYSRQ y
|
||||
|
||||
# The kernel doesn't boot at all, with FTRACE
|
||||
FTRACE n
|
||||
'';
|
||||
target = "vmlinux";
|
||||
};
|
||||
gcc = {
|
||||
arch = "loongson2f";
|
||||
float = "hard";
|
||||
@@ -231,6 +529,35 @@ rec {
|
||||
};
|
||||
};
|
||||
|
||||
# based on:
|
||||
# https://www.mail-archive.com/qemu-discuss@nongnu.org/msg05179.html
|
||||
# https://gmplib.org/~tege/qemu.html#mips64-debian
|
||||
mips64el-qemu-linux-gnuabi64 = {
|
||||
linux-kernel = {
|
||||
name = "mips64el";
|
||||
baseConfig = "64r2el_defconfig";
|
||||
target = "vmlinuz";
|
||||
autoModules = false;
|
||||
DTB = true;
|
||||
# for qemu 9p passthrough filesystem
|
||||
extraConfig = ''
|
||||
MIPS_MALTA y
|
||||
PAGE_SIZE_4KB y
|
||||
CPU_LITTLE_ENDIAN y
|
||||
CPU_MIPS64_R2 y
|
||||
64BIT y
|
||||
CPU_MIPS64_R2 y
|
||||
|
||||
NET_9P y
|
||||
NET_9P_VIRTIO y
|
||||
9P_FS y
|
||||
9P_FS_POSIX_ACL y
|
||||
PCI y
|
||||
VIRTIO_PCI y
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
##
|
||||
## Other
|
||||
##
|
||||
@@ -284,7 +611,7 @@ rec {
|
||||
if version == null then
|
||||
pc
|
||||
else if lib.versionOlder version "6" then
|
||||
armv5tel-multiplatform
|
||||
sheevaplug
|
||||
else if lib.versionOlder version "7" then
|
||||
raspberrypi
|
||||
else
|
||||
|
||||
@@ -5114,96 +5114,4 @@ runTests {
|
||||
);
|
||||
expected = false;
|
||||
};
|
||||
|
||||
# mapDefinitionValue
|
||||
|
||||
testMapDefinitionValuePlain = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) 5;
|
||||
expected = 6;
|
||||
};
|
||||
|
||||
testMapDefinitionValueMkForce = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) (lib.mkForce 5);
|
||||
expected = lib.mkForce 6;
|
||||
};
|
||||
|
||||
testMapDefinitionValueMkDefault = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) (lib.mkDefault 5);
|
||||
expected = lib.mkDefault 6;
|
||||
};
|
||||
|
||||
testMapDefinitionValueMkOrder = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) (lib.mkOrder 500 5);
|
||||
expected = lib.mkOrder 500 6;
|
||||
};
|
||||
|
||||
testMapDefinitionValueMkOverrideNested = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) (lib.mkForce (lib.mkOrder 500 5));
|
||||
expected = lib.mkForce (lib.mkOrder 500 6);
|
||||
};
|
||||
|
||||
testMapDefinitionValueMkIf = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) (lib.mkIf true 5);
|
||||
expected = lib.mkIf true 6;
|
||||
};
|
||||
|
||||
testMapDefinitionValueMkMerge = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) (
|
||||
lib.mkMerge [
|
||||
5
|
||||
10
|
||||
]
|
||||
);
|
||||
expected = lib.mkMerge [
|
||||
6
|
||||
11
|
||||
];
|
||||
};
|
||||
|
||||
testMapDefinitionValueMkDefinition = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) (
|
||||
lib.mkDefinition {
|
||||
file = "test";
|
||||
value = 5;
|
||||
}
|
||||
);
|
||||
expected = lib.mkDefinition {
|
||||
file = "test";
|
||||
value = 6;
|
||||
};
|
||||
};
|
||||
|
||||
testMapDefinitionValueDeep = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) (lib.mkIf true (lib.mkForce (lib.mkOrder 500 5)));
|
||||
expected = lib.mkIf true (lib.mkForce (lib.mkOrder 500 6));
|
||||
};
|
||||
|
||||
testMapDefinitionValueAllNested = {
|
||||
expr = lib.modules.mapDefinitionValue (x: x + 1) (
|
||||
lib.mkMerge [
|
||||
(lib.mkIf true (
|
||||
lib.mkForce (
|
||||
lib.mkOrder 500 (
|
||||
lib.mkDefinition {
|
||||
file = "test";
|
||||
value = lib.mkBefore 5;
|
||||
}
|
||||
)
|
||||
)
|
||||
))
|
||||
]
|
||||
);
|
||||
expected = lib.mkMerge [
|
||||
(lib.mkIf true (
|
||||
lib.mkForce (
|
||||
lib.mkOrder 500 (
|
||||
lib.mkDefinition {
|
||||
file = "test";
|
||||
value = lib.mkBefore 6;
|
||||
}
|
||||
)
|
||||
)
|
||||
))
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -899,19 +899,6 @@ checkConfigError 'Did you mean .enable., .ebe. or .enabled.\?' config ./error-ty
|
||||
checkConfigError 'Did you mean .services\.myservice\.port. or .services\.myservice\.enable.\?' config.services.myservice ./error-typo-submodule.nix
|
||||
checkConfigError 'Did you mean .services\.nginx\.virtualHosts\."example\.com"\.ssl\.certificate. or .services\.nginx\.virtualHosts\."example\.com"\.ssl\.certificateKey.\?' config.services.nginx.virtualHosts.\"example.com\" ./error-typo-deeply-nested.nix
|
||||
|
||||
# types.attrListOf
|
||||
checkConfigOutput '"ok"' config.assertions ./declare-attrList.nix
|
||||
checkConfigError 'A definition for option .attrListInt.badValue.a. is not of type .signed integer.. Definition values:' config.attrListIntStrict.badValue ./declare-attrList.nix
|
||||
checkConfigError 'A definition for option .attrList.badListElem. is not of type .attribute list of string.. Each list element must be a single-key attribute set, but got 2 keys' config.attrListStrict.badListElem ./declare-attrList.nix
|
||||
checkConfigError 'A definition for option .attrList.badString. is not of type .attribute list of string.. TypeError: Definition values:' config.attrListStrict.badString ./declare-attrList.nix
|
||||
checkConfigError 'A definition for option .attrList.badListString. is not of type .attribute list of string.. Each list element must be an attribute set, but got string' config.attrListStrict.badListString ./declare-attrList.nix
|
||||
|
||||
# attrListWith valueMeta.definitions: file propagation
|
||||
checkConfigError 'the-defs-file\.nix' config.argv ./attrList-valueMeta-definitions-file-diagnostic-forwarding.nix
|
||||
|
||||
# attrListOf does not support type merging
|
||||
checkConfigError 'The option .merged. in .*/declare-attrList-type-merge.nix. is already declared in .*/declare-attrList-type-merge.nix' config.merged ./declare-attrList-type-merge.nix
|
||||
|
||||
cat <<EOF
|
||||
====== module tests ======
|
||||
$pass Pass
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
{ lib, options, ... }:
|
||||
let
|
||||
inherit (lib) mkOption mkMerge types;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
{
|
||||
_file = "the-defs-file.nix";
|
||||
config.flags.my-flag = 3.14;
|
||||
}
|
||||
];
|
||||
|
||||
options.flags = mkOption {
|
||||
type = types.attrListWith {
|
||||
elemType = types.anything;
|
||||
asAttrs = true;
|
||||
mergeAttrValues = _name: vs: lib.head vs;
|
||||
};
|
||||
};
|
||||
options.argv = mkOption { type = types.listOf types.str; };
|
||||
|
||||
# Feed definitions into argv; the float from the-defs-file.nix should cause
|
||||
# a type error mentioning that file
|
||||
config.argv = mkMerge options.flags.valueMeta.definitions;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
# Test that attrListOf does not support type merging:
|
||||
# two declarations of the same option should fail.
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
{ options.merged = mkOption { type = types.attrListOf types.str; }; }
|
||||
{ options.merged = mkOption { type = types.attrListOf types.str; }; }
|
||||
];
|
||||
}
|
||||
@@ -1,925 +0,0 @@
|
||||
# Run with:
|
||||
# cd nixpkgs
|
||||
# ./lib/tests/modules.sh
|
||||
{ lib, config, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
mkOrder
|
||||
mkMerge
|
||||
mkBefore
|
||||
mkAfter
|
||||
mkIf
|
||||
mkOverride
|
||||
mkDefault
|
||||
mkForce
|
||||
types
|
||||
;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
attrList = mkOption {
|
||||
type = types.lazyAttrsOf (types.attrListOf types.str);
|
||||
};
|
||||
|
||||
attrListInt = mkOption {
|
||||
type = types.lazyAttrsOf (types.attrListOf types.int);
|
||||
};
|
||||
|
||||
attrListSubmodule = mkOption {
|
||||
type = types.attrListOf (
|
||||
types.submodule {
|
||||
options.port = mkOption {
|
||||
type = types.int;
|
||||
description = "Port number";
|
||||
};
|
||||
options.host = mkOption {
|
||||
type = types.str;
|
||||
default = "localhost";
|
||||
description = "Hostname";
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
# asAttrs: value is a merged attrset, ordered list in valueMeta
|
||||
asAttrs = mkOption {
|
||||
type = types.lazyAttrsOf (
|
||||
types.attrListWith {
|
||||
elemType = types.str;
|
||||
asAttrs = true;
|
||||
mergeAttrValues = _name: values: lib.last values;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
# asAttrs with default mergeAttrValues: duplicates collected into lists
|
||||
asAttrsDefault = mkOption {
|
||||
type = types.lazyAttrsOf (
|
||||
types.attrListWith {
|
||||
elemType = types.int;
|
||||
asAttrs = true;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
# Strict wrappers that force deep evaluation, for testing error cases
|
||||
attrListStrict = mkOption {
|
||||
type = types.lazyAttrsOf types.raw;
|
||||
};
|
||||
|
||||
attrListIntStrict = mkOption {
|
||||
type = types.lazyAttrsOf types.raw;
|
||||
};
|
||||
|
||||
# either picks attrList when input is list/attrset, int when input is int
|
||||
eitherAttrListOrInt = mkOption {
|
||||
type = types.either (types.attrListOf types.str) types.int;
|
||||
};
|
||||
|
||||
eitherAttrListOrIntFallback = mkOption {
|
||||
type = types.either (types.attrListOf types.str) types.int;
|
||||
};
|
||||
|
||||
eitherIntOrAttrList = mkOption {
|
||||
type = types.either types.int (types.attrListOf types.str);
|
||||
};
|
||||
|
||||
eitherIntOrAttrListFallback = mkOption {
|
||||
type = types.either types.int (types.attrListOf types.str);
|
||||
};
|
||||
|
||||
assertions = mkOption { };
|
||||
};
|
||||
|
||||
imports = [
|
||||
# Second module contributing to multiModule
|
||||
{
|
||||
attrListInt.multiModule = [
|
||||
{ b = 2; }
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
config = {
|
||||
|
||||
# List input: pass-through
|
||||
attrList.listInput = [
|
||||
{ a = "alpha"; }
|
||||
{ b = "beta"; }
|
||||
];
|
||||
|
||||
# Attrset input with explicit ordering
|
||||
attrList.attrsetOrdered = {
|
||||
x = mkOrder 200 "x-val";
|
||||
y = mkOrder 100 "y-val";
|
||||
};
|
||||
|
||||
# Mixed: list elements at default priority, attrset with mkOrder
|
||||
attrList.mixed = mkMerge [
|
||||
[
|
||||
{ m = "from-list"; }
|
||||
]
|
||||
{
|
||||
n = mkOrder 50 "from-attrset";
|
||||
}
|
||||
];
|
||||
|
||||
# Multiple list definitions from separate modules
|
||||
attrListInt.multiModule = [
|
||||
{ a = 1; }
|
||||
];
|
||||
|
||||
# Attrset without mkOrder uses default priority
|
||||
attrList.attrsetNoOrder = {
|
||||
foo = "bar";
|
||||
baz = "qux";
|
||||
};
|
||||
|
||||
# Empty list
|
||||
attrList.empty = [ ];
|
||||
|
||||
# Ordering test: lower priority first
|
||||
attrList.ordering = mkMerge [
|
||||
{
|
||||
last = mkOrder 1500 "last";
|
||||
}
|
||||
{
|
||||
first = mkOrder 500 "first";
|
||||
}
|
||||
[
|
||||
{ middle = "middle"; }
|
||||
]
|
||||
];
|
||||
|
||||
# List elements support mkOrder/mkBefore/mkAfter
|
||||
attrList.listOrdering = [
|
||||
(mkAfter { z = "after"; })
|
||||
{ m = "default"; }
|
||||
(mkBefore { a = "before"; })
|
||||
];
|
||||
|
||||
# Plain list entries land at default priority (1000):
|
||||
# they appear after mkOrder 999 and before mkOrder 1001.
|
||||
attrList.listDefaultPrio = mkMerge [
|
||||
{ after = mkOrder 1001 "after"; }
|
||||
[
|
||||
{ mid = "list-entry"; }
|
||||
]
|
||||
{ before = mkOrder 999 "before"; }
|
||||
];
|
||||
|
||||
# mkBefore and mkAfter
|
||||
attrList.beforeAfter = mkMerge [
|
||||
{
|
||||
z = mkAfter "after";
|
||||
}
|
||||
{
|
||||
a = mkBefore "before";
|
||||
}
|
||||
[
|
||||
{ m = "default"; }
|
||||
]
|
||||
];
|
||||
|
||||
# mkIf: conditional definition
|
||||
attrList.withMkIf = mkMerge [
|
||||
(mkIf true [
|
||||
{ yes = "included"; }
|
||||
])
|
||||
(mkIf false [
|
||||
{ no = "excluded"; }
|
||||
])
|
||||
];
|
||||
|
||||
# mkOverride: higher priority override wins
|
||||
attrList.withOverride = mkMerge [
|
||||
(mkOverride 100 [
|
||||
{ replaced = "gone"; }
|
||||
])
|
||||
(mkOverride 50 [
|
||||
{ winner = "wins"; }
|
||||
])
|
||||
];
|
||||
|
||||
# mkDefault: lower priority than normal
|
||||
attrList.withDefault = mkMerge [
|
||||
(mkDefault [
|
||||
{ default = "overridden"; }
|
||||
])
|
||||
[
|
||||
{ normal = "wins"; }
|
||||
]
|
||||
];
|
||||
|
||||
# mkForce on the whole option (should discard other defs)
|
||||
attrList.withForce = mkMerge [
|
||||
[
|
||||
{ discarded = "gone"; }
|
||||
]
|
||||
(mkForce [
|
||||
{ forced = "wins"; }
|
||||
])
|
||||
];
|
||||
|
||||
# mkForce with mkOrder inside
|
||||
attrList.forceWithOrder = mkForce [
|
||||
(mkAfter { second = "after"; })
|
||||
(mkBefore { first = "before"; })
|
||||
];
|
||||
|
||||
# mkForce on individual element values; non-forced entries are discarded.
|
||||
# Discarded values use a mix of: plain value, mkDefault(abort ...), mkOverride 100 (abort ...).
|
||||
# The abort variants verify laziness: peelProperties sees the wrapper without forcing the content.
|
||||
attrListInt.forceElementValue = [
|
||||
{ a = mkDefault (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated"); }
|
||||
{ a = mkForce 42; }
|
||||
{ a = mkOverride 100 (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated"); }
|
||||
{ b = 2; }
|
||||
];
|
||||
|
||||
# mkForce on attrset format
|
||||
attrList.forceAttrset = mkMerge [
|
||||
[
|
||||
{ discarded = "gone"; }
|
||||
]
|
||||
(mkForce {
|
||||
x = mkOrder 200 "x-val";
|
||||
y = mkOrder 100 "y-val";
|
||||
})
|
||||
];
|
||||
|
||||
# mkForce on repeated key: forced entries override non-forced
|
||||
attrList.forceRepeatedKey = [
|
||||
{ x = mkOverride 100 (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated"); }
|
||||
{ x = mkForce "wins"; }
|
||||
{ x = mkForce "wins 2"; }
|
||||
];
|
||||
|
||||
# mkForce on repeated key across mkMerge
|
||||
attrList.forceRepeatedKeyMerge = mkMerge [
|
||||
[
|
||||
{ x = "unused: overridden by mkForce"; }
|
||||
{ x = mkDefault (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated"); }
|
||||
]
|
||||
[
|
||||
{ x = mkOverride 100 (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated"); }
|
||||
]
|
||||
[
|
||||
{ x = mkForce "forced"; }
|
||||
]
|
||||
];
|
||||
|
||||
# mkForce on repeated key in attrset format across mkMerge
|
||||
attrList.forceRepeatedKeyAttrs = mkMerge [
|
||||
{
|
||||
x = mkDefault (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated");
|
||||
y = "kept";
|
||||
}
|
||||
{ x = mkForce "forced"; }
|
||||
];
|
||||
|
||||
# mkForce only affects the key it's on, other keys survive
|
||||
attrList.forcePartialAttrs = mkMerge [
|
||||
{
|
||||
x = "unused: overridden by mkForce";
|
||||
y = "normal y";
|
||||
}
|
||||
{ x = mkForce "forced x"; }
|
||||
];
|
||||
|
||||
# mkForce in attrset format overrides same key from list format
|
||||
attrList.forceMixedFormats = mkMerge [
|
||||
[
|
||||
{ x = mkOverride 100 (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated"); }
|
||||
{ y = "list y"; }
|
||||
]
|
||||
{ x = mkForce "attrset forced x"; }
|
||||
];
|
||||
|
||||
# Nesting: list format, mkOrder on element + mkForce on value
|
||||
attrList.nestListOrderForce = mkMerge [
|
||||
[
|
||||
{ x = mkDefault (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated"); }
|
||||
(mkOrder 500 { x = mkForce "forced-early"; })
|
||||
(mkOrder 1500 { y = "late"; })
|
||||
]
|
||||
[
|
||||
(mkOrder 100 { z = "earliest"; })
|
||||
]
|
||||
];
|
||||
|
||||
# Nesting: list format, mkOrder(mkForce(val)) on value
|
||||
attrList.nestListOrderOfForce = mkMerge [
|
||||
[
|
||||
{ x = mkOverride 100 (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated"); }
|
||||
{ y = "plain-early"; }
|
||||
]
|
||||
[
|
||||
{ x = mkOrder 1500 (mkForce "forced-late"); }
|
||||
{ z = mkOrder 500 "earliest"; }
|
||||
]
|
||||
[
|
||||
{ x = "unused: overridden by mkForce"; }
|
||||
{ w = mkOrder 1200 "mid"; }
|
||||
]
|
||||
];
|
||||
|
||||
# Nesting: list format, mkForce(mkOrder(val)) on value
|
||||
attrList.nestListForceOfOrder = mkMerge [
|
||||
[
|
||||
{ x = "unused: overridden by mkForce"; }
|
||||
{ y = "plain-early"; }
|
||||
]
|
||||
[
|
||||
{ x = mkForce (mkOrder 1500 "forced-late"); }
|
||||
{ z = mkOrder 500 "earliest"; }
|
||||
]
|
||||
[
|
||||
{ x = mkDefault (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated"); }
|
||||
{ w = mkOrder 1200 "mid"; }
|
||||
]
|
||||
];
|
||||
|
||||
# Nesting: attrset format, mkOrder wrapping mkForce
|
||||
attrList.nestAttrsOrderOfForce = mkMerge [
|
||||
{
|
||||
x = mkOverride 100 (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated");
|
||||
y = "plain-early";
|
||||
}
|
||||
{
|
||||
x = mkOrder 1500 (mkForce "forced-late");
|
||||
z = mkOrder 500 "earliest";
|
||||
}
|
||||
{
|
||||
x = "unused: overridden by mkForce";
|
||||
w = mkOrder 1200 "mid";
|
||||
}
|
||||
];
|
||||
|
||||
# Nesting: attrset format, mkForce wrapping mkOrder
|
||||
attrList.nestAttrsForceOfOrder = mkMerge [
|
||||
{
|
||||
x = "unused: overridden by mkForce";
|
||||
y = "plain-early";
|
||||
}
|
||||
{
|
||||
x = mkForce (mkOrder 1500 "forced-late");
|
||||
z = mkOrder 500 "earliest";
|
||||
}
|
||||
{
|
||||
x = mkDefault (abort "overridden by mkForce; laziness guarantee: MUST NOT be evaluated");
|
||||
w = mkOrder 1200 "mid";
|
||||
}
|
||||
];
|
||||
|
||||
# mkIf false on individual element value filters it out (list format)
|
||||
attrListInt.optionalValueList = [
|
||||
{ a = mkIf true 1; }
|
||||
{ b = mkIf false 2; }
|
||||
{ c = 3; }
|
||||
];
|
||||
|
||||
# mkIf false on individual element value filters it out (attrset format)
|
||||
attrListInt.optionalValueAttrs = {
|
||||
a = mkIf true 1;
|
||||
b = mkIf false 2;
|
||||
c = 3;
|
||||
};
|
||||
|
||||
# submodule elemType: produces real valueMeta
|
||||
attrListSubmodule = [
|
||||
{
|
||||
web = {
|
||||
port = 80;
|
||||
};
|
||||
}
|
||||
{
|
||||
db = {
|
||||
port = 5432;
|
||||
host = "dbhost";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
# asAttrs: unique keys — value is a plain attrset
|
||||
asAttrs.unique = [
|
||||
{ a = "alpha"; }
|
||||
{ b = "beta"; }
|
||||
];
|
||||
|
||||
# asAttrs: duplicate keys — last in order wins
|
||||
asAttrs.duplicateKeys = mkMerge [
|
||||
{ x = mkOrder 500 "first"; }
|
||||
{ x = mkOrder 1500 "last"; }
|
||||
{ y = "only"; }
|
||||
];
|
||||
|
||||
# asAttrs: with ordering — value is attrset, ordered list in valueMeta
|
||||
asAttrs.ordered = {
|
||||
z = mkOrder 200 "z-val";
|
||||
a = mkOrder 100 "a-val";
|
||||
};
|
||||
|
||||
# asAttrs: with mkForce — forced key overrides
|
||||
asAttrs.withForce = mkMerge [
|
||||
{ x = "unused: overridden by mkForce"; }
|
||||
{
|
||||
x = mkForce "forced";
|
||||
y = "kept";
|
||||
}
|
||||
];
|
||||
|
||||
# asAttrs: empty
|
||||
asAttrs.empty = [ ];
|
||||
|
||||
# asAttrsDefault: unique keys
|
||||
asAttrsDefault.unique = [
|
||||
{ a = 1; }
|
||||
{ b = 2; }
|
||||
];
|
||||
|
||||
# asAttrsDefault: duplicate keys — default collects into lists
|
||||
asAttrsDefault.duplicates = mkMerge [
|
||||
{ x = mkOrder 500 10; }
|
||||
{ x = mkOrder 1500 30; }
|
||||
{ y = 99; }
|
||||
[
|
||||
{ x = 20; }
|
||||
]
|
||||
];
|
||||
|
||||
# either: attrList branch matches for list input
|
||||
eitherAttrListOrInt = [
|
||||
{ a = "hello"; }
|
||||
{ b = "world"; }
|
||||
];
|
||||
|
||||
# either: int input falls through to int branch
|
||||
eitherAttrListOrIntFallback = 42;
|
||||
|
||||
# either (swapped): int first, attrList second — int input matches int
|
||||
eitherIntOrAttrList = 42;
|
||||
|
||||
# either (swapped): list input falls through to attrList branch
|
||||
eitherIntOrAttrListFallback = [
|
||||
{ a = "hello"; }
|
||||
];
|
||||
|
||||
# Bad: string where int expected
|
||||
attrListInt.badValue = [
|
||||
{ a = "not-an-int"; }
|
||||
];
|
||||
|
||||
# Bad: list element with multiple keys
|
||||
attrList.badListElem = [
|
||||
{
|
||||
a = "ok";
|
||||
b = "extra";
|
||||
}
|
||||
];
|
||||
|
||||
# Bad: plain string instead of list or attrset
|
||||
attrList.badString = "not-a-container";
|
||||
|
||||
# Bad: list element is a bare string, not a singleton attrset
|
||||
attrList.badListString = [
|
||||
"not a singleton attribute"
|
||||
];
|
||||
|
||||
attrListStrict = builtins.mapAttrs (k: v: builtins.deepSeq v v) config.attrList;
|
||||
attrListIntStrict = builtins.mapAttrs (k: v: builtins.deepSeq v v) config.attrListInt;
|
||||
|
||||
assertions =
|
||||
let
|
||||
c = lib.evalModules {
|
||||
modules = [ ./declare-attrList.nix ];
|
||||
};
|
||||
cfg = c.config;
|
||||
in
|
||||
|
||||
# List input preserves elements
|
||||
assert
|
||||
cfg.attrList.listInput == [
|
||||
{ a = "alpha"; }
|
||||
{ b = "beta"; }
|
||||
];
|
||||
|
||||
# Attrset input with mkOrder: lower priority comes first
|
||||
assert
|
||||
cfg.attrList.attrsetOrdered == [
|
||||
{ y = "y-val"; }
|
||||
{ x = "x-val"; }
|
||||
];
|
||||
|
||||
# Mixed input: mkOrder 50 < default 1000
|
||||
assert
|
||||
cfg.attrList.mixed == [
|
||||
{ n = "from-attrset"; }
|
||||
{ m = "from-list"; }
|
||||
];
|
||||
|
||||
# Multiple definitions from separate modules concatenate
|
||||
# (import module's definition comes before this module's)
|
||||
assert
|
||||
cfg.attrListInt.multiModule == [
|
||||
{ b = 2; }
|
||||
{ a = 1; }
|
||||
];
|
||||
|
||||
# Attrset without mkOrder: all at default priority
|
||||
assert builtins.length cfg.attrList.attrsetNoOrder == 2;
|
||||
|
||||
# Empty list stays empty
|
||||
assert cfg.attrList.empty == [ ];
|
||||
|
||||
# List elements support mkOrder/mkBefore/mkAfter
|
||||
assert
|
||||
cfg.attrList.listOrdering == [
|
||||
{ a = "before"; }
|
||||
{ m = "default"; }
|
||||
{ z = "after"; }
|
||||
];
|
||||
|
||||
# Plain list entries are at default priority (1000)
|
||||
assert
|
||||
cfg.attrList.listDefaultPrio == [
|
||||
{ before = "before"; }
|
||||
{ mid = "list-entry"; }
|
||||
{ after = "after"; }
|
||||
];
|
||||
|
||||
# Ordering: 500 < 1000 (default) < 1500
|
||||
assert
|
||||
cfg.attrList.ordering == [
|
||||
{ first = "first"; }
|
||||
{ middle = "middle"; }
|
||||
{ last = "last"; }
|
||||
];
|
||||
|
||||
# mkBefore (500) < default (1000) < mkAfter (1500)
|
||||
assert
|
||||
cfg.attrList.beforeAfter == [
|
||||
{ a = "before"; }
|
||||
{ m = "default"; }
|
||||
{ z = "after"; }
|
||||
];
|
||||
|
||||
# mkIf true includes, mkIf false excludes
|
||||
assert
|
||||
cfg.attrList.withMkIf == [
|
||||
{ yes = "included"; }
|
||||
];
|
||||
|
||||
# mkOverride: only lowest priority override survives
|
||||
assert
|
||||
cfg.attrList.withOverride == [
|
||||
{ winner = "wins"; }
|
||||
];
|
||||
|
||||
# mkDefault is overridden by normal definitions
|
||||
assert
|
||||
cfg.attrList.withDefault == [
|
||||
{ normal = "wins"; }
|
||||
];
|
||||
|
||||
# mkForce discards other definitions
|
||||
assert
|
||||
cfg.attrList.withForce == [
|
||||
{ forced = "wins"; }
|
||||
];
|
||||
|
||||
# mkForce with mkOrder inside: ordering still works
|
||||
assert
|
||||
cfg.attrList.forceWithOrder == [
|
||||
{ first = "before"; }
|
||||
{ second = "after"; }
|
||||
];
|
||||
|
||||
# mkForce on individual element values passes through
|
||||
assert
|
||||
cfg.attrListInt.forceElementValue == [
|
||||
{ a = 42; }
|
||||
{ b = 2; }
|
||||
];
|
||||
|
||||
# mkForce on attrset format: discards other defs, ordering preserved
|
||||
assert
|
||||
cfg.attrList.forceAttrset == [
|
||||
{ y = "y-val"; }
|
||||
{ x = "x-val"; }
|
||||
];
|
||||
|
||||
# mkForce on repeated key: forced entries override non-forced
|
||||
assert
|
||||
cfg.attrList.forceRepeatedKey == [
|
||||
{ x = "wins"; }
|
||||
{ x = "wins 2"; }
|
||||
];
|
||||
|
||||
# mkForce on repeated key across mkMerge: forced wins
|
||||
assert
|
||||
cfg.attrList.forceRepeatedKeyMerge == [
|
||||
{ x = "forced"; }
|
||||
];
|
||||
|
||||
# mkForce on repeated key in attrset format: discards other x, keeps y
|
||||
assert
|
||||
cfg.attrList.forceRepeatedKeyAttrs == [
|
||||
{ y = "kept"; }
|
||||
{ x = "forced"; }
|
||||
];
|
||||
|
||||
# mkForce only affects its own key
|
||||
assert
|
||||
cfg.attrList.forcePartialAttrs == [
|
||||
{ y = "normal y"; }
|
||||
{ x = "forced x"; }
|
||||
];
|
||||
|
||||
# mkForce in attrset format overrides same key from list format
|
||||
assert
|
||||
cfg.attrList.forceMixedFormats == [
|
||||
{ y = "list y"; }
|
||||
{ x = "attrset forced x"; }
|
||||
];
|
||||
|
||||
# Nesting: list format, mkOrder on element + mkForce on value
|
||||
# z(100) < x-forced(500) < y(1500); x-discarded filtered by mkForce
|
||||
assert
|
||||
cfg.attrList.nestListOrderForce == [
|
||||
{ z = "earliest"; }
|
||||
{ x = "forced-early"; }
|
||||
{ y = "late"; }
|
||||
];
|
||||
|
||||
# Nesting: list format, mkOrder(mkForce(val)) on value
|
||||
# z(500) < y(1000) < w(1200) < x-forced(1500); x-discarded entries filtered
|
||||
assert
|
||||
cfg.attrList.nestListOrderOfForce == [
|
||||
{ z = "earliest"; }
|
||||
{ y = "plain-early"; }
|
||||
{ w = "mid"; }
|
||||
{ x = "forced-late"; }
|
||||
];
|
||||
|
||||
# Nesting: list format, mkForce(mkOrder(val)) on value
|
||||
# z(500) < y(1000) < w(1200) < x-forced(1500); x-discarded entries filtered
|
||||
assert
|
||||
cfg.attrList.nestListForceOfOrder == [
|
||||
{ z = "earliest"; }
|
||||
{ y = "plain-early"; }
|
||||
{ w = "mid"; }
|
||||
{ x = "forced-late"; }
|
||||
];
|
||||
|
||||
# Nesting: attrset format, mkOrder(mkForce(val))
|
||||
# z(500) < y(1000) < w(1200) < x-forced(1500); x-discarded entries filtered
|
||||
assert
|
||||
cfg.attrList.nestAttrsOrderOfForce == [
|
||||
{ z = "earliest"; }
|
||||
{ y = "plain-early"; }
|
||||
{ w = "mid"; }
|
||||
{ x = "forced-late"; }
|
||||
];
|
||||
|
||||
# Nesting: attrset format, mkForce(mkOrder(val))
|
||||
# z(500) < y(1000) < w(1200) < x-forced(1500); x-discarded entries filtered
|
||||
assert
|
||||
cfg.attrList.nestAttrsForceOfOrder == [
|
||||
{ z = "earliest"; }
|
||||
{ y = "plain-early"; }
|
||||
{ w = "mid"; }
|
||||
{ x = "forced-late"; }
|
||||
];
|
||||
|
||||
# mkIf false on individual element value filters it out (list format)
|
||||
assert
|
||||
cfg.attrListInt.optionalValueList == [
|
||||
{ a = 1; }
|
||||
{ c = 3; }
|
||||
];
|
||||
|
||||
# mkIf false on individual element value filters it out (attrset format)
|
||||
assert
|
||||
cfg.attrListInt.optionalValueAttrs == [
|
||||
{ a = 1; }
|
||||
{ c = 3; }
|
||||
];
|
||||
|
||||
# submodule: value, option descriptions, and valueMeta with real configuration metadata
|
||||
assert
|
||||
cfg.attrListSubmodule == [
|
||||
{
|
||||
web = {
|
||||
host = "localhost";
|
||||
port = 80;
|
||||
};
|
||||
}
|
||||
{
|
||||
db = {
|
||||
host = "dbhost";
|
||||
port = 5432;
|
||||
};
|
||||
}
|
||||
];
|
||||
assert
|
||||
builtins.map (m: m.configuration.config) c.options.attrListSubmodule.valueMeta.attrList == [
|
||||
{
|
||||
host = "localhost";
|
||||
port = 80;
|
||||
}
|
||||
{
|
||||
host = "dbhost";
|
||||
port = 5432;
|
||||
}
|
||||
];
|
||||
assert
|
||||
builtins.map (
|
||||
m:
|
||||
builtins.mapAttrs (n: o: o.description) (builtins.removeAttrs m.configuration.options [ "_module" ])
|
||||
) c.options.attrListSubmodule.valueMeta.attrList == [
|
||||
{
|
||||
host = "Hostname";
|
||||
port = "Port number";
|
||||
}
|
||||
{
|
||||
host = "Hostname";
|
||||
port = "Port number";
|
||||
}
|
||||
];
|
||||
|
||||
# valueMeta.attrList has one entry per (non-filtered) element
|
||||
assert
|
||||
c.options.attrList.valueMeta.attrs.listInput.attrList == [
|
||||
{ }
|
||||
{ }
|
||||
];
|
||||
assert
|
||||
c.options.attrList.valueMeta.attrs.attrsetOrdered.attrList == [
|
||||
{ }
|
||||
{ }
|
||||
];
|
||||
assert
|
||||
c.options.attrList.valueMeta.attrs.mixed.attrList == [
|
||||
{ }
|
||||
{ }
|
||||
];
|
||||
assert c.options.attrList.valueMeta.attrs.empty.attrList == [ ];
|
||||
assert
|
||||
c.options.attrListInt.valueMeta.attrs.optionalValueList.attrList == [
|
||||
{ }
|
||||
{ }
|
||||
];
|
||||
|
||||
# either: headError is null for valid attrList input, so attrList branch is picked
|
||||
assert
|
||||
cfg.eitherAttrListOrInt == [
|
||||
{ a = "hello"; }
|
||||
{ b = "world"; }
|
||||
];
|
||||
|
||||
# either: headError is non-null for int input, so int branch is picked
|
||||
assert cfg.eitherAttrListOrIntFallback == 42;
|
||||
|
||||
# either (swapped): int first — int input matches
|
||||
assert cfg.eitherIntOrAttrList == 42;
|
||||
|
||||
# either (swapped): list input falls through to attrList branch
|
||||
assert
|
||||
cfg.eitherIntOrAttrListFallback == [
|
||||
{ a = "hello"; }
|
||||
];
|
||||
|
||||
# asAttrs: unique keys — value is a plain attrset
|
||||
assert
|
||||
cfg.asAttrs.unique == {
|
||||
a = "alpha";
|
||||
b = "beta";
|
||||
};
|
||||
# ordered list preserved in valueMeta
|
||||
assert
|
||||
c.options.asAttrs.valueMeta.attrs.unique.attrListValue == [
|
||||
{ a = "alpha"; }
|
||||
{ b = "beta"; }
|
||||
];
|
||||
|
||||
# asAttrs: duplicate keys — last in order wins
|
||||
assert
|
||||
cfg.asAttrs.duplicateKeys == {
|
||||
x = "last";
|
||||
y = "only";
|
||||
};
|
||||
assert
|
||||
c.options.asAttrs.valueMeta.attrs.duplicateKeys.attrListValue == [
|
||||
{ x = "first"; }
|
||||
{ y = "only"; }
|
||||
{ x = "last"; }
|
||||
];
|
||||
|
||||
# asAttrs: ordered — value is attrset (unordered), list in valueMeta preserves order
|
||||
assert
|
||||
cfg.asAttrs.ordered == {
|
||||
a = "a-val";
|
||||
z = "z-val";
|
||||
};
|
||||
assert
|
||||
c.options.asAttrs.valueMeta.attrs.ordered.attrListValue == [
|
||||
{ a = "a-val"; }
|
||||
{ z = "z-val"; }
|
||||
];
|
||||
|
||||
# asAttrs: mkForce — forced key overrides, value is attrset
|
||||
assert
|
||||
cfg.asAttrs.withForce == {
|
||||
x = "forced";
|
||||
y = "kept";
|
||||
};
|
||||
|
||||
# asAttrs: empty — value is empty attrset
|
||||
assert cfg.asAttrs.empty == { };
|
||||
|
||||
# asAttrsDefault: unique keys — each value wrapped in singleton list
|
||||
assert
|
||||
cfg.asAttrsDefault.unique == {
|
||||
a = [ 1 ];
|
||||
b = [ 2 ];
|
||||
};
|
||||
|
||||
# asAttrsDefault: duplicate keys — values collected into list in order
|
||||
assert
|
||||
cfg.asAttrsDefault.duplicates == {
|
||||
x = [
|
||||
10
|
||||
20
|
||||
30
|
||||
];
|
||||
y = [ 99 ];
|
||||
};
|
||||
assert
|
||||
c.options.asAttrsDefault.valueMeta.attrs.duplicates.attrListValue == [
|
||||
{ x = 10; }
|
||||
{ y = 99; }
|
||||
{ x = 20; }
|
||||
{ x = 30; }
|
||||
];
|
||||
|
||||
# valueMeta.definitions: mkDefinition records with mkOrder-wrapped single-key attrsets
|
||||
# Use duplicateKeys which has mixed priorities and repeated keys
|
||||
assert
|
||||
let
|
||||
defs = c.options.asAttrs.valueMeta.attrs.duplicateKeys.definitions;
|
||||
extract = d: {
|
||||
prio = d.value.priority;
|
||||
value = d.value.content;
|
||||
};
|
||||
in
|
||||
map extract defs == [
|
||||
{
|
||||
prio = 500;
|
||||
value = {
|
||||
x = "first";
|
||||
};
|
||||
}
|
||||
{
|
||||
prio = 1000;
|
||||
value = {
|
||||
y = "only";
|
||||
};
|
||||
}
|
||||
{
|
||||
prio = 1500;
|
||||
value = {
|
||||
x = "last";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
# Round-trip: feed definitions through mapDefinitionValue + mkMerge into a listOf option
|
||||
assert
|
||||
let
|
||||
rendered = lib.modules.mapDefinitionValue (attr: lib.cli.toCommandLineGNU { } attr) (
|
||||
mkMerge c.options.asAttrs.valueMeta.attrs.duplicateKeys.definitions
|
||||
);
|
||||
result =
|
||||
(lib.evalModules {
|
||||
modules = [
|
||||
{ options.out = mkOption { type = types.listOf types.str; }; }
|
||||
{ config.out = rendered; }
|
||||
# Interleave: mkOrder 800 lands between x(500) and y(1000)
|
||||
{ config.out = mkOrder 800 [ "--interleaved" ]; }
|
||||
];
|
||||
}).config.out;
|
||||
in
|
||||
result == [
|
||||
"-xfirst"
|
||||
"--interleaved"
|
||||
"-yonly"
|
||||
"-xlast"
|
||||
];
|
||||
|
||||
# Error cases are tested via checkConfigError in modules.sh
|
||||
|
||||
"ok";
|
||||
};
|
||||
}
|
||||
@@ -167,28 +167,6 @@ in
|
||||
elemType = str;
|
||||
lazy = false;
|
||||
}).description == "attribute set of string";
|
||||
assert (attrListOf str).description == "attribute list of string";
|
||||
assert (attrListOf int).description == "attribute list of signed integer";
|
||||
assert (attrListOf bool).description == "attribute list of boolean";
|
||||
assert (attrListOf (either int str)).description == "attribute list of (signed integer or string)";
|
||||
assert (attrListOf (nullOr str)).description == "attribute list of (null or string)";
|
||||
assert (attrListOf (listOf str)).description == "attribute list of list of string";
|
||||
assert
|
||||
(attrListOf (attrsOf int)).description == "attribute list of attribute set of signed integer";
|
||||
assert (attrListOf (attrListOf str)).description == "attribute list of attribute list of string";
|
||||
assert (attrListOf ints.positive).description == "attribute list of (positive integer, meaning >0)";
|
||||
assert
|
||||
(attrListOf (enum [
|
||||
"a"
|
||||
"b"
|
||||
])).description == "attribute list of (one of \"a\", \"b\")";
|
||||
assert
|
||||
(attrListOf (strMatching "[0-9]+")).description
|
||||
== "attribute list of string matching the pattern [0-9]+";
|
||||
assert
|
||||
(attrListOf (nonEmptyListOf str)).description == "attribute list of non-empty (list of string)";
|
||||
assert (attrListOf (submodule { })).description == "attribute list of (submodule)";
|
||||
|
||||
assert (coercedTo str abort int).description == "signed integer or string convertible to it";
|
||||
assert (coercedTo int abort str).description == "string or signed integer convertible to it";
|
||||
assert (coercedTo bool abort str).description == "string or boolean convertible to it";
|
||||
|
||||
@@ -70,16 +70,4 @@ dir="$(nix-instantiate --eval --strict --read-write-mode --json --expr '(with im
|
||||
EOF
|
||||
) || die "cleanSourceWith + cleanSource"
|
||||
|
||||
|
||||
dir="$(nix-instantiate --eval --strict --read-write-mode --json --expr '(with import <nixpkgs/lib>; "${
|
||||
sources.sourceByGlobs '"$work"' [ "*.md" "**/*.o" ]
|
||||
}")' | crudeUnquoteJSON)"
|
||||
(cd "$dir"; find) | sort -f | diff -U10 - <(cat <<EOF
|
||||
.
|
||||
./module.o
|
||||
./README.md
|
||||
EOF
|
||||
) || die "sourceByGlobs 1"
|
||||
|
||||
|
||||
echo >&2 tests ok
|
||||
|
||||
@@ -504,7 +504,7 @@ in
|
||||
On each release the first letter is bumped and a new animal is chosen
|
||||
starting with that new letter.
|
||||
*/
|
||||
codeName = "Zokor";
|
||||
codeName = "Yarara";
|
||||
|
||||
/**
|
||||
Returns the current nixpkgs version suffix as string.
|
||||
|
||||
180
lib/types.nix
180
lib/types.nix
@@ -20,7 +20,6 @@ let
|
||||
isStorePath
|
||||
isString
|
||||
substring
|
||||
sort
|
||||
throwIf
|
||||
toDerivation
|
||||
toList
|
||||
@@ -28,7 +27,6 @@ let
|
||||
;
|
||||
inherit (lib.lists)
|
||||
concatLists
|
||||
concatMap
|
||||
elemAt
|
||||
filter
|
||||
foldl'
|
||||
@@ -72,11 +70,6 @@ let
|
||||
mergeDefinitions
|
||||
fixupOptionType
|
||||
mergeOptionDecls
|
||||
defaultOrderPriority
|
||||
defaultOverridePriority
|
||||
mkDefinition
|
||||
mkOrder
|
||||
mkOverride
|
||||
;
|
||||
inherit (lib.fileset)
|
||||
isFileset
|
||||
@@ -812,179 +805,6 @@ rec {
|
||||
substSubModules = m: nonEmptyListOf (elemType.substSubModules m);
|
||||
};
|
||||
|
||||
attrListOf = elemType: attrListWith { inherit elemType; };
|
||||
|
||||
attrListWith =
|
||||
{
|
||||
elemType,
|
||||
asAttrs ? false,
|
||||
mergeAttrValues ? _name: values: values,
|
||||
}:
|
||||
mkOptionType rec {
|
||||
name = "attrListOf";
|
||||
description = "attribute list of ${
|
||||
optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType
|
||||
}";
|
||||
descriptionClass = "composite";
|
||||
check = {
|
||||
__functor = _self: x: isList x || isAttrs x;
|
||||
isV2MergeCoherent = true;
|
||||
};
|
||||
merge = {
|
||||
__functor =
|
||||
self: loc: defs:
|
||||
(self.v2 { inherit loc defs; }).value;
|
||||
v2 =
|
||||
{ loc, defs }:
|
||||
let
|
||||
# Peel order and override properties from a value in any nesting order.
|
||||
# Returns { value, prio, overridePrio }.
|
||||
# mkOrder is stripped (we consume it for sorting).
|
||||
# mkOverride is preserved in value (mergeDefinitions strips it).
|
||||
peelProperties =
|
||||
value:
|
||||
let
|
||||
type = value._type or null;
|
||||
in
|
||||
if type == "order" then
|
||||
let
|
||||
inner = peelProperties value.content;
|
||||
in
|
||||
{
|
||||
inherit (inner) value overridePrio;
|
||||
prio = value.priority;
|
||||
}
|
||||
else if type == "override" then
|
||||
let
|
||||
inner = peelProperties value.content;
|
||||
in
|
||||
{
|
||||
inherit (inner) prio;
|
||||
overridePrio = value.priority;
|
||||
# Re-wrap mkOverride around the inner value (with mkOrder stripped)
|
||||
value = mkOverride value.priority inner.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
inherit value;
|
||||
prio = defaultOrderPriority;
|
||||
overridePrio = defaultOverridePriority;
|
||||
};
|
||||
|
||||
# Extract { file, key, value, prio, overridePrio } from a single-key attrset,
|
||||
# optionally wrapped in mkOrder at the element level (list format).
|
||||
extractItem =
|
||||
file: raw:
|
||||
let
|
||||
hasOrder = isType "order" raw;
|
||||
item = if hasOrder then raw.content else raw;
|
||||
key = head (attrNames item);
|
||||
peeled = peelProperties item.${key};
|
||||
in
|
||||
if isAttrs item && length (attrNames item) == 1 then
|
||||
peeled
|
||||
// {
|
||||
inherit file key;
|
||||
prio = if hasOrder then raw.priority else peeled.prio;
|
||||
}
|
||||
else
|
||||
throw "A definition for option `${showOption loc}' is not of type `${description}'. ${
|
||||
if !isAttrs item then
|
||||
"Each list element must be an attribute set, but got ${builtins.typeOf item}"
|
||||
else
|
||||
"Each list element must be a single-key attribute set, but got ${toString (length (attrNames item))} keys"
|
||||
}.${
|
||||
showDefs [
|
||||
{
|
||||
inherit file;
|
||||
value = raw;
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
# Convert a definition to a flat list of { file, key, value, prio, overridePrio }
|
||||
defToItems =
|
||||
def:
|
||||
if isList def.value then
|
||||
map (extractItem def.file) def.value
|
||||
else
|
||||
# isAttrs: properties are on the values directly
|
||||
map (
|
||||
key:
|
||||
peelProperties def.value.${key}
|
||||
// {
|
||||
inherit (def) file;
|
||||
inherit key;
|
||||
}
|
||||
) (attrNames def.value);
|
||||
|
||||
allItems = concatMap defToItems defs;
|
||||
|
||||
# Per key, find the highest override priority (lowest number)
|
||||
winningOverridePrio = foldl' (
|
||||
acc: item:
|
||||
let
|
||||
prev = acc.${item.key} or defaultOverridePriority;
|
||||
in
|
||||
if item.overridePrio < prev then
|
||||
acc // { ${item.key} = item.overridePrio; }
|
||||
else
|
||||
# minimize `//` operations
|
||||
acc
|
||||
) { } allItems;
|
||||
|
||||
# Keep only items at the winning override priority for their key
|
||||
items = sort (a: b: a.prio < b.prio) (
|
||||
filter (
|
||||
item: item.overridePrio == winningOverridePrio.${item.key} or defaultOverridePriority
|
||||
) allItems
|
||||
);
|
||||
|
||||
evals = filter (e: e.eval.optionalValue ? value) (
|
||||
map (item: {
|
||||
inherit (item) key file prio;
|
||||
eval = mergeDefinitions (loc ++ [ item.key ]) elemType [
|
||||
{
|
||||
inherit (item) file value;
|
||||
}
|
||||
];
|
||||
}) items
|
||||
);
|
||||
|
||||
attrListValue = map (e: { ${e.key} = e.eval.optionalValue.value or e.eval.mergedValue; }) evals;
|
||||
in
|
||||
{
|
||||
headError = checkDefsForError check loc defs;
|
||||
value = if asAttrs then zipAttrsWith mergeAttrValues attrListValue else attrListValue;
|
||||
valueMeta.attrList = map (e: e.eval.checkedAndMerged.valueMeta) evals;
|
||||
/**
|
||||
The ordered list representation, especially useful when asAttrs is set.
|
||||
*/
|
||||
valueMeta.attrListValue = attrListValue;
|
||||
valueMeta.definitions = map (
|
||||
e:
|
||||
mkDefinition {
|
||||
inherit (e) file;
|
||||
value = mkOrder e.prio { ${e.key} = e.eval.optionalValue.value or e.eval.mergedValue; };
|
||||
}
|
||||
) evals;
|
||||
};
|
||||
};
|
||||
emptyValue = {
|
||||
value = if asAttrs then { } else [ ];
|
||||
};
|
||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "*" ]);
|
||||
getSubModules = elemType.getSubModules;
|
||||
substSubModules =
|
||||
m:
|
||||
attrListWith {
|
||||
inherit asAttrs mergeAttrValues;
|
||||
elemType = elemType.substSubModules m;
|
||||
};
|
||||
typeMerge = t: null; # Disable type merging
|
||||
nestedTypes.elemType = elemType;
|
||||
};
|
||||
|
||||
attrsOf = elemType: attrsWith { inherit elemType; };
|
||||
|
||||
# A version of attrsOf that's lazy in its values at the expense of
|
||||
|
||||
@@ -309,7 +309,8 @@
|
||||
"members": {
|
||||
"AndersonTorres": 5954806,
|
||||
"adisbladis": 63286,
|
||||
"panchoh": 471059
|
||||
"panchoh": 471059,
|
||||
"ttuegel": 563054
|
||||
},
|
||||
"name": "emacs"
|
||||
},
|
||||
@@ -406,13 +407,12 @@
|
||||
"gnome": {
|
||||
"description": "Maintain GNOME desktop environment and platform.",
|
||||
"id": 3806133,
|
||||
"maintainers": {
|
||||
"jtojnar": 705123
|
||||
},
|
||||
"maintainers": {},
|
||||
"members": {
|
||||
"bobby285271": 20080233,
|
||||
"dasj19": 7589338,
|
||||
"hedning": 71978
|
||||
"hedning": 71978,
|
||||
"jtojnar": 705123
|
||||
},
|
||||
"name": "GNOME"
|
||||
},
|
||||
@@ -702,7 +702,6 @@
|
||||
"Mic92": 96200,
|
||||
"Radvendii": 1239929,
|
||||
"edolstra": 1148549,
|
||||
"lisanna-dettwyler": 72424138,
|
||||
"lovesegfault": 7243783,
|
||||
"xokdvium": 145775305
|
||||
},
|
||||
@@ -820,13 +819,14 @@
|
||||
"description": "Maintain the Qt framework, KDE application suite, Plasma desktop environment and related projects",
|
||||
"id": 4341481,
|
||||
"maintainers": {
|
||||
"K900": 386765,
|
||||
"NickCao": 15247171,
|
||||
"SuperSandro2000": 7258858
|
||||
"ttuegel": 563054
|
||||
},
|
||||
"members": {
|
||||
"FRidh": 2129135,
|
||||
"K900": 386765,
|
||||
"LunNova": 782440,
|
||||
"NickCao": 15247171,
|
||||
"SuperSandro2000": 7258858,
|
||||
"bkchr": 5718007,
|
||||
"ilya-fedin": 17829319,
|
||||
"mjm": 1181,
|
||||
@@ -896,7 +896,8 @@
|
||||
"id": 7304571,
|
||||
"maintainers": {
|
||||
"Mic92": 96200,
|
||||
"winterqt": 78392041
|
||||
"winterqt": 78392041,
|
||||
"zowoq": 59103226
|
||||
},
|
||||
"members": {},
|
||||
"name": "rust"
|
||||
@@ -935,7 +936,6 @@
|
||||
"infinisil": 20525370
|
||||
},
|
||||
"members": {
|
||||
"andir": 638836,
|
||||
"pyrox0": 35778371
|
||||
},
|
||||
"name": "Security review"
|
||||
|
||||
@@ -118,6 +118,13 @@
|
||||
github = "0xB10C";
|
||||
githubId = 19157360;
|
||||
};
|
||||
_0xbe7a = {
|
||||
email = "nix@be7a.de";
|
||||
name = "Bela Stoyan";
|
||||
github = "0xbe7a";
|
||||
githubId = 6232980;
|
||||
keys = [ { fingerprint = "2536 9E86 1AA5 9EB7 4C47 B138 6510 870A 77F4 9A99"; } ];
|
||||
};
|
||||
_0xC45 = {
|
||||
email = "jason@0xc45.com";
|
||||
name = "Jason Vigil";
|
||||
@@ -703,12 +710,6 @@
|
||||
githubId = 25004152;
|
||||
name = "Adrian Gunnar Lauterer";
|
||||
};
|
||||
adrielvelazquez = {
|
||||
email = "AdrielVelazquez@gmail.com";
|
||||
github = "AdrielVelazquez";
|
||||
githubId = 3443378;
|
||||
name = "Adriel Velazquez";
|
||||
};
|
||||
AdrienLemaire = {
|
||||
email = "lemaire.adrien@gmail.com";
|
||||
github = "AdrienLemaire";
|
||||
@@ -1875,10 +1876,7 @@
|
||||
github = "ap-1";
|
||||
githubId = 67872951;
|
||||
name = "Anish Pallati";
|
||||
keys = [
|
||||
{ fingerprint = "2A0A 16F5 E026 BE3B A47F B7A6 841A FB68 9A5B ACCB"; }
|
||||
{ fingerprint = "B89E A3F3 16A7 411C B5B2 8A14 B1CA 8321 35A8 C503"; }
|
||||
];
|
||||
keys = [ { fingerprint = "2A0A 16F5 E026 BE3B A47F B7A6 841A FB68 9A5B ACCB"; } ];
|
||||
};
|
||||
ankhers = {
|
||||
email = "me@ankhers.dev";
|
||||
@@ -4158,13 +4156,6 @@
|
||||
githubId = 30717258;
|
||||
name = "bubblepipe";
|
||||
};
|
||||
bubylou = {
|
||||
email = "bubylou@pm.me";
|
||||
matrix = "@bubylou:matrix.org";
|
||||
github = "bubylou";
|
||||
githubId = 3878640;
|
||||
name = "Nicholas Malcolm";
|
||||
};
|
||||
buckley310 = {
|
||||
email = "sean.bck@gmail.com";
|
||||
matrix = "@buckley310:matrix.org";
|
||||
@@ -4291,12 +4282,6 @@
|
||||
{ fingerprint = "D088 A5AF C45B 78D1 CD4F 457C 6957 B3B6 46F2 BB4E"; }
|
||||
];
|
||||
};
|
||||
c6rg0 = {
|
||||
email = "c6rg0@protonmail.com";
|
||||
github = "c6rg0";
|
||||
githubId = 64259221;
|
||||
name = "c6rg0";
|
||||
};
|
||||
caarlos0 = {
|
||||
name = "Carlos A Becker";
|
||||
email = "carlos@becker.software";
|
||||
@@ -4377,6 +4362,12 @@
|
||||
githubId = 1516457;
|
||||
name = "Christian Albrecht";
|
||||
};
|
||||
callahad = {
|
||||
email = "dan.callahan@gmail.com";
|
||||
github = "callahad";
|
||||
githubId = 24193;
|
||||
name = "Dan Callahan";
|
||||
};
|
||||
callumio = {
|
||||
email = "git@cleslie.uk";
|
||||
github = "callumio";
|
||||
@@ -4564,12 +4555,6 @@
|
||||
githubId = 53847249;
|
||||
name = "Casey Avila";
|
||||
};
|
||||
castorNova2 = {
|
||||
email = "solemnsquire@gmail.com";
|
||||
github = "castorNova2";
|
||||
githubId = 84083897;
|
||||
name = "Nidhish Chauhan";
|
||||
};
|
||||
catap = {
|
||||
email = "kirill@korins.ky";
|
||||
github = "catap";
|
||||
@@ -7619,11 +7604,6 @@
|
||||
githubId = 54573;
|
||||
name = "Edward Amsden";
|
||||
};
|
||||
eana = {
|
||||
github = "eana";
|
||||
githubId = 18534280;
|
||||
name = "Jonas Eana";
|
||||
};
|
||||
earldouglas = {
|
||||
email = "james@earldouglas.com";
|
||||
github = "earldouglas";
|
||||
@@ -7660,12 +7640,6 @@
|
||||
github = "eclairevoyant";
|
||||
name = "éclairevoyant";
|
||||
};
|
||||
eConnah = {
|
||||
email = "git@econnah.uk";
|
||||
github = "eConnah";
|
||||
githubId = 63052937;
|
||||
name = "Connor Alecks";
|
||||
};
|
||||
edanaher = {
|
||||
email = "nixos@edanaher.net";
|
||||
github = "edanaher";
|
||||
@@ -8322,11 +8296,6 @@
|
||||
githubId = 5427394;
|
||||
name = "Ersin Akinci";
|
||||
};
|
||||
es-sai-fi = {
|
||||
name = "es-sai-fi";
|
||||
github = "es-sai-fi";
|
||||
githubId = 96452903;
|
||||
};
|
||||
esau79p = {
|
||||
github = "EsAu79p";
|
||||
githubId = 21313906;
|
||||
@@ -8683,13 +8652,6 @@
|
||||
githubId = 88741530;
|
||||
name = "Fabian Rigoll";
|
||||
};
|
||||
fabiob = {
|
||||
email = "fabio@atelie.dev.br";
|
||||
github = "fabiob";
|
||||
githubId = 140875;
|
||||
name = "Fábio Batista";
|
||||
keys = [ { fingerprint = "D2D8 69D8 5EEC 30AD D327 B4A5 6CD5 5257 DB01 8B72"; } ];
|
||||
};
|
||||
fallenbagel = {
|
||||
name = "fallenbagel";
|
||||
github = "fallenbagel";
|
||||
@@ -9256,12 +9218,6 @@
|
||||
githubId = 119691;
|
||||
name = "Michael Gough";
|
||||
};
|
||||
fraggerfox = {
|
||||
email = "santhosh.raju@gmail.com";
|
||||
github = "fraggerfox";
|
||||
githubId = 189939;
|
||||
name = "Santhosh Raju";
|
||||
};
|
||||
fraioveio = {
|
||||
email = "francesco@vecchia.lol";
|
||||
github = "FraioVeio";
|
||||
@@ -9372,6 +9328,14 @@
|
||||
githubId = 1943632;
|
||||
name = "fro_ozen";
|
||||
};
|
||||
frogamic = {
|
||||
email = "frogamic@protonmail.com";
|
||||
github = "frogamic";
|
||||
githubId = 10263813;
|
||||
name = "Dominic Shelton";
|
||||
matrix = "@frogamic:beeper.com";
|
||||
keys = [ { fingerprint = "779A 7CA8 D51C C53A 9C51 43F7 AAE0 70F0 67EC 00A5"; } ];
|
||||
};
|
||||
frontear = {
|
||||
name = "Ali Rizvi";
|
||||
email = "perm-iterate-0b@icloud.com";
|
||||
@@ -10160,12 +10124,6 @@
|
||||
githubId = 6893840;
|
||||
name = "Yacine Hmito";
|
||||
};
|
||||
gquetel = {
|
||||
email = "gregor.quetel@telecom-paris.fr";
|
||||
github = "gquetel";
|
||||
githubId = 48437427;
|
||||
name = "Grégor Quetel";
|
||||
};
|
||||
gracicot = {
|
||||
email = "dev@gracicot.com";
|
||||
matrix = "@gracicot-59e8f173d73408ce4f7ac803:gitter.im";
|
||||
@@ -11091,7 +11049,7 @@
|
||||
name = "Hugo Tavares Reis";
|
||||
};
|
||||
httprafa = {
|
||||
email = "rafa.kienitz@proton.me";
|
||||
email = "rafael.kienitz@gmail.com";
|
||||
github = "HttpRafa";
|
||||
githubId = 60099368;
|
||||
name = "Rafael Kienitz";
|
||||
@@ -11712,12 +11670,6 @@
|
||||
githubId = 7348004;
|
||||
name = "Benjamin Levy";
|
||||
};
|
||||
iogamaster = {
|
||||
email = "iogamastercode+nixpkgs@gmail.com";
|
||||
name = "IogaMaster";
|
||||
github = "IogaMaster";
|
||||
githubId = 67164465;
|
||||
};
|
||||
ionutnechita = {
|
||||
email = "ionut_n2001@yahoo.com";
|
||||
github = "ionutnechita";
|
||||
@@ -12619,12 +12571,6 @@
|
||||
githubId = 30251156;
|
||||
name = "Jesse Moore";
|
||||
};
|
||||
jesssullivan = {
|
||||
email = "jess@sulliwood.org";
|
||||
github = "Jesssullivan";
|
||||
githubId = 37297218;
|
||||
name = "Jess Sullivan";
|
||||
};
|
||||
jethair = {
|
||||
email = "jethair@duck.com";
|
||||
github = "JetHair";
|
||||
@@ -14387,6 +14333,12 @@
|
||||
githubId = 451835;
|
||||
name = "Kirill Elagin";
|
||||
};
|
||||
kirikaza = {
|
||||
email = "k@kirikaza.ru";
|
||||
github = "kirikaza";
|
||||
githubId = 804677;
|
||||
name = "Kirill Kazakov";
|
||||
};
|
||||
kirillrdy = {
|
||||
email = "kirillrdy@gmail.com";
|
||||
github = "kirillrdy";
|
||||
@@ -15631,6 +15583,12 @@
|
||||
githubId = 4312404;
|
||||
name = "Chris Rendle-Short";
|
||||
};
|
||||
lightdiscord = {
|
||||
email = "root@arnaud.sh";
|
||||
github = "lightdiscord";
|
||||
githubId = 24509182;
|
||||
name = "Arnaud Pascal";
|
||||
};
|
||||
lightquantum = {
|
||||
email = "self@lightquantum.me";
|
||||
github = "PhotonQuantum";
|
||||
@@ -15837,6 +15795,12 @@
|
||||
githubId = 23727619;
|
||||
name = "Luca Ruperto";
|
||||
};
|
||||
lnl7 = {
|
||||
email = "daiderd@gmail.com";
|
||||
github = "LnL7";
|
||||
githubId = 689294;
|
||||
name = "Daiderd Jordan";
|
||||
};
|
||||
lo1tuma = {
|
||||
email = "schreck.mathias@gmail.com";
|
||||
github = "lo1tuma";
|
||||
@@ -16301,11 +16265,6 @@
|
||||
githubId = 26020062;
|
||||
name = "lumi";
|
||||
};
|
||||
luminarleaf = {
|
||||
github = "LuminarLeaf";
|
||||
githubId = 80571430;
|
||||
name = "Luminar Leaf";
|
||||
};
|
||||
luna_1024 = {
|
||||
email = "contact@luna.computer";
|
||||
github = "luna-1024";
|
||||
@@ -16484,12 +16443,6 @@
|
||||
githubId = 8094643;
|
||||
keys = [ { fingerprint = "BAA9 7711 58CA D457 B4AE 8B06 8188 423D 2FA2 0A65"; } ];
|
||||
};
|
||||
m4r1vs = {
|
||||
email = "marius.niveri@gmail.com";
|
||||
name = "Marius Niveri";
|
||||
github = "m4r1vs";
|
||||
githubId = 26097311;
|
||||
};
|
||||
m7medvision = {
|
||||
name = "Mohammed";
|
||||
github = "m7medVision";
|
||||
@@ -17428,6 +17381,12 @@
|
||||
githubId = 613740;
|
||||
name = "Martin Baillie";
|
||||
};
|
||||
mbbx6spp = {
|
||||
email = "me@susanpotter.net";
|
||||
github = "mbbx6spp";
|
||||
githubId = 564;
|
||||
name = "Susan Potter";
|
||||
};
|
||||
mbe = {
|
||||
email = "brandonedens@gmail.com";
|
||||
github = "brandonedens";
|
||||
@@ -18301,6 +18260,13 @@
|
||||
githubId = 52108954;
|
||||
name = "Matias Zwinger";
|
||||
};
|
||||
mkf = {
|
||||
email = "m@mikf.pl";
|
||||
github = "mkf";
|
||||
githubId = 7753506;
|
||||
name = "Michał Krzysztof Feiler";
|
||||
keys = [ { fingerprint = "1E36 9940 CC7E 01C4 CFE8 F20A E35C 2D7C 2C6A C724"; } ];
|
||||
};
|
||||
mkg = {
|
||||
email = "mkg@vt.edu";
|
||||
github = "mkgvt";
|
||||
@@ -18733,10 +18699,10 @@
|
||||
keys = [ { fingerprint = "3B66 ACFA D10F 02AA B1D5 2CB1 8DD0 D81D 7D1F C61A"; } ];
|
||||
};
|
||||
mshnwq = {
|
||||
email = "hmachnouk@proton.me";
|
||||
email = "mshnwq.com@gmail.com";
|
||||
github = "mshnwq";
|
||||
githubId = 68467027;
|
||||
name = "Mshnwq";
|
||||
name = "Hayan Al-Machnouk";
|
||||
};
|
||||
msiedlarek = {
|
||||
email = "mikolaj@siedlarek.pl";
|
||||
@@ -19405,11 +19371,6 @@
|
||||
githubId = 79978224;
|
||||
name = "winston";
|
||||
};
|
||||
nelind = {
|
||||
name = "Nel";
|
||||
github = "nelind3";
|
||||
githubId = 57587152;
|
||||
};
|
||||
nelsonjeppesen = {
|
||||
email = "nix@jeppesen.io";
|
||||
github = "NelsonJeppesen";
|
||||
@@ -19438,12 +19399,6 @@
|
||||
name = "neo";
|
||||
email = "chojs990222@gmail.com";
|
||||
};
|
||||
neonvoid = {
|
||||
email = "me@neonvoid.dev";
|
||||
github = "neonvoidx";
|
||||
githubId = 25580051;
|
||||
name = "neonvoid";
|
||||
};
|
||||
neosimsim = {
|
||||
email = "me@abn.sh";
|
||||
github = "neosimsim";
|
||||
@@ -19508,12 +19463,6 @@
|
||||
githubId = 1488603;
|
||||
name = "François Espinet";
|
||||
};
|
||||
netpleb = {
|
||||
email = "netpleb@proton.me";
|
||||
github = "netpleb";
|
||||
githubId = 130105838;
|
||||
name = "netpleb";
|
||||
};
|
||||
netthier = {
|
||||
email = "netthier@proton.me";
|
||||
name = "nett_hier";
|
||||
@@ -20405,12 +20354,6 @@
|
||||
email = "nyu@nyuku.ru";
|
||||
githubId = 97425873;
|
||||
};
|
||||
nyxar77 = {
|
||||
name = "nyxar77";
|
||||
github = "nyxar77";
|
||||
email = "dev@nyxar.space";
|
||||
githubId = 153492661;
|
||||
};
|
||||
nyxonios = {
|
||||
name = "nyxonios";
|
||||
github = "Nyxonios";
|
||||
@@ -21444,12 +21387,6 @@
|
||||
githubId = 7420227;
|
||||
name = "Peter Tri Ho";
|
||||
};
|
||||
peterwaller-arm = {
|
||||
email = "peter.waller@arm.com";
|
||||
github = "peterwaller-arm";
|
||||
githubId = 52030119;
|
||||
name = "Peter Waller";
|
||||
};
|
||||
peterwilli = {
|
||||
email = "peter@codebuffet.co";
|
||||
github = "peterwilli";
|
||||
@@ -22165,12 +22102,6 @@
|
||||
githubId = 246631;
|
||||
keys = [ { fingerprint = "3E46 7EF1 54AA A1D0 C7DF A694 E45C B17F 1940 CA52"; } ];
|
||||
};
|
||||
pretentiousUsername = {
|
||||
name = "Ian Mitchell";
|
||||
email = "mitchell.ian.2001@gmail.com";
|
||||
github = "pretentiousUsername";
|
||||
githubId = 94192644;
|
||||
};
|
||||
priegger = {
|
||||
email = "philipp@riegger.name";
|
||||
github = "priegger";
|
||||
@@ -23405,6 +23336,12 @@
|
||||
githubId = 6047658;
|
||||
name = "Ryan Horiguchi";
|
||||
};
|
||||
rht = {
|
||||
email = "rhtbot@protonmail.com";
|
||||
github = "rht";
|
||||
githubId = 395821;
|
||||
name = "rht";
|
||||
};
|
||||
rhydianjenkins = {
|
||||
name = "Rhydian Jenkins";
|
||||
github = "RhydianJenkins";
|
||||
@@ -23440,13 +23377,6 @@
|
||||
githubId = 61013287;
|
||||
name = "Ricardo Steijn";
|
||||
};
|
||||
ricardomaps = {
|
||||
email = "ricardomapurungajunior@gmail.com";
|
||||
github = "ricardomaps";
|
||||
githubId = 49507078;
|
||||
name = "Ricardo Mapurunga Junior";
|
||||
matrix = "@ricmaps:matrix.org";
|
||||
};
|
||||
richar = {
|
||||
github = "ri-char";
|
||||
githubId = 17962023;
|
||||
@@ -25096,12 +25026,6 @@
|
||||
githubId = 2049686;
|
||||
name = "Sebastián Estrella";
|
||||
};
|
||||
seudonym = {
|
||||
name = "Wahid Khan";
|
||||
email = "wk170179+nixpkgs@gmail.com";
|
||||
github = "seudonym";
|
||||
githubId = 80459261;
|
||||
};
|
||||
seven_bear = {
|
||||
name = "Edmond Freeman";
|
||||
email = "edmondfreeman7@gmail.com";
|
||||
@@ -25374,6 +25298,12 @@
|
||||
githubId = 487050;
|
||||
name = "Shea Levy";
|
||||
};
|
||||
shlok = {
|
||||
email = "sd-nix-maintainer@quant.is";
|
||||
github = "shlok";
|
||||
githubId = 3000933;
|
||||
name = "Shlok Datye";
|
||||
};
|
||||
shmish111 = {
|
||||
email = "shmish111@gmail.com";
|
||||
github = "shmish111";
|
||||
@@ -25716,6 +25646,12 @@
|
||||
githubId = 216167;
|
||||
name = "Steve Jones";
|
||||
};
|
||||
sjmackenzie = {
|
||||
email = "setori88@gmail.com";
|
||||
github = "sjmackenzie";
|
||||
githubId = 158321;
|
||||
name = "Stewart Mackenzie";
|
||||
};
|
||||
skaphi = {
|
||||
name = "Oskar Philipsson";
|
||||
email = "oskar.philipsson@gmail.com";
|
||||
@@ -25758,7 +25694,6 @@
|
||||
};
|
||||
skyesoss = {
|
||||
name = "Skye Soss";
|
||||
email = "skye@soss.website";
|
||||
matrix = "@skyesoss:matrix.org";
|
||||
github = "Skyb0rg007";
|
||||
githubId = 30806179;
|
||||
@@ -26156,12 +26091,6 @@
|
||||
name = "sportshead";
|
||||
keys = [ { fingerprint = "A6B6 D031 782E BDF7 631A 8E7E A874 DB2C BFD3 CFD0"; } ];
|
||||
};
|
||||
spotdemo4 = {
|
||||
email = "me@trev.xyz";
|
||||
github = "spotdemo4";
|
||||
githubId = 3732640;
|
||||
name = "spotdemo4";
|
||||
};
|
||||
spreetin = {
|
||||
email = "spreetin@protonmail.com";
|
||||
name = "David Falk";
|
||||
@@ -28407,6 +28336,12 @@
|
||||
githubId = 77488956;
|
||||
name = "Timothy Tschnitzel";
|
||||
};
|
||||
ttuegel = {
|
||||
email = "ttuegel@mailbox.org";
|
||||
github = "ttuegel";
|
||||
githubId = 563054;
|
||||
name = "Thomas Tuegel";
|
||||
};
|
||||
tu-maurice = {
|
||||
email = "valentin.gehrke+nixpkgs@zom.bi";
|
||||
github = "tu-maurice";
|
||||
@@ -28593,12 +28528,6 @@
|
||||
githubId = 30677291;
|
||||
name = "u2x1";
|
||||
};
|
||||
u3kkasha = {
|
||||
email = "fida.waseque@gmail.com";
|
||||
github = "u3kkasha";
|
||||
githubId = 146055002;
|
||||
name = "Fida Waseque Choudhury";
|
||||
};
|
||||
uakci = {
|
||||
name = "uakci";
|
||||
email = "git@uakci.space";
|
||||
@@ -29498,12 +29427,6 @@
|
||||
github = "wdavidw";
|
||||
githubId = 46896;
|
||||
};
|
||||
wduo87391 = {
|
||||
name = "wduo87391";
|
||||
email = "wduo87391@gmail.com";
|
||||
github = "wduo87391";
|
||||
githubId = 197874825;
|
||||
};
|
||||
weathercold = {
|
||||
name = "Weathercold";
|
||||
email = "weathercold.scr@proton.me";
|
||||
@@ -29690,11 +29613,6 @@
|
||||
}
|
||||
];
|
||||
};
|
||||
wilaz = {
|
||||
name = "Wilaz";
|
||||
github = "Wilaz";
|
||||
githubId = 98198668;
|
||||
};
|
||||
wildsebastian = {
|
||||
name = "Sebastian Wild";
|
||||
email = "sebastian@wild-siena.com";
|
||||
|
||||
@@ -49,7 +49,6 @@ lpeglabel,,,,1.6.0,,
|
||||
lrexlib-gnu,,,,,,
|
||||
lrexlib-oniguruma,,,,,,junestepp
|
||||
lrexlib-pcre,,,,,,
|
||||
lrexlib-pcre2,,,,,,wishstudio
|
||||
lrexlib-posix,,,,,,
|
||||
lsp-progress.nvim,,,,,5.1,gepbird
|
||||
lsqlite3,,,,,,
|
||||
@@ -168,7 +167,6 @@ telescope.nvim,,,,,5.1,
|
||||
tiktoken_core,,,,,,natsukium
|
||||
tl,,,,,,mephistophiles
|
||||
toml-edit,,,,,5.1,mrcjkb
|
||||
tomlua,,,,,,birdee
|
||||
tree-sitter-cli,,,,,,
|
||||
tree-sitter-http,,,,0.0.33-1,,
|
||||
tree-sitter-norg,,,,,5.1,mrcjkb
|
||||
@@ -176,7 +174,6 @@ tree-sitter-norg-meta,,,,,,
|
||||
tree-sitter-orgmode,,,,,5.1,
|
||||
utf8,,,,,,
|
||||
tree-sitter-teal,,,,,,
|
||||
vicious,,,,,,
|
||||
vstruct,,,,,,
|
||||
vusted,,,,,,
|
||||
xml2lua,,,,,,teto
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
Common configuration for headless machines (e.g., Amazon EC2 instances).
|
||||
|
||||
Disables serial consoles,
|
||||
Disables [vesa](#opt-boot.vesa), serial consoles,
|
||||
[emergency mode](#opt-systemd.enableEmergencyMode),
|
||||
[grub splash images](#opt-boot.loader.grub.splashImage)
|
||||
and configures the kernel to reboot automatically on panic.
|
||||
|
||||
@@ -6,7 +6,7 @@ Status: in development. This functionality is new in NixOS 25.11, and significan
|
||||
Traditionally, NixOS services were defined using sets of options *in* modules, not *as* modules. This made them non-modular, resulting in problems with composability, reuse, and portability.
|
||||
|
||||
A configuration management framework is an application of `evalModules` with the `class` and `specialArgs` input attribute set to particular values.
|
||||
NixOS is such a configuration management framework, and so are [Home Manager](https://github.com/nix-community/home-manager) and [`nix-darwin`](https://github.com/nix-darwin/nix-darwin).
|
||||
NixOS is such a configuration management framework, and so are [Home Manager](https://github.com/nix-community/home-manager) and [`nix-darwin`](https://github.com/lnl7/nix-darwin).
|
||||
|
||||
The service management component of a configuration management framework is the set of module options that connects Nix expressions with the underlying service (or process) manager.
|
||||
For NixOS this is the module wrapping [`systemd`](https://systemd.io/), on `nix-darwin` this is the module wrapping [`launchd`](https://en.wikipedia.org/wiki/Launchd).
|
||||
|
||||
@@ -494,47 +494,6 @@ Composed types are types that take a type as parameter. `listOf
|
||||
|
||||
Displays the option as `foo.<id>` in the manual.
|
||||
|
||||
`types.attrListOf` *`t`*
|
||||
|
||||
: An ordered list of single-attribute attribute sets, where each value is of *`t`* type.
|
||||
The output is always `[ { name1 = value1; } { name2 = value2; } ... ]`.
|
||||
|
||||
Definitions can be provided in two formats, which may be mixed via `lib.mkMerge`, `imports`, etc:
|
||||
|
||||
- **List format**: `[ { a = 1; } { b = 2; } ]` — each element must be a single-attribute attribute set.
|
||||
Elements may be wrapped in `lib.mkOrder` (or `lib.mkBefore`/`lib.mkAfter`) to control ordering;
|
||||
unwrapped elements use the default order priority.
|
||||
|
||||
- **Attribute set format**: `{ a = lib.mkOrder 100 1; b = 2; }` — each name-value pair becomes a single-attribute attribute set in the output.
|
||||
Values may be wrapped in `lib.mkOrder` (or `lib.mkBefore`/`lib.mkAfter`) to control ordering.
|
||||
Values without `lib.mkOrder` use the default priority.
|
||||
|
||||
Multiple definitions of the same option are concatenated and then sorted by priority.
|
||||
Entries at the same priority level preserve their definition order.
|
||||
|
||||
`types.attrListWith` { *`elemType`*, *`asAttrs`* ? false, *`mergeAttrValues`* ? _name: values: values }
|
||||
|
||||
: An ordered list of single-attribute attribute sets, where each value is of *`elemType`* type.
|
||||
|
||||
**Parameters**
|
||||
|
||||
`elemType` (Required)
|
||||
: Specifies the type of each value in the attribute list.
|
||||
|
||||
`asAttrs`
|
||||
: When `true`, the option value is an attribute set instead of a list.
|
||||
Duplicate keys are merged using `mergeAttrValues`.
|
||||
The ordered list is always available via `valueMeta.attrListValue`.
|
||||
|
||||
`mergeAttrValues`
|
||||
: A function `name: values: mergedValue` that controls how duplicate keys
|
||||
are combined when `asAttrs = true`. This is passed as the callback to
|
||||
`lib.zipAttrsWith`. The `values` list is in order of priority.
|
||||
By default, all values are collected into a list.
|
||||
|
||||
**Behavior**
|
||||
|
||||
- `attrListWith { elemType = t; }` is equivalent to `attrListOf t`
|
||||
|
||||
`types.uniq` *`t`*
|
||||
|
||||
|
||||
@@ -65,42 +65,6 @@
|
||||
"module-services-keycloak-unix-socket": [
|
||||
"index.html#module-services-keycloak-unix-socket"
|
||||
],
|
||||
"module-services-mautrix-discord": [
|
||||
"index.html#module-services-mautrix-discord"
|
||||
],
|
||||
"module-services-mautrix-discord-advanced": [
|
||||
"index.html#module-services-mautrix-discord-advanced"
|
||||
],
|
||||
"module-services-mautrix-discord-authentication": [
|
||||
"index.html#module-services-mautrix-discord-authentication"
|
||||
],
|
||||
"module-services-mautrix-discord-backfill": [
|
||||
"index.html#module-services-mautrix-discord-backfill"
|
||||
],
|
||||
"module-services-mautrix-discord-basic-example": [
|
||||
"index.html#module-services-mautrix-discord-basic-example"
|
||||
],
|
||||
"module-services-mautrix-discord-basic-usage": [
|
||||
"index.html#module-services-mautrix-discord-basic-usage"
|
||||
],
|
||||
"module-services-mautrix-discord-double-puppet": [
|
||||
"index.html#module-services-mautrix-discord-double-puppet"
|
||||
],
|
||||
"module-services-mautrix-discord-encryption": [
|
||||
"index.html#module-services-mautrix-discord-encryption"
|
||||
],
|
||||
"module-services-mautrix-discord-server-defaults": [
|
||||
"index.html#module-services-mautrix-discord-server-defaults"
|
||||
],
|
||||
"module-services-mautrix-discord-setup": [
|
||||
"index.html#module-services-mautrix-discord-setup"
|
||||
],
|
||||
"module-services-mautrix-discord-synapse": [
|
||||
"index.html#module-services-mautrix-discord-synapse"
|
||||
],
|
||||
"module-services-mautrix-discord-troubleshooting": [
|
||||
"index.html#module-services-mautrix-discord-troubleshooting"
|
||||
],
|
||||
"module-services-tandoor-recipes-migrating-media-option-move": [
|
||||
"index.html#module-services-tandoor-recipes-migrating-media-option-move",
|
||||
"index.html#module-services-tandoor-recipes-migrating-media-option-1"
|
||||
@@ -2399,21 +2363,6 @@
|
||||
"ch-release-notes": [
|
||||
"release-notes.html#ch-release-notes"
|
||||
],
|
||||
"sec-release-26.11": [
|
||||
"release-notes.html#sec-release-26.11"
|
||||
],
|
||||
"sec-release-26.11-highlights": [
|
||||
"release-notes.html#sec-release-26.11-highlights"
|
||||
],
|
||||
"sec-release-26.11-new-modules": [
|
||||
"release-notes.html#sec-release-26.11-new-modules"
|
||||
],
|
||||
"sec-release-26.11-incompatibilities": [
|
||||
"release-notes.html#sec-release-26.11-incompatibilities"
|
||||
],
|
||||
"sec-release-26.11-notable-changes": [
|
||||
"release-notes.html#sec-release-26.11-notable-changes"
|
||||
],
|
||||
"sec-release-26.05": [
|
||||
"release-notes.html#sec-release-26.05"
|
||||
],
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
This section lists the release notes for each stable version of NixOS and current unstable revision.
|
||||
|
||||
```{=include=} sections
|
||||
rl-2611.section.md
|
||||
rl-2605.section.md
|
||||
rl-2511.section.md
|
||||
rl-2505.section.md
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
- If you use LUKS disk encryption, ensure that `fileSystems."/".device` is set to `"/dev/mapper/<name>"`, where `<name>` matches the name in your `boot.initrd.luks.devices.<name>` definition, to avoid systemd timing out while prompting for a passphrase. If you have a more complex setup, e.g. with LVM on top of LUKS, you may need to add `"x-systemd.device-timeout=infinity"` to `fileSystems."/".options` instead. If you need to disable the timeout before you can boot into the system, pass `systemd.default_device_timeout_sec=infinity` on the kernel command line.
|
||||
- The `cryptsetup-askpass` program is not available; use `systemctl default` instead, which will prompt for passphrases as necessary. If you pipe password responses into SSH over stdin, use `ssh -o RequestTTY=force` to ensure `systemctl default` gets a TTY to prompt on.
|
||||
- Many kernel parameters have been replaced with native systemd versions; see [](#sec-boot-problems).
|
||||
- `/dev/root` is not available with the systemd stage 1. In the old scripted stage 1, `/dev/root` was a symlink created by the init script from the `root=` kernel command line. With systemd stage 1, this symlink is not provided. If your configuration uses `/dev/root` in `fileSystems`, replace it with a stable device path such as `/dev/disk/by-label/...`, `/dev/disk/by-uuid/...`, or the appropriate `/dev/mapper/...` path.
|
||||
|
||||
- The system.nix file has been added as an alternative entry point to configuration.nix (and flake.nix) that allows configuring NixOS without using `nix-channel`.
|
||||
This file must evaluate to a NixOS system derivation or an attribute set of such derivations, in which case the attribute to build has to be selected with the `--attr` option of `nixos-rebuild` or `nixos-install`.
|
||||
@@ -96,8 +95,6 @@
|
||||
|
||||
- [kiwix-serve](https://wiki.kiwix.org/wiki/Kiwix-serve), a service that serves ZIM files (such as Wikipedia archives) over HTTP. Available as [services.kiwix-serve](#opt-services.kiwix-serve.enable).
|
||||
|
||||
- [matterjs-server](https://github.com/matter-js/matterjs-server), a Matter controller with a Home Assistant compatible WebSocket API. Available as [services.matterjs-server](#opt-services.matterjs-server.enable).
|
||||
|
||||
- [Remark42](https://remark42.com/), a self-hosted comment engine. Available as [services.remark42](#opt-services.remark42.enable).
|
||||
|
||||
- [LibreChat](https://www.librechat.ai/), open-source self-hostable ChatGPT clone with Agents and RAG APIs. Available as [services.librechat](#opt-services.librechat.enable).
|
||||
@@ -197,8 +194,6 @@
|
||||
|
||||
- `services.home-assistant.config.lovelace.mode` has been renamed to `lovelace.dashboards` and `lovelace.resource_mode` to match the [configuration format](https://www.home-assistant.io/dashboards/dashboards/) required by Home Assistant 2026.8. Users who explicitly set `lovelace.mode` should remove it; the module generates the correct entries automatically.
|
||||
|
||||
- `fulcrum` has been updated to 2.x. If run against an existing v1.x database without the `--db-upgrade` flag it refuses to start; the upgrade takes around an hour on Bitcoin mainnet.
|
||||
|
||||
- `opentrack`, `slushload`, `synthesia`, `vtfedit`, `winbox`, `wineasio`, and `yabridge` use wineWow64Packages instead of wineWowPackages as wine versions >= 11.0 have deprecated wineWowPackages. As such, the prefixes for these packages are NOT backwards compatible and need to be regenerated with potential for data loss.
|
||||
|
||||
- []{#sec-release-26.05-incompatibilities-profiles-hardened-removed} `profiles/hardened` has been removed, because:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Release 26.11 ("Zokor", 2026.11/??) {#sec-release-26.11}
|
||||
# Release 26.11 (2026.11/??) {#sec-release-26.11}
|
||||
|
||||
## Highlights {#sec-release-26.11-highlights}
|
||||
|
||||
@@ -10,26 +10,16 @@
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
|
||||
- [tranquil](https://tangled.org/tranquil.farm/tranquil-pds) is an ATProto PDS (personal data server) implementation in Rust. A featureful, spec conscious and community driven alternative to the Bluesky reference implementation PDS. Available as [services.tranquil-pds](#opt-services.tranquil-pds.enable).
|
||||
|
||||
- [FlapAlerted](https://github.com/Kioubit/FlapAlerted), detects BGP flapping events and provides statistics based on BGP update messages. Available as [services.flap-alerted](#opt-services.flap-alerted.enable).
|
||||
- Create the first release note entry in this section!
|
||||
|
||||
## Backward Incompatibilities {#sec-release-26.11-incompatibilities}
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
|
||||
- `boot.vesa` has been removed. It was deprecated in 2020 because Xorg now works better with kernel modesetting. If you still need the legacy VESA 800x600 fallback, set `boot.kernelParams = [ "vga=0x317" "nomodeset" ];` directly.
|
||||
|
||||
- Support for the legacy U‐Boot image format has been removed from the initrd generators, as it is deprecated upstream and no longer used by any platform in Nixpkgs.
|
||||
|
||||
- Python 2 has been removed from the top-level package set, as it is long past end-of-life. The `python2`, `python27`, `python2Full`, `python27Full`, `python2Packages`, and `python27Packages` attributes, along with the legacy `python`, `pythonFull`, and `pythonPackages` aliases, now throw an error directing you to `python3`. The `isPy2` and `isPy27` package flags have been removed accordingly. The only remaining Python 2 interpreter is vendored inside the `resholve` package for its `oil` dependency and is not exposed for general use.
|
||||
|
||||
- `services.timesyncd.extraConfig` has been removed in favor of the structured [](#opt-services.timesyncd.settings.Time) option. Use `services.timesyncd.settings.Time` to set any `timesyncd.conf(5)` option directly. For example, replace `services.timesyncd.extraConfig = "PollIntervalMaxSec=180";` with `services.timesyncd.settings.Time.PollIntervalMaxSec = 180;`.
|
||||
- Create the first release note entry in this section!
|
||||
|
||||
## Other Notable Changes {#sec-release-26.11-notable-changes}
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
|
||||
- `boot.loader.systemd-boot` gained support for [Automatic Boot Assessment](https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT/) via the new [`boot.loader.systemd-boot.bootCounting`](#opt-boot.loader.systemd-boot.bootCounting.enable) options, allowing automatic detection of and recovery from bad NixOS generations. As part of this change, boot loader entries on the ESP/XBOOTLDR partition are now named `nixos-<content-hash>.conf` instead of `nixos-generation-<n>.conf`; existing entries are migrated automatically on the next `nixos-rebuild boot`/`switch`.
|
||||
|
||||
- The `newuidmap` and `newgidmap` security wrappers are now installed with `cap_setuid`/`cap_setgid` file capabilities instead of the setuid-root bit, matching shadow's `--with-fcaps` install mode and other major distributions. Rootless containers (podman, docker-rootless, unprivileged user namespaces) are unaffected. The only behavioural change is that mapping host uid 0 via `/etc/subuid` (which NixOS never configures by default) additionally requires `cap_setfcap`; users who explicitly grant uid 0 in a subuid range can restore the previous behaviour with `security.wrappers.newuidmap.capabilities = lib.mkForce "cap_setuid,cap_setfcap+ep";`.
|
||||
- Create the first release note entry in this section!
|
||||
|
||||
@@ -1031,7 +1031,6 @@ class QemuMachine(BaseMachine):
|
||||
As soon as we read some data from the socket here, we assume that
|
||||
our root shell is operational.
|
||||
"""
|
||||
assert self.shell
|
||||
(ready, _, _) = select.select([self.shell], [], [], timeout_secs)
|
||||
return bool(ready)
|
||||
|
||||
|
||||
@@ -5,12 +5,7 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
literalExpression
|
||||
literalMD
|
||||
;
|
||||
inherit (lib) mkOption types literalMD;
|
||||
|
||||
inherit (config) sshBackdoor;
|
||||
|
||||
@@ -122,10 +117,9 @@ in
|
||||
{
|
||||
options = {
|
||||
pythonTestDriverPackage = mkOption {
|
||||
description = "Package containing the python NixOS test driver implementation";
|
||||
description = "Package containing the python NixOS test driver implemetnation";
|
||||
type = types.package;
|
||||
default = hostPkgs.nixos-test-driver;
|
||||
defaultText = literalExpression "hostPkgs.nixos-test-driver";
|
||||
readOnly = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@ in
|
||||
# When imperative, seed /etc/vconsole.conf on first boot from declared
|
||||
# defaults so the keymap isn't lost before localectl is ever used
|
||||
systemd.tmpfiles.rules = lib.mkIf i18nCfg.imperativeLocale [
|
||||
"C /etc/vconsole.conf - - - - ${vconsoleConf true}"
|
||||
"C /etc/vconsole.conf - - - - ${vconsoleConf}"
|
||||
];
|
||||
|
||||
systemd.services.reload-systemd-vconsole-setup = {
|
||||
|
||||
@@ -47,8 +47,6 @@ in
|
||||
gyre-fonts # TrueType substitutes for standard PostScript fonts
|
||||
liberation_ttf
|
||||
unifont
|
||||
noto-fonts-cjk-sans
|
||||
noto-fonts-cjk-serif
|
||||
noto-fonts-color-emoji
|
||||
]
|
||||
);
|
||||
|
||||
@@ -6,16 +6,12 @@
|
||||
- ./nix.nix
|
||||
- ./nix-flakes.nix
|
||||
*/
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkOption
|
||||
stringAfter
|
||||
types
|
||||
;
|
||||
|
||||
@@ -74,7 +70,7 @@ in
|
||||
defaultChannel = mkOption {
|
||||
internal = true;
|
||||
type = types.str;
|
||||
default = "https://channels.nixos.org/nixos-unstable";
|
||||
default = "https://channels.nixos.org/nixos-26.05";
|
||||
description = "Default NixOS channel to which the root user is subscribed.";
|
||||
};
|
||||
};
|
||||
@@ -102,10 +98,8 @@ in
|
||||
''f /root/.nix-channels - - - - ${config.system.defaultChannel} nixos\n''
|
||||
];
|
||||
|
||||
system.preSwitchChecks.no-nix-channel = mkIf (!cfg.channel.enable) (
|
||||
lib.replaceStrings [ "@getent@" ] [ (lib.getExe pkgs.getent) ] (
|
||||
builtins.readFile ./nix-channel/pre-switch-check.sh
|
||||
)
|
||||
system.activationScripts.no-nix-channel = mkIf (!cfg.channel.enable) (
|
||||
stringAfter [ "etc" "users" ] (builtins.readFile ./nix-channel/activation-check.sh)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
warn() {
|
||||
printf "\033[1;35mwarning:\033[0m %s\n" "$*" >&2
|
||||
}
|
||||
# shellcheck shell=bash
|
||||
|
||||
explainChannelWarning=0
|
||||
if [[ -e "/root/.nix-defexpr/channels" ]]; then
|
||||
@@ -13,13 +11,11 @@ if [[ -e "/nix/var/nix/profiles/per-user/root/channels" ]]; then
|
||||
fi
|
||||
while IFS=: read -r _ _ _ _ _ home _ ; do
|
||||
if [[ -n "$home" && -e "$home/.nix-defexpr/channels" ]]; then
|
||||
warn "$home/.nix-defexpr/channels exists, but channels have been disabled."
|
||||
warn "$home/.nix-defexpr/channels exists, but channels have been disabled." 1>&2
|
||||
explainChannelWarning=1
|
||||
fi
|
||||
done < <(@getent@ passwd)
|
||||
done < <(getent passwd)
|
||||
if [[ $explainChannelWarning -eq 1 ]]; then
|
||||
echo "Due to https://github.com/NixOS/nix/issues/9574, Nix may still use these channels when NIX_PATH is unset." >&2
|
||||
echo "Delete the above directory or directories to prevent this." >&2
|
||||
echo "Due to https://github.com/NixOS/nix/issues/9574, Nix may still use these channels when NIX_PATH is unset." 1>&2
|
||||
echo "Delete the above directory or directories to prevent this." 1>&2
|
||||
fi
|
||||
# This check is informational only and must never block a switch.
|
||||
true
|
||||
20
nixos/modules/config/nix-channel/test.nix
Normal file
20
nixos/modules/config/nix-channel/test.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
# Run:
|
||||
# nix-build -A nixosTests.nix-channel
|
||||
{ lib, testers }:
|
||||
let
|
||||
inherit (lib) fileset;
|
||||
|
||||
runShellcheck = testers.shellcheck {
|
||||
name = "activation-check";
|
||||
src = fileset.toSource {
|
||||
root = ./.;
|
||||
fileset = fileset.unions [
|
||||
./activation-check.sh
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
lib.recurseIntoAttrs {
|
||||
inherit runShellcheck;
|
||||
}
|
||||
@@ -36,22 +36,25 @@
|
||||
# Avoid bundling an entire MariaDB installation on the ISO.
|
||||
programs.kde-pim.enable = false;
|
||||
|
||||
systemd.tmpfiles.settings."10-installer-desktop" =
|
||||
system.activationScripts.installerDesktop =
|
||||
let
|
||||
|
||||
# Comes from documentation.nix when xserver and nixos.enable are true.
|
||||
manualDesktopFile = "/run/current-system/sw/share/applications/nixos-manual.desktop";
|
||||
|
||||
homeDir = "/home/nixos/";
|
||||
desktopDir = homeDir + "Desktop/";
|
||||
|
||||
in
|
||||
{
|
||||
"/home/nixos/Desktop".d = {
|
||||
user = "nixos";
|
||||
group = "users";
|
||||
mode = "0755";
|
||||
};
|
||||
"/home/nixos/Desktop/nixos-manual.desktop"."L+".argument = manualDesktopFile;
|
||||
"/home/nixos/Desktop/gparted.desktop"."L+".argument =
|
||||
"${pkgs.gparted}/share/applications/gparted.desktop";
|
||||
"/home/nixos/Desktop/calamares.desktop"."L+".argument =
|
||||
"${pkgs.calamares-nixos}/share/applications/calamares.desktop";
|
||||
};
|
||||
''
|
||||
mkdir -p ${desktopDir}
|
||||
chown nixos ${homeDir} ${desktopDir}
|
||||
|
||||
ln -sfT ${manualDesktopFile} ${desktopDir + "nixos-manual.desktop"}
|
||||
ln -sfT ${pkgs.gparted}/share/applications/gparted.desktop ${desktopDir + "gparted.desktop"}
|
||||
ln -sfT ${pkgs.calamares-nixos}/share/applications/calamares.desktop ${
|
||||
desktopDir + "calamares.desktop"
|
||||
}
|
||||
'';
|
||||
|
||||
}
|
||||
|
||||
@@ -787,10 +787,9 @@ in
|
||||
options = [ "mode=0755" ];
|
||||
};
|
||||
|
||||
# With systemd stage 1, the ISO is identified by its volume label.
|
||||
# With the scripted stage 1, /dev/root is a symlink to the actual
|
||||
# root device specified on the kernel command line, created by the
|
||||
# stage 1 init script.
|
||||
# Note that /dev/root is a symlink to the actual root device
|
||||
# specified on the kernel command line, created in the stage 1
|
||||
# init script.
|
||||
"/iso" = lib.mkImageMediaOverride {
|
||||
device =
|
||||
if config.boot.initrd.systemd.enable then
|
||||
|
||||
@@ -314,27 +314,6 @@ in
|
||||
name = "nixos-rebuild";
|
||||
package = config.system.build.nixos-rebuild;
|
||||
})
|
||||
(
|
||||
{ config, ... }:
|
||||
{
|
||||
options.system.tools.nixos-rebuild.enableRun0Elevation = lib.mkEnableOption ''
|
||||
support for being targeted by `nixos-rebuild --elevate=run0
|
||||
--ask-elevate-password`.
|
||||
|
||||
This enables polkit and adds {command}`polkit-stdin-agent` to
|
||||
{option}`environment.systemPackages` so that a deploying host
|
||||
can find a target-architecture agent at
|
||||
{file}`<toplevel>/sw/bin/polkit-stdin-agent` after copying the
|
||||
closure (which is required for cross-architecture deploys and
|
||||
mismatched nixpkgs revisions to work).
|
||||
'';
|
||||
|
||||
config = lib.mkIf config.system.tools.nixos-rebuild.enableRun0Elevation {
|
||||
security.polkit.enable = lib.mkDefault true;
|
||||
environment.systemPackages = [ pkgs.polkit-stdin-agent ];
|
||||
};
|
||||
}
|
||||
)
|
||||
(mkToolModule {
|
||||
name = "nixos-version";
|
||||
package = nixos-version;
|
||||
|
||||
@@ -51,6 +51,7 @@ let
|
||||
VENDOR_URL = optionalString isNixos "https://nixos.org/";
|
||||
DOCUMENTATION_URL = optionalString isNixos "https://nixos.org/learn.html";
|
||||
SUPPORT_URL = optionalString isNixos "https://nixos.org/community.html";
|
||||
SUPPORT_END = "2026-12-31";
|
||||
BUG_REPORT_URL = optionalString isNixos "https://github.com/NixOS/nixpkgs/issues";
|
||||
ANSI_COLOR = optionalString isNixos "0;38;2;126;186;228";
|
||||
IMAGE_ID = optionalString (config.system.image.id != null) config.system.image.id;
|
||||
|
||||
@@ -394,6 +394,7 @@
|
||||
./security/ca.nix
|
||||
./security/chromium-suid-sandbox.nix
|
||||
./security/default.nix
|
||||
./security/dhparams.nix
|
||||
./security/doas.nix
|
||||
./security/duosec.nix
|
||||
./security/google_oslogin.nix
|
||||
@@ -732,7 +733,6 @@
|
||||
./services/home-automation/home-assistant.nix
|
||||
./services/home-automation/homebridge.nix
|
||||
./services/home-automation/matter-server.nix
|
||||
./services/home-automation/matterjs-server.nix
|
||||
./services/home-automation/openthread-border-router.nix
|
||||
./services/home-automation/wyoming/faster-whisper.nix
|
||||
./services/home-automation/wyoming/openwakeword.nix
|
||||
@@ -887,7 +887,6 @@
|
||||
./services/misc/ihaskell.nix
|
||||
./services/misc/iio-niri.nix
|
||||
./services/misc/input-remapper.nix
|
||||
./services/misc/inventree.nix
|
||||
./services/misc/invidious-router.nix
|
||||
./services/misc/irkerd.nix
|
||||
./services/misc/jackett.nix
|
||||
@@ -1018,7 +1017,6 @@
|
||||
./services/monitoring/das_watchdog.nix
|
||||
./services/monitoring/datadog-agent.nix
|
||||
./services/monitoring/do-agent.nix
|
||||
./services/monitoring/flap-alerted.nix
|
||||
./services/monitoring/fluent-bit.nix
|
||||
./services/monitoring/fusion-inventory.nix
|
||||
./services/monitoring/gatus.nix
|
||||
@@ -1794,7 +1792,6 @@
|
||||
./services/web-apps/suwayomi-server.nix
|
||||
./services/web-apps/szurubooru.nix
|
||||
./services/web-apps/tabbyapi.nix
|
||||
./services/web-apps/tranquil-pds.nix
|
||||
./services/web-apps/trilium.nix
|
||||
./services/web-apps/tt-rss.nix
|
||||
./services/web-apps/tuliprox.nix
|
||||
|
||||
@@ -15,8 +15,6 @@ in
|
||||
programs.gamemode = {
|
||||
enable = lib.mkEnableOption "GameMode to optimise system performance on demand";
|
||||
|
||||
package = lib.mkPackageOption pkgs "gamemode" { };
|
||||
|
||||
enableRenice =
|
||||
lib.mkEnableOption "CAP_SYS_NICE on gamemoded to support lowering process niceness"
|
||||
// {
|
||||
@@ -55,7 +53,7 @@ in
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment = {
|
||||
systemPackages = [ cfg.package ];
|
||||
systemPackages = [ pkgs.gamemode ];
|
||||
etc."gamemode.ini".source = configFile;
|
||||
};
|
||||
|
||||
@@ -65,14 +63,14 @@ in
|
||||
gamemoded = {
|
||||
owner = "root";
|
||||
group = "root";
|
||||
source = "${cfg.package}/bin/gamemoded";
|
||||
source = "${pkgs.gamemode}/bin/gamemoded";
|
||||
capabilities = "cap_sys_nice+ep";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
packages = [ cfg.package ];
|
||||
packages = [ pkgs.gamemode ];
|
||||
user.services.gamemoded = {
|
||||
# Use pkexec from the security wrappers to allow users to
|
||||
# run libexec/cpugovctl & libexec/gpuclockctl as root with
|
||||
|
||||
@@ -26,8 +26,6 @@ in
|
||||
|
||||
package = lib.mkPackageOption pkgs "gamescope" { };
|
||||
|
||||
enableWsi = lib.mkEnableOption "gamescope-wsi, the Vulkan WSI layer, alongside gamescope";
|
||||
|
||||
capSysNice = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
@@ -78,11 +76,6 @@ in
|
||||
};
|
||||
|
||||
environment.systemPackages = lib.mkIf (!cfg.capSysNice) [ gamescope ];
|
||||
|
||||
hardware.graphics = lib.optionalAttrs cfg.enableWsi {
|
||||
extraPackages = with pkgs; [ gamescope-wsi ];
|
||||
extraPackages32 = with pkgs; [ pkgsi686Linux.gamescope-wsi ];
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = [ ];
|
||||
|
||||
@@ -12,15 +12,9 @@ in
|
||||
options = {
|
||||
programs.iotop = {
|
||||
enable = lib.mkEnableOption "iotop + setcap wrapper";
|
||||
|
||||
package = lib.mkPackageOption pkgs "iotop" { example = "iotop-c"; };
|
||||
|
||||
enableDelayacct = lib.mkEnableOption ''
|
||||
the task_delayacct kernel task delay accounting in order to show all
|
||||
statistics'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
security.wrappers.iotop = {
|
||||
owner = "root";
|
||||
@@ -28,7 +22,5 @@ in
|
||||
capabilities = "cap_net_admin+p";
|
||||
source = lib.getExe cfg.package;
|
||||
};
|
||||
|
||||
boot.kernel.sysctl = lib.mkIf cfg.enableDelayacct { "kernel.task_delayacct" = 1; };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -267,22 +267,13 @@ in
|
||||
group = "root";
|
||||
inherit source;
|
||||
};
|
||||
mkCapRoot = capabilities: source: {
|
||||
inherit capabilities source;
|
||||
owner = "root";
|
||||
group = "root";
|
||||
};
|
||||
in
|
||||
{
|
||||
su = mkSetuidRoot "${config.security.shadow.su.package}/bin/su";
|
||||
sg = mkSetuidRoot "${cfg.package.out}/bin/sg";
|
||||
newgrp = mkSetuidRoot "${cfg.package.out}/bin/newgrp";
|
||||
# File capabilities instead of setuid root, mirroring shadow's
|
||||
# own --with-fcaps install mode and what Arch/Fedora/Debian ship.
|
||||
# The kernel only requires CAP_SETUID/CAP_SETGID over the parent
|
||||
# userns to write a multi-line /proc/<pid>/[ug]id_map.
|
||||
newuidmap = mkCapRoot "cap_setuid+ep" "${cfg.package.out}/bin/newuidmap";
|
||||
newgidmap = mkCapRoot "cap_setgid+ep" "${cfg.package.out}/bin/newgidmap";
|
||||
newuidmap = mkSetuidRoot "${cfg.package.out}/bin/newuidmap";
|
||||
newgidmap = mkSetuidRoot "${cfg.package.out}/bin/newgidmap";
|
||||
}
|
||||
// lib.optionalAttrs config.users.mutableUsers {
|
||||
chsh = mkSetuidRoot "${cfg.package.out}/bin/chsh";
|
||||
|
||||
@@ -56,29 +56,38 @@ in
|
||||
'';
|
||||
apply =
|
||||
steam:
|
||||
steam.override (prev: {
|
||||
extraEnv =
|
||||
(lib.optionalAttrs (cfg.extraCompatPackages != [ ]) {
|
||||
STEAM_EXTRA_COMPAT_TOOLS_PATHS = extraCompatPaths;
|
||||
})
|
||||
// (lib.optionalAttrs cfg.extest.enable {
|
||||
LD_PRELOAD = "${pkgs.pkgsi686Linux.extest}/lib/libextest.so";
|
||||
})
|
||||
// (prev.extraEnv or { });
|
||||
extraLibraries =
|
||||
pkgs:
|
||||
let
|
||||
prevLibs = if prev ? extraLibraries then prev.extraLibraries pkgs else [ ];
|
||||
additionalLibs =
|
||||
with config.hardware.graphics;
|
||||
if pkgs.stdenv.hostPlatform.is64bit then
|
||||
[ package ] ++ extraPackages
|
||||
else
|
||||
[ package32 ] ++ extraPackages32;
|
||||
in
|
||||
prevLibs ++ additionalLibs;
|
||||
extraPkgs = p: (cfg.extraPackages ++ lib.optionals (prev ? extraPkgs) (prev.extraPkgs p));
|
||||
});
|
||||
steam.override (
|
||||
prev:
|
||||
{
|
||||
extraEnv =
|
||||
(lib.optionalAttrs (cfg.extraCompatPackages != [ ]) {
|
||||
STEAM_EXTRA_COMPAT_TOOLS_PATHS = extraCompatPaths;
|
||||
})
|
||||
// (lib.optionalAttrs cfg.extest.enable {
|
||||
LD_PRELOAD = "${pkgs.pkgsi686Linux.extest}/lib/libextest.so";
|
||||
})
|
||||
// (prev.extraEnv or { });
|
||||
extraLibraries =
|
||||
pkgs:
|
||||
let
|
||||
prevLibs = if prev ? extraLibraries then prev.extraLibraries pkgs else [ ];
|
||||
additionalLibs =
|
||||
with config.hardware.graphics;
|
||||
if pkgs.stdenv.hostPlatform.is64bit then
|
||||
[ package ] ++ extraPackages
|
||||
else
|
||||
[ package32 ] ++ extraPackages32;
|
||||
in
|
||||
prevLibs ++ additionalLibs;
|
||||
extraPkgs = p: (cfg.extraPackages ++ lib.optionals (prev ? extraPkgs) (prev.extraPkgs p));
|
||||
}
|
||||
// lib.optionalAttrs (cfg.gamescopeSession.enable && gamescopeCfg.capSysNice) {
|
||||
buildFHSEnv = pkgs.buildFHSEnv.override {
|
||||
# use the setuid wrapped bubblewrap
|
||||
bubblewrap = "${config.security.wrapperDir}/..";
|
||||
};
|
||||
}
|
||||
);
|
||||
description = ''
|
||||
The Steam package to use. Additional libraries are added from the system
|
||||
configuration to ensure graphics work properly.
|
||||
@@ -209,6 +218,16 @@ in
|
||||
enable32Bit = true;
|
||||
};
|
||||
|
||||
security.wrappers = lib.mkIf (cfg.gamescopeSession.enable && gamescopeCfg.capSysNice) {
|
||||
# needed or steam fails
|
||||
bwrap = {
|
||||
owner = "root";
|
||||
group = "root";
|
||||
source = "${pkgs.bubblewrap}/bin/bwrap";
|
||||
setuid = true;
|
||||
};
|
||||
};
|
||||
|
||||
programs.steam.extraPackages = cfg.fontPackages;
|
||||
|
||||
programs.gamescope.enable = lib.mkDefault cfg.gamescopeSession.enable;
|
||||
|
||||
@@ -23,7 +23,7 @@ in
|
||||
enable = lib.mkEnableOption "TUN mode of Throne";
|
||||
|
||||
setuid = lib.mkEnableOption ''
|
||||
setting suid bit for ThroneCore to run as root, which is less
|
||||
setting suid bit for throne-core to run as root, which is less
|
||||
secure than default setcap method but closer to upstream assumptions.
|
||||
Enable this if you find the default setcap method configured in
|
||||
this module doesn't work for you
|
||||
@@ -36,8 +36,8 @@ in
|
||||
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
security.wrappers."ThroneCore" = lib.mkIf cfg.tunMode.enable {
|
||||
source = "${cfg.package}/share/throne/ThroneCore";
|
||||
security.wrappers.throne-core = lib.mkIf cfg.tunMode.enable {
|
||||
source = "${cfg.package}/share/throne/Core";
|
||||
owner = "root";
|
||||
group = "root";
|
||||
setuid = lib.mkIf cfg.tunMode.setuid true;
|
||||
@@ -49,7 +49,7 @@ in
|
||||
|
||||
# avoid resolvectl password prompt popping up three times
|
||||
# https://github.com/SagerNet/sing-tun/blob/0686f8c4f210f4e7039c352d42d762252f9d9cf5/tun_linux.go#L1062
|
||||
# We use a hack here to determine whether the requested process is ThroneCore
|
||||
# We use a hack here to determine whether the requested process is throne-core
|
||||
# Detect whether its capabilities contain at least `net_admin` and `net_raw`.
|
||||
# This does not reduce security, as we can already bypass `resolved` with them.
|
||||
# Alternatives to consider:
|
||||
@@ -61,7 +61,7 @@ in
|
||||
# change its own cmdline. `/proc/<pid>/exe` is reliable but kernel forbids
|
||||
# checking that entry of process from different users, and polkit runs `spawn`
|
||||
# as an unprivileged user.
|
||||
# 3. Put ThroneCore into a systemd service, and let polkit check service name.
|
||||
# 3. Put throne-core into a systemd service, and let polkit check service name.
|
||||
# This is the most secure and convenient way but requires heavy modification
|
||||
# to Throne source code. Would be good to let upstream support that eventually.
|
||||
security.polkit.extraConfig =
|
||||
@@ -69,7 +69,6 @@ in
|
||||
''
|
||||
polkit.addRule(function(action, subject) {
|
||||
const allowedActionIds = [
|
||||
"org.freedesktop.resolve1.revert",
|
||||
"org.freedesktop.resolve1.set-domains",
|
||||
"org.freedesktop.resolve1.set-default-route",
|
||||
"org.freedesktop.resolve1.set-dns-servers"
|
||||
|
||||
@@ -249,8 +249,8 @@ in
|
||||
setopt ${builtins.concatStringsSep " " cfg.setOptions}
|
||||
''}
|
||||
|
||||
# Determine current fqdn hostname
|
||||
HOST=$(hostname --fqdn)
|
||||
# Alternative method of determining short and full hostname.
|
||||
HOST=${config.networking.fqdnOrHostName}
|
||||
|
||||
# Setup command line history.
|
||||
# Don't export these, otherwise other shells (bash) will try to use same HISTFILE.
|
||||
|
||||
@@ -125,9 +125,6 @@ in
|
||||
(mkRemovedOptionModule [ "programs" "yabar" ]
|
||||
"programs.yabar has been removed from NixOS. This is because the yabar repository has been archived upstream."
|
||||
)
|
||||
(mkRemovedOptionModule [ "security" "dhparams" ] ''
|
||||
The security.dhparams module has been removed as RFC 7919 has shown that generating your own params is problematic.
|
||||
'')
|
||||
(mkRemovedOptionModule [ "security" "hideProcessInformation" ] ''
|
||||
The hidepid module was removed, since the underlying machinery
|
||||
is broken when using cgroups-v2.
|
||||
|
||||
223
nixos/modules/security/dhparams.nix
Normal file
223
nixos/modules/security/dhparams.nix
Normal file
@@ -0,0 +1,223 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
options,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib) literalExpression mkOption types;
|
||||
cfg = config.security.dhparams;
|
||||
opt = options.security.dhparams;
|
||||
|
||||
bitType = types.addCheck types.int (b: b >= 16) // {
|
||||
name = "bits";
|
||||
description = "integer of at least 16 bits";
|
||||
};
|
||||
|
||||
paramsSubmodule =
|
||||
{ name, config, ... }:
|
||||
{
|
||||
options.bits = mkOption {
|
||||
type = bitType;
|
||||
default = cfg.defaultBitSize;
|
||||
defaultText = literalExpression "config.${opt.defaultBitSize}";
|
||||
description = ''
|
||||
The bit size for the prime that is used during a Diffie-Hellman
|
||||
key exchange.
|
||||
'';
|
||||
};
|
||||
|
||||
options.path = mkOption {
|
||||
type = types.path;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
The resulting path of the generated Diffie-Hellman parameters
|
||||
file for other services to reference. This could be either a
|
||||
store path or a file inside the directory specified by
|
||||
{option}`security.dhparams.path`.
|
||||
'';
|
||||
};
|
||||
|
||||
config.path =
|
||||
let
|
||||
generated = pkgs.runCommand "dhparams-${name}.pem" {
|
||||
nativeBuildInputs = [ pkgs.openssl ];
|
||||
} "openssl dhparam -out \"$out\" ${toString config.bits}";
|
||||
in
|
||||
if cfg.stateful then "${cfg.path}/${name}.pem" else generated;
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
options = {
|
||||
security.dhparams = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to generate new DH params and clean up old DH params.
|
||||
'';
|
||||
};
|
||||
|
||||
params = mkOption {
|
||||
type =
|
||||
with types;
|
||||
let
|
||||
coerce = bits: { inherit bits; };
|
||||
in
|
||||
attrsOf (coercedTo int coerce (submodule paramsSubmodule));
|
||||
default = { };
|
||||
example = lib.literalExpression "{ nginx.bits = 3072; }";
|
||||
description = ''
|
||||
Diffie-Hellman parameters to generate.
|
||||
|
||||
The value is the size (in bits) of the DH params to generate. The
|
||||
generated DH params path can be found in
|
||||
`config.security.dhparams.params.«name».path`.
|
||||
|
||||
::: {.note}
|
||||
The name of the DH params is taken as being the name of
|
||||
the service it serves and the params will be generated before the
|
||||
said service is started.
|
||||
:::
|
||||
|
||||
::: {.warning}
|
||||
If you are removing all dhparams from this list, you
|
||||
have to leave {option}`security.dhparams.enable` for at
|
||||
least one activation in order to have them be cleaned up. This also
|
||||
means if you rollback to a version without any dhparams the
|
||||
existing ones won't be cleaned up. Of course this only applies if
|
||||
{option}`security.dhparams.stateful` is
|
||||
`true`.
|
||||
:::
|
||||
|
||||
::: {.note}
|
||||
**For module implementers:** It's recommended
|
||||
to not set a specific bit size here, so that users can easily
|
||||
override this by setting
|
||||
{option}`security.dhparams.defaultBitSize`.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
stateful = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether generation of Diffie-Hellman parameters should be stateful or
|
||||
not. If this is enabled, PEM-encoded files for Diffie-Hellman
|
||||
parameters are placed in the directory specified by
|
||||
{option}`security.dhparams.path`. Otherwise the files are
|
||||
created within the Nix store.
|
||||
|
||||
::: {.note}
|
||||
If this is `false` the resulting store
|
||||
path will be non-deterministic and will be rebuilt every time the
|
||||
`openssl` package changes.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
defaultBitSize = mkOption {
|
||||
type = bitType;
|
||||
default = 2048;
|
||||
description = ''
|
||||
This allows to override the default bit size for all of the
|
||||
Diffie-Hellman parameters set in
|
||||
{option}`security.dhparams.params`.
|
||||
'';
|
||||
};
|
||||
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
default = "/var/lib/dhparams";
|
||||
description = ''
|
||||
Path to the directory in which Diffie-Hellman parameters will be
|
||||
stored. This only is relevant if
|
||||
{option}`security.dhparams.stateful` is
|
||||
`true`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
(lib.mkIf cfg.enable {
|
||||
warnings = [
|
||||
''
|
||||
The `security.dhparams` module is deprecated and scheduled for removal in NixOS 26.11.
|
||||
Generating your own params has been shown to be problematic in RFC 7919 (2016).
|
||||
|
||||
Remove any uses of DHE and migrate to ECDHE (RFC 8422, 2018) and
|
||||
Hybrid PQ (draft-ietf-tls-ecdhe-mlkem, 2026) key exchange algorithms.
|
||||
''
|
||||
];
|
||||
})
|
||||
(lib.mkIf (cfg.enable && cfg.stateful) {
|
||||
systemd.services = {
|
||||
dhparams-init = {
|
||||
description = "Clean Up Old Diffie-Hellman Parameters";
|
||||
|
||||
# Clean up even when no DH params is set
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig.RemainAfterExit = true;
|
||||
serviceConfig.Type = "oneshot";
|
||||
|
||||
script = ''
|
||||
if [ ! -d ${cfg.path} ]; then
|
||||
mkdir -p ${cfg.path}
|
||||
fi
|
||||
|
||||
# Remove old dhparams
|
||||
for file in ${cfg.path}/*; do
|
||||
if [ ! -f "$file" ]; then
|
||||
continue
|
||||
fi
|
||||
${lib.concatStrings (
|
||||
lib.mapAttrsToList (
|
||||
name:
|
||||
{ bits, path, ... }:
|
||||
''
|
||||
if [ "$file" = ${lib.escapeShellArg path} ] && \
|
||||
${pkgs.openssl}/bin/openssl dhparam -in "$file" -text \
|
||||
| head -n 1 | grep "(${toString bits} bit)" > /dev/null; then
|
||||
continue
|
||||
fi
|
||||
''
|
||||
) cfg.params
|
||||
)}
|
||||
rm "$file"
|
||||
done
|
||||
|
||||
# TODO: Ideally this would be removing the *former* cfg.path, though
|
||||
# this does not seem really important as changes to it are quite
|
||||
# unlikely
|
||||
rmdir --ignore-fail-on-non-empty ${cfg.path}
|
||||
'';
|
||||
};
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
name:
|
||||
{ bits, path, ... }:
|
||||
lib.nameValuePair "dhparams-gen-${name}" {
|
||||
description = "Generate Diffie-Hellman Parameters for ${name}";
|
||||
after = [ "dhparams-init.service" ];
|
||||
before = [ "${name}.service" ];
|
||||
requiredBy = [ "${name}.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
unitConfig.ConditionPathExists = "!${path}";
|
||||
serviceConfig.Type = "oneshot";
|
||||
script = ''
|
||||
mkdir -p ${lib.escapeShellArg cfg.path}
|
||||
${pkgs.openssl}/bin/openssl dhparam -out ${lib.escapeShellArg path} \
|
||||
${toString bits}
|
||||
'';
|
||||
}
|
||||
) cfg.params;
|
||||
})
|
||||
];
|
||||
|
||||
}
|
||||
@@ -8,21 +8,6 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
attrNames
|
||||
catAttrs
|
||||
concatLines
|
||||
concatMap
|
||||
filter
|
||||
unique
|
||||
flip
|
||||
elem
|
||||
attrValues
|
||||
concatMapStrings
|
||||
hasPrefix
|
||||
concatStringsSep
|
||||
sort
|
||||
;
|
||||
|
||||
moduleSettingsType =
|
||||
with lib.types;
|
||||
@@ -896,30 +881,41 @@ let
|
||||
|
||||
text =
|
||||
let
|
||||
ensureUniqueOrder =
|
||||
type: rules:
|
||||
let
|
||||
checkPair =
|
||||
a: b:
|
||||
assert lib.assertMsg (a.order != b.order)
|
||||
"security.pam.services.${name}.rules.${type}: rules '${a.name}' and '${b.name}' cannot have the same order value (${toString a.order})";
|
||||
b;
|
||||
checked = lib.zipListsWith checkPair rules (lib.drop 1 rules);
|
||||
in
|
||||
lib.take 1 rules ++ checked;
|
||||
# Formats a string for use in `module-arguments`. See `man pam.conf`.
|
||||
formatModuleArgument =
|
||||
token: if lib.hasInfix " " token then "[${lib.replaceStrings [ "]" ] [ "\\]" ] token}]" else token;
|
||||
|
||||
formatRules =
|
||||
type:
|
||||
concatStringsSep "\n" (
|
||||
map
|
||||
(
|
||||
rule:
|
||||
"${type} ${rule.control} ${rule.modulePath}${
|
||||
if rule.args == [ ] then "" else " " + concatStringsSep " " (map formatModuleArgument rule.args)
|
||||
} # ${rule.name} (order ${toString rule.order})"
|
||||
lib.pipe cfg.rules.${type} [
|
||||
lib.attrValues
|
||||
(lib.filter (rule: rule.enable))
|
||||
(lib.sort (a: b: a.order < b.order))
|
||||
(ensureUniqueOrder type)
|
||||
(map (
|
||||
rule:
|
||||
lib.concatStringsSep " " (
|
||||
[
|
||||
type
|
||||
rule.control
|
||||
rule.modulePath
|
||||
]
|
||||
++ map formatModuleArgument rule.args
|
||||
++ [ "# ${rule.name} (order ${toString rule.order})" ]
|
||||
)
|
||||
(
|
||||
sort (
|
||||
a: b:
|
||||
if a.order != b.order then
|
||||
a.order < b.order
|
||||
else
|
||||
throw "security.pam.services.${name}.rules.${type}: rules '${a.name}' and '${b.name}' cannot have the same order value (${toString a.order})"
|
||||
) (filter (rule: rule.enable) (attrValues cfg.rules.${type}))
|
||||
)
|
||||
);
|
||||
))
|
||||
(lib.concatStringsSep "\n")
|
||||
];
|
||||
in
|
||||
lib.mkDefault ''
|
||||
# Account management.
|
||||
@@ -2641,29 +2637,35 @@ in
|
||||
};
|
||||
|
||||
security.apparmor.includes."abstractions/pam" =
|
||||
concatMapStrings (name: "r ${config.environment.etc."pam.d/${name}".source},\n") (
|
||||
attrNames enabledServices
|
||||
lib.concatMapStrings (name: "r ${config.environment.etc."pam.d/${name}".source},\n") (
|
||||
lib.attrNames enabledServices
|
||||
)
|
||||
+ (
|
||||
let
|
||||
types = concatMap attrValues (catAttrs "rules" (attrValues enabledServices));
|
||||
rules = concatMap attrValues types;
|
||||
|
||||
isDirect = flip elem [
|
||||
"include"
|
||||
"substack"
|
||||
];
|
||||
activeRules = filter (rule: rule.enable && !isDirect rule.control) rules;
|
||||
|
||||
modulePaths = concatMap (
|
||||
with lib;
|
||||
pipe enabledServices [
|
||||
lib.attrValues
|
||||
(catAttrs "rules")
|
||||
(lib.concatMap lib.attrValues)
|
||||
(lib.concatMap lib.attrValues)
|
||||
(lib.filter (rule: rule.enable))
|
||||
(lib.filter (
|
||||
rule:
|
||||
if (!hasPrefix "/" rule.modulePath) then
|
||||
throw ''non-absolute PAM modulePath "${rule.modulePath}" is unsupported by apparmor''
|
||||
else
|
||||
[ rule.modulePath ]
|
||||
) activeRules;
|
||||
in
|
||||
concatLines (map (module: "mr ${module},") (unique modulePaths))
|
||||
!builtins.elem rule.control [
|
||||
"include"
|
||||
"substack"
|
||||
]
|
||||
))
|
||||
(lib.catAttrs "modulePath")
|
||||
(map (
|
||||
modulePath:
|
||||
lib.throwIfNot (lib.hasPrefix "/" modulePath)
|
||||
''non-absolute PAM modulePath "${modulePath}" is unsupported by apparmor''
|
||||
modulePath
|
||||
))
|
||||
lib.unique
|
||||
(map (module: "mr ${module},"))
|
||||
concatLines
|
||||
]
|
||||
);
|
||||
|
||||
security.sudo.extraConfig = optionalSudoConfigForSSHAgentAuth;
|
||||
|
||||
@@ -179,10 +179,10 @@ in
|
||||
}" />
|
||||
<!-- specify the binaries to be called -->
|
||||
<!-- the comma in front of the options is necessary for empty options -->
|
||||
<fusemount>${pkgs.fuse3}/bin/mount.fuse3 %(VOLUME) %(MNTPT) -o ,${
|
||||
<fusemount>${pkgs.fuse}/bin/mount.fuse %(VOLUME) %(MNTPT) -o ,${
|
||||
lib.concatStringsSep "," (cfg.fuseMountOptions ++ [ "%(OPTIONS)" ])
|
||||
}'</fusemount>
|
||||
<fuseumount>${pkgs.fuse3}/bin/fusermount3 -u %(MNTPT)</fuseumount>
|
||||
<fuseumount>${pkgs.fuse}/bin/fusermount -u %(MNTPT)</fuseumount>
|
||||
<!-- the comma in front of the options is necessary for empty options -->
|
||||
<cryptmount>${pkgs.pam_mount}/bin/mount.crypt -o ,${
|
||||
lib.concatStringsSep "," (cfg.cryptMountOptions ++ [ "%(OPTIONS)" ])
|
||||
|
||||
@@ -181,23 +181,8 @@ in
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
security.enableWrappers = lib.mkEnableOption "" // {
|
||||
security.enableWrappers = lib.mkEnableOption "SUID/SGID wrappers" // {
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable SUID/SGID wrappers.
|
||||
|
||||
::: {.warning}
|
||||
ONLY DISABLE THIS OPTION IF YOU KNOW WHAT YOU'RE DOING.
|
||||
:::
|
||||
|
||||
A normal interactive NixOS system requires SUID/SGID wrappers (e.g. for
|
||||
PAM and sudo). Disabling them, thus will lock you out from your system.
|
||||
|
||||
Disabling the SUID/SGID binaries is useful for non-interactive systems
|
||||
(like a firewall appliance) to minimize the attack surface. In the
|
||||
future, this might become available for interactive systems as well
|
||||
(e.g. with systemd's [run0](https://www.freedesktop.org/software/systemd/man/latest/run0)).
|
||||
'';
|
||||
};
|
||||
|
||||
security.wrappers = lib.mkOption {
|
||||
|
||||
@@ -189,15 +189,11 @@ let
|
||||
[ "--docker-image ${service.dockerImage}" ]
|
||||
++ optional service.dockerDisableCache "--docker-disable-cache"
|
||||
++ optional service.dockerPrivileged "--docker-privileged"
|
||||
++ optional service.dockerServicesPrivileged "--docker-services_privileged true"
|
||||
++ optional (service.dockerPullPolicy != null) "--docker-pull-policy ${service.dockerPullPolicy}"
|
||||
++ map (v: "--docker-volumes ${escapeShellArg v}") service.dockerVolumes
|
||||
++ map (v: "--docker-extra-hosts ${escapeShellArg v}") service.dockerExtraHosts
|
||||
++ map (v: "--docker-allowed-images ${escapeShellArg v}") service.dockerAllowedImages
|
||||
++ map (v: "--docker-allowed-services ${escapeShellArg v}") service.dockerAllowedServices
|
||||
++ map (
|
||||
v: "--docker-allowed-privileged-services ${escapeShellArg v}"
|
||||
) service.dockerAllowedPrivilegedServices
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -525,13 +521,6 @@ in
|
||||
Give extended privileges to container.
|
||||
'';
|
||||
};
|
||||
dockerServicesPrivileged = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Give extended privileges to services.
|
||||
'';
|
||||
};
|
||||
dockerExtraHosts = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
@@ -565,19 +554,6 @@ in
|
||||
Whitelist allowed services.
|
||||
'';
|
||||
};
|
||||
dockerAllowedPrivilegedServices = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"docker.io/library/docker:*-dind-rootless"
|
||||
"docker.io/library/docker:dind-rootless"
|
||||
"docker:*-dind-rootless"
|
||||
"docker:dind-rootless"
|
||||
];
|
||||
description = ''
|
||||
Whitelist allowed privileged services.
|
||||
'';
|
||||
};
|
||||
preGetSourcesScript = mkOption {
|
||||
type = types.nullOr (types.either types.str types.path);
|
||||
default = null;
|
||||
|
||||
@@ -36,8 +36,6 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
package = lib.mkPackageOption pkgs "gemstash" { };
|
||||
|
||||
settings = lib.mkOption {
|
||||
default = { };
|
||||
description = ''
|
||||
@@ -98,7 +96,7 @@ in
|
||||
after = [ "network.target" ];
|
||||
serviceConfig = lib.mkMerge [
|
||||
{
|
||||
ExecStart = "${lib.getExe cfg.package} start --no-daemonize --config-file ${settingsFormat.generate "gemstash.yaml" (prefixColon cfg.settings)}";
|
||||
ExecStart = "${pkgs.gemstash}/bin/gemstash start --no-daemonize --config-file ${settingsFormat.generate "gemstash.yaml" (prefixColon cfg.settings)}";
|
||||
NoNewPrivileges = true;
|
||||
User = "gemstash";
|
||||
Group = "gemstash";
|
||||
|
||||
@@ -26,7 +26,6 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [
|
||||
pkgs.cosmic-comp
|
||||
pkgs.cosmic-icons
|
||||
cfg.package
|
||||
];
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
config,
|
||||
options,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
@@ -8,9 +7,6 @@
|
||||
|
||||
let
|
||||
cfg = config.services.displayManager;
|
||||
opts = options.services.displayManager;
|
||||
|
||||
toPretty = lib.generators.toPretty { };
|
||||
|
||||
installedSessions =
|
||||
pkgs.runCommand "desktops"
|
||||
@@ -83,7 +79,7 @@ in
|
||||
default = config.user != null;
|
||||
defaultText = lib.literalExpression "config.${options.user} != null";
|
||||
description = ''
|
||||
Automatically log in as {option}`${options.user}`.
|
||||
Automatically log in as {option}`autoLogin.user`.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -105,7 +101,16 @@ in
|
||||
};
|
||||
|
||||
defaultSession = lib.mkOption {
|
||||
type = lib.types.nullOr (lib.types.str // { description = "session name"; });
|
||||
type = lib.types.nullOr lib.types.str // {
|
||||
description = "session name";
|
||||
check =
|
||||
d:
|
||||
lib.assertMsg (d != null -> (lib.types.str.check d && lib.elem d cfg.sessionData.sessionNames)) ''
|
||||
Default graphical session, '${d}', not found.
|
||||
Valid names for 'services.displayManager.defaultSession' are:
|
||||
${lib.concatStringsSep "\n " cfg.sessionData.sessionNames}
|
||||
'';
|
||||
};
|
||||
default = null;
|
||||
example = "gnome";
|
||||
description = ''
|
||||
@@ -125,12 +130,26 @@ in
|
||||
|
||||
sessionPackages = lib.mkOption {
|
||||
type = lib.types.listOf (
|
||||
lib.types.addCheck lib.types.package (
|
||||
p: p ? providedSessions && p.providedSessions != [ ] && lib.all lib.isString p.providedSessions
|
||||
)
|
||||
lib.types.package
|
||||
// {
|
||||
description = "package with provided sessions";
|
||||
descriptionClass = "composite";
|
||||
check =
|
||||
p:
|
||||
lib.assertMsg
|
||||
(
|
||||
lib.types.package.check p
|
||||
&& p ? providedSessions
|
||||
&& p.providedSessions != [ ]
|
||||
&& lib.all lib.isString p.providedSessions
|
||||
)
|
||||
''
|
||||
Package, '${p.name}', did not specify any session names, as strings, in
|
||||
'passthru.providedSessions'. This is required when used as a session package.
|
||||
|
||||
The session names can be looked up in:
|
||||
${p}/share/xsessions
|
||||
${p}/share/wayland-sessions
|
||||
'';
|
||||
}
|
||||
);
|
||||
default = [ ];
|
||||
@@ -189,15 +208,7 @@ in
|
||||
{
|
||||
assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null;
|
||||
message = ''
|
||||
`${opts.autoLogin}.enable` requires `${opts.autoLogin}.user` to be set
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = cfg.defaultSession == null || lib.elem cfg.defaultSession cfg.sessionData.sessionNames;
|
||||
message = ''
|
||||
Default graphical session, ${toPretty cfg.defaultSession}, not found. Definitions:${lib.options.showDefs opts.defaultSession.definitionsWithLocations}.
|
||||
Valid names for `${opts.defaultSession}` are:
|
||||
${lib.concatMapStringsSep "\n " toPretty cfg.sessionData.sessionNames}
|
||||
services.displayManager.autoLogin.enable requires services.displayManager.autoLogin.user to be set
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
@@ -455,22 +455,6 @@ in
|
||||
settings.conffile = "/etc/pam/environment";
|
||||
settings.readenv = 0;
|
||||
}
|
||||
# make sure the spawned session has the same variables as `display-manager.service`
|
||||
# https://github.com/NixOS/nixpkgs/issues/523332
|
||||
{
|
||||
name = "env-greeter";
|
||||
control = "required";
|
||||
modulePath = "${config.security.pam.package}/lib/security/pam_env.so";
|
||||
settings.conffile =
|
||||
let
|
||||
env = config.services.displayManager.generic.environment;
|
||||
in
|
||||
pkgs.writeText "gdm-launch-environment-env-conf" ''
|
||||
PATH DEFAULT="''${PATH}:${pkgs.gnome-session}/bin"
|
||||
XDG_DATA_DIRS DEFAULT="''${XDG_DATA_DIRS}:${env.XDG_DATA_DIRS}"
|
||||
'';
|
||||
settings.readenv = 0;
|
||||
}
|
||||
{
|
||||
name = "systemd";
|
||||
control = "optional";
|
||||
|
||||
@@ -30,6 +30,7 @@ let
|
||||
mapAttrsToList
|
||||
mergeAttrsList
|
||||
mkEnableOption
|
||||
mkDefault
|
||||
mkIf
|
||||
mkMerge
|
||||
mkOption
|
||||
@@ -776,25 +777,7 @@ in
|
||||
openFirewall = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to open the firewall for the specified frontend port
|
||||
|
||||
:::{.note}
|
||||
For components specific ports see {option}`services.home-assistant.openFirewallForComponents`.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewallForComponents = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to open required firewall ports for enabled components.
|
||||
|
||||
:::{.note}
|
||||
For the frontend see {option}`services.home-assistant.openFirewall`.
|
||||
:::
|
||||
'';
|
||||
description = "Whether to open the firewall for the specified port.";
|
||||
};
|
||||
|
||||
blueprints = mergeAttrsList (
|
||||
@@ -862,13 +845,7 @@ in
|
||||
}
|
||||
];
|
||||
|
||||
networking.firewall.allowedTCPPorts = mkMerge [
|
||||
(mkIf cfg.openFirewall [ cfg.config.http.server_port ])
|
||||
(mkIf cfg.openFirewallForComponents
|
||||
# https://www.home-assistant.io/integrations/sonos/#network-requirements
|
||||
(optionals (useComponent "sonos") [ 1400 ])
|
||||
)
|
||||
];
|
||||
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.config.http.server_port ];
|
||||
|
||||
# symlink the configuration to /etc/home-assistant
|
||||
environment.etc = mkMerge [
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.matterjs-server;
|
||||
in
|
||||
{
|
||||
options.services.matterjs-server = {
|
||||
enable = lib.mkEnableOption "matterjs-server, a Matter Controller WebSocket server based on Matter.js";
|
||||
|
||||
package = lib.mkPackageOption pkgs "matterjs-server" { };
|
||||
|
||||
listenAddress = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "IP address the WebSocket API binds to.";
|
||||
};
|
||||
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 5580;
|
||||
description = "TCP port the WebSocket API listens on.";
|
||||
};
|
||||
|
||||
openFirewall = lib.mkEnableOption null // {
|
||||
description = "Whether to open the WebSocket API port in the firewall.";
|
||||
};
|
||||
|
||||
bluetoothSupport = lib.mkEnableOption ''
|
||||
BLE (Bluetooth Low Energy) commissioning support. Select an adapter with
|
||||
`--bluetooth-adapter=<id>` in
|
||||
{option}`services.matterjs-server.extraArgs`
|
||||
'';
|
||||
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"--primary-interface=enp11s0"
|
||||
"--log-level=debug"
|
||||
];
|
||||
description = ''
|
||||
Additional command-line arguments passed to `matterjs-server`. See
|
||||
`matterjs-server --help` for the full list of options.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
networking.firewall = lib.mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [ cfg.port ];
|
||||
};
|
||||
|
||||
systemd.services.matterjs-server = {
|
||||
description = "Matter Controller WebSocket server based on Matter.js";
|
||||
documentation = [ "https://github.com/matter-js/matterjs-server" ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
|
||||
serviceConfig =
|
||||
let
|
||||
bluetoothCaps = [
|
||||
"CAP_NET_RAW"
|
||||
"CAP_NET_ADMIN"
|
||||
];
|
||||
in
|
||||
{
|
||||
ExecStart = lib.escapeShellArgs (
|
||||
[
|
||||
(lib.getExe cfg.package)
|
||||
"--storage-path=%S/matterjs-server"
|
||||
"--listen-address=${cfg.listenAddress}"
|
||||
"--port=${toString cfg.port}"
|
||||
"--production-mode"
|
||||
]
|
||||
++ cfg.extraArgs
|
||||
);
|
||||
|
||||
StateDirectory = "matterjs-server";
|
||||
StateDirectoryMode = "0700";
|
||||
|
||||
DynamicUser = true;
|
||||
|
||||
# Required for interaction with hci devices and bluetooth sockets
|
||||
AmbientCapabilities = lib.optionals cfg.bluetoothSupport bluetoothCaps;
|
||||
CapabilityBoundingSet = lib.optionals cfg.bluetoothSupport bluetoothCaps;
|
||||
LockPersonality = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = !cfg.bluetoothSupport; # Prevents gaining capabilities in the host namespace
|
||||
ProcSubset = "pid";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProtectSystem = "strict";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_NETLINK"
|
||||
"AF_UNIX"
|
||||
]
|
||||
++ lib.optional cfg.bluetoothSupport "AF_BLUETOOTH";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
];
|
||||
UMask = "0077";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ kranzes ];
|
||||
}
|
||||
@@ -91,9 +91,9 @@ let
|
||||
# files required to exist also won't be present, so missingok is forced.
|
||||
user=$(${pkgs.buildPackages.coreutils}/bin/id -un)
|
||||
group=$(${pkgs.buildPackages.coreutils}/bin/id -gn)
|
||||
sed -E -e "s/\bsu\s.*/su $user $group/" \
|
||||
-e "s/\b((create|createolddir)\b(\s+[0-9]+)?).*/\1 $user $group/" \
|
||||
-e "1imissingok" -e "s/\bnomissingok\b//" \
|
||||
sed -e "s/\bsu\s.*/su $user $group/" \
|
||||
-e "s/\b\(create\s\+[0-9]*\s*\|createolddir\s\+[0-9]*\s\+\).*/\1$user $group/" \
|
||||
-e "1imissingok" -e "s/\bnomissingok\b//" \
|
||||
$out > logrotate.conf
|
||||
# Since this makes for very verbose builds only show real error.
|
||||
# There is no way to control log level, but logrotate hardcodes
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
# Mautrix-Discord {#module-services-mautrix-discord}
|
||||
|
||||
*Source:* {file}`modules/services/matrix/mautrix-discord`
|
||||
|
||||
*Upstream documentation:* <https://docs.mau.fi/bridges/go/discord/index.html>
|
||||
|
||||
[Mautrix-Discord](https://github.com/mautrix/discord) is a Matrix-Discord bridge.
|
||||
|
||||
## Basic Usage {#module-services-mautrix-discord-basic-usage}
|
||||
|
||||
The common setup is to enable the bridge, point it at your homeserver, and set the permissions you want to allow:
|
||||
|
||||
1. Set `services.mautrix-discord.enable` to `true`.
|
||||
2. Set `services.mautrix-discord.settings.homeserver.address` and `services.mautrix-discord.settings.homeserver.domain`.
|
||||
3. Override `services.mautrix-discord.settings.bridge.permissions` if the default relay permissions do not fit your deployment.
|
||||
|
||||
The module provides sensible defaults for the appservice listener, registration tokens, and relay permissions.
|
||||
|
||||
### Basic Example {#module-services-mautrix-discord-basic-example}
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord = {
|
||||
enable = true;
|
||||
registerToSynapse = true;
|
||||
settings = {
|
||||
homeserver = {
|
||||
address = "http://localhost:8008";
|
||||
domain = "example.com";
|
||||
};
|
||||
bridge.permissions = {
|
||||
"example.com" = "user";
|
||||
"@admin:example.com" = "admin";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Server Defaults {#module-services-mautrix-discord-server-defaults}
|
||||
|
||||
By default, the bridge listens on `http://localhost:29334` and generates its appservice tokens automatically.
|
||||
|
||||
## Authentication {#module-services-mautrix-discord-authentication}
|
||||
|
||||
If you want to store the bridge database outside the default SQLite file, set `settings.appservice.database` to use PostgreSQL instead of SQLite:
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord.settings.appservice.database = {
|
||||
type = "postgres";
|
||||
uri = "postgresql:///mautrix-discord?host=/run/postgresql";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
If the connection needs a password, combine it with `services.mautrix-discord.environmentFile`:
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord = {
|
||||
environmentFile = "/run/secrets/mautrix-discord-env";
|
||||
settings.appservice.database.uri = "postgresql://mautrix:$DB_PASSWORD@localhost/mautrix-discord";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Use `services.mautrix-discord.environmentFile` for any secret you do not want in the Nix store.
|
||||
This includes database passwords, shared secrets, and similar values.
|
||||
|
||||
Example:
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord = {
|
||||
environmentFile = "/run/secrets/mautrix-discord-env";
|
||||
settings.bridge.login_shared_secret_map = {
|
||||
"example.com" = "$SHARED_SECRET";
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Bridge Setup {#module-services-mautrix-discord-setup}
|
||||
|
||||
After the service starts, open a chat with `@discordbot:example.com`, send `login`, and follow the instructions to link your Discord account.
|
||||
|
||||
For more detail, see the [Mautrix-Discord documentation](https://docs.mau.fi/bridges/go/discord/index.html).
|
||||
|
||||
## Advanced Configuration {#module-services-mautrix-discord-advanced}
|
||||
|
||||
The upstream default configuration is available at [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml). To print the generated default configuration from the package, run:
|
||||
|
||||
```bash
|
||||
nix-shell -p mautrix-discord --run "mautrix-discord -e"
|
||||
```
|
||||
|
||||
### Encryption {#module-services-mautrix-discord-encryption}
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord.settings.bridge.encryption = {
|
||||
allow = true;
|
||||
default = true;
|
||||
require = false;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Encryption needs additional bridge-side setup. See the [bridge encryption documentation](https://docs.mau.fi/bridges/general/end-to-bridge-encryption.html) for details.
|
||||
|
||||
### Backfill {#module-services-mautrix-discord-backfill}
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord.settings.bridge.backfill.forward_limits.initial = {
|
||||
dm = 50;
|
||||
channel = 50;
|
||||
thread = 50;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Double Puppeting {#module-services-mautrix-discord-double-puppet}
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord = {
|
||||
environmentFile = "/run/secrets/mautrix-discord-env";
|
||||
settings.bridge.login_shared_secret_map = {
|
||||
"example.com" = "$SHARED_SECRET";
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
where `/run/secrets/mautrix-discord-env` contains
|
||||
```
|
||||
SHARED_SECRET=aProtectedSecret
|
||||
```
|
||||
|
||||
## Synapse Integration {#module-services-mautrix-discord-synapse}
|
||||
|
||||
When `services.mautrix-discord.registerToSynapse` is `true`, the bridge writes its registration file automatically and Synapse picks it up.
|
||||
|
||||
If Synapse is enabled, this option defaults to `true`.
|
||||
|
||||
## Troubleshooting {#module-services-mautrix-discord-troubleshooting}
|
||||
|
||||
- View logs with `journalctl -u mautrix-discord.service -f`.
|
||||
- Check `systemctl status mautrix-discord` if the bridge does not start.
|
||||
- Verify the homeserver can reach the configured appservice address.
|
||||
- Ensure the registration file exists and Synapse can read it.
|
||||
|
||||
For more help, see the
|
||||
[Mautrix-Discord documentation](https://docs.mau.fi/bridges/go/discord/index.html)
|
||||
or the support room at [#discord:maunium.net](https://matrix.to/#/#discord:maunium.net).
|
||||
@@ -5,59 +5,15 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
defaultDataDir = "/var/lib/mautrix-discord";
|
||||
cfg = config.services.mautrix-discord;
|
||||
dataDir = cfg.dataDir;
|
||||
format = pkgs.formats.yaml { };
|
||||
serviceDependencies = [
|
||||
"mautrix-discord-registration.service"
|
||||
]
|
||||
++ (lib.lists.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit)
|
||||
++ (lib.lists.optional config.services.matrix-conduit.enable "matrix-conduit.service")
|
||||
++ (lib.lists.optional config.services.dendrite.enable "dendrite.service");
|
||||
|
||||
registrationFile = "${dataDir}/discord-registration.yaml";
|
||||
|
||||
settingsFile = "${dataDir}/config.yaml";
|
||||
settingsFileUnformatted = format.generate "discord-config-unsubstituted.yaml" cfg.settings;
|
||||
default_token = "This value is generated when generating the registration";
|
||||
settingsDefault = {
|
||||
homeserver = {
|
||||
address = "";
|
||||
domain = "";
|
||||
};
|
||||
|
||||
appservice = {
|
||||
address = "http://localhost:29334";
|
||||
hostname = "0.0.0.0";
|
||||
port = 29334;
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
uri = "file:${defaultDataDir}/mautrix-discord.db?_txlock=immediate";
|
||||
};
|
||||
id = "discord";
|
||||
bot = {
|
||||
username = "discordbot";
|
||||
displayname = "Discord bridge bot";
|
||||
avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC";
|
||||
};
|
||||
as_token = default_token;
|
||||
hs_token = default_token;
|
||||
};
|
||||
|
||||
bridge.permissions."*" = "relay";
|
||||
|
||||
logging = {
|
||||
min_level = "info";
|
||||
writers = [
|
||||
{
|
||||
type = "stdout";
|
||||
format = "pretty-colored";
|
||||
time_format = " ";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
@@ -67,14 +23,238 @@ in
|
||||
package = lib.mkPackageOption pkgs "mautrix-discord" { };
|
||||
|
||||
settings = lib.mkOption {
|
||||
apply = lib.recursiveUpdate settingsDefault;
|
||||
type = format.type;
|
||||
default = settingsDefault;
|
||||
type = lib.types.submodule {
|
||||
freeformType = format.type;
|
||||
|
||||
config = {
|
||||
_module.args = { inherit cfg lib; };
|
||||
};
|
||||
|
||||
options = {
|
||||
homeserver = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = {
|
||||
software = "standard";
|
||||
status_endpoint = null;
|
||||
message_send_checkpoint_endpoint = null;
|
||||
async_media = false;
|
||||
websocket = false;
|
||||
ping_interval_seconds = 0;
|
||||
};
|
||||
description = ''
|
||||
fullDataDiration.
|
||||
See [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml)
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
appservice = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = {
|
||||
address = "http://localhost:29334";
|
||||
hostname = "0.0.0.0";
|
||||
port = 29334;
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
uri = "file:/var/lib/mautrix-discord/mautrix-discord.db?_txlock=immediate";
|
||||
max_open_conns = 20;
|
||||
max_idle_conns = 2;
|
||||
max_conn_idle_time = null;
|
||||
max_conn_lifetime = null;
|
||||
};
|
||||
id = "discord";
|
||||
bot = {
|
||||
username = "discordbot";
|
||||
displayname = "Discord bridge bot";
|
||||
avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC";
|
||||
};
|
||||
ephemeral_events = true;
|
||||
async_transactions = false;
|
||||
as_token = "This value is generated when generating the registration";
|
||||
hs_token = "This value is generated when generating the registration";
|
||||
};
|
||||
defaultText = lib.literalExpression ''
|
||||
{
|
||||
address = "http://localhost:29334";
|
||||
hostname = "0.0.0.0";
|
||||
port = 29334;
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
uri = "file:''${config.services.mautrix-discord.dataDir}/mautrix-discord.db?_txlock=immediate";
|
||||
max_open_conns = 20;
|
||||
max_idle_conns = 2;
|
||||
max_conn_idle_time = null;
|
||||
max_conn_lifetime = null;
|
||||
};
|
||||
id = "discord";
|
||||
bot = {
|
||||
username = "discordbot";
|
||||
displayname = "Discord bridge bot";
|
||||
avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC";
|
||||
};
|
||||
ephemeral_events = true;
|
||||
async_transactions = false;
|
||||
as_token = "This value is generated when generating the registration";
|
||||
hs_token = "This value is generated when generating the registration";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Appservice configuration.
|
||||
See [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml)
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
bridge = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = {
|
||||
username_template = "discord_{{.}}";
|
||||
displayname_template = "{{if .Webhook}}Webhook{{else}}{{or .GlobalName .Username}}{{if .Bot}} (bot){{end}}{{end}}";
|
||||
channel_name_template = "{{if or (eq .Type 3) (eq .Type 4)}}{{.Name}}{{else}}#{{.Name}}{{end}}";
|
||||
guild_name_template = "{{.Name}}";
|
||||
private_chat_portal_meta = "default";
|
||||
public_address = null;
|
||||
avatar_proxy_key = "generate";
|
||||
portal_message_buffer = 128;
|
||||
startup_private_channel_create_limit = 5;
|
||||
delivery_receipts = false;
|
||||
message_status_events = false;
|
||||
message_error_notices = true;
|
||||
restricted_rooms = true;
|
||||
autojoin_thread_on_open = true;
|
||||
embed_fields_as_tables = true;
|
||||
mute_channels_on_create = false;
|
||||
sync_direct_chat_list = false;
|
||||
resend_bridge_info = false;
|
||||
custom_emoji_reactions = true;
|
||||
delete_portal_on_channel_delete = false;
|
||||
delete_guild_on_leave = true;
|
||||
federate_rooms = true;
|
||||
prefix_webhook_messages = true;
|
||||
enable_webhook_avatars = false;
|
||||
use_discord_cdn_upload = true;
|
||||
#proxy =
|
||||
cache_media = "unencrypted";
|
||||
direct_media = {
|
||||
enabled = false;
|
||||
#server_name = "discord-media.example.com";
|
||||
#well_known_response =
|
||||
allow_proxy = true;
|
||||
server_key = "generate";
|
||||
};
|
||||
animated_sticker = {
|
||||
target = "webp";
|
||||
args = {
|
||||
width = 320;
|
||||
height = 320;
|
||||
fps = 25;
|
||||
};
|
||||
};
|
||||
double_puppet_server_map = {
|
||||
#"example.com" = "https://example.com";
|
||||
};
|
||||
double_puppet_allow_discovery = false;
|
||||
login_shared_secret_map = {
|
||||
#"example.com" = "foobar";
|
||||
};
|
||||
command_prefix = "!discord";
|
||||
management_room_text = {
|
||||
welcome = "Hello, I'm a Discord bridge bot.";
|
||||
welcome_connected = "Use `help` for help.";
|
||||
welcome_unconnected = "Use `help` for help or `login` to log in.";
|
||||
additional_help = "";
|
||||
};
|
||||
backfill = {
|
||||
forward_limits = {
|
||||
initial = {
|
||||
dm = 0;
|
||||
channel = 0;
|
||||
thread = 0;
|
||||
};
|
||||
missed = {
|
||||
dm = 0;
|
||||
channel = 0;
|
||||
thread = 0;
|
||||
};
|
||||
max_guild_members = -1;
|
||||
};
|
||||
};
|
||||
encryption = {
|
||||
allow = false;
|
||||
default = false;
|
||||
appservice = false;
|
||||
msc4190 = false;
|
||||
require = false;
|
||||
allow_key_sharing = false;
|
||||
plaintext_mentions = false;
|
||||
delete_keys = {
|
||||
delete_outbound_on_ack = false;
|
||||
dont_store_outbound = false;
|
||||
ratchet_on_decrypt = false;
|
||||
delete_fully_used_on_decrypt = false;
|
||||
delete_prev_on_new_session = false;
|
||||
delete_on_device_delete = false;
|
||||
periodically_delete_expired = false;
|
||||
delete_outdated_inbound = false;
|
||||
};
|
||||
verification_levels = {
|
||||
receive = "unverified";
|
||||
send = "unverified";
|
||||
share = "cross-signed-tofu";
|
||||
};
|
||||
rotation = {
|
||||
enable_custom = false;
|
||||
milliseconds = 604800000;
|
||||
messages = 100;
|
||||
disable_device_change_key_rotation = false;
|
||||
};
|
||||
};
|
||||
provisioning = {
|
||||
prefix = "/_matrix/provision";
|
||||
shared_secret = "generate";
|
||||
debug_endpoints = false;
|
||||
};
|
||||
permissions = {
|
||||
"*" = "relay";
|
||||
#"example.com" = "user";
|
||||
#"@admin:example.com": "admin";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Bridge configuration.
|
||||
See [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml)
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
logging = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = {
|
||||
min_level = "info";
|
||||
writers = lib.singleton {
|
||||
type = "stdout";
|
||||
format = "pretty-colored";
|
||||
time_format = " ";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Logging configuration.
|
||||
See [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml)
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
homeserver = {
|
||||
address = "http://localhost:8008";
|
||||
domain = "example.com";
|
||||
domain = "public-domain.tld";
|
||||
};
|
||||
|
||||
appservice.public = {
|
||||
prefix = "/public";
|
||||
external = "https://public-appservice-address/public";
|
||||
};
|
||||
|
||||
bridge.permissions = {
|
||||
@@ -85,12 +265,8 @@ in
|
||||
'';
|
||||
description = ''
|
||||
{file}`config.yaml` configuration as a Nix attribute set.
|
||||
|
||||
Configuration options should match those described in
|
||||
[example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml).
|
||||
|
||||
Secret tokens should be specified using {option}`environmentFile`
|
||||
instead of this world-readable attribute set.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -106,9 +282,12 @@ in
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = defaultDataDir;
|
||||
defaultText = defaultDataDir;
|
||||
description = "Directory to store the bridge's data.";
|
||||
default = "/var/lib/mautrix-discord";
|
||||
defaultText = "/var/lib/mautrix-discord";
|
||||
description = ''
|
||||
Directory to store the bridge's configuration and database files.
|
||||
This directory will be created if it does not exist.
|
||||
'';
|
||||
};
|
||||
|
||||
# TODO: Get upstream to add an environment File option. Refer to https://github.com/NixOS/nixpkgs/pull/404871#issuecomment-2895663652 and https://github.com/mautrix/discord/issues/187
|
||||
@@ -116,31 +295,92 @@ in
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
File containing environment variables for secret substitution.
|
||||
Variables in the config like `$VARIABLE` will be replaced.
|
||||
File containing environment variables to substitute when copying the configuration
|
||||
out of Nix store to the `services.mautrix-discord.dataDir`.
|
||||
Can be used for storing the secrets without making them available in the Nix store.
|
||||
For example, you can set `services.mautrix-discord.settings.appservice.as_token = "$MAUTRIX_DISCORD_APPSERVICE_AS_TOKEN"`
|
||||
and then specify `MAUTRIX_DISCORD_APPSERVICE_AS_TOKEN="{token}"` in the environment file.
|
||||
This value will get substituted into the configuration file as a token.
|
||||
'';
|
||||
};
|
||||
|
||||
serviceUnit = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
readOnly = true;
|
||||
default = "mautrix-discord.service";
|
||||
description = ''
|
||||
The systemd unit (a service or a target) for other services to depend on if they
|
||||
need to be started after matrix-synapse.
|
||||
This option is useful as the actual parent unit for all matrix-synapse processes
|
||||
changes when configuring workers.
|
||||
'';
|
||||
};
|
||||
|
||||
registrationServiceUnit = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
readOnly = true;
|
||||
default = "mautrix-discord-registration.service";
|
||||
description = ''
|
||||
The registration service that generates the registration file.
|
||||
Systemd unit (a service or a target) for other services to depend on if they
|
||||
need to be started after mautrix-discord registration service.
|
||||
This option is useful as the actual parent unit for all matrix-synapse processes
|
||||
changes when configuring workers.
|
||||
'';
|
||||
};
|
||||
|
||||
serviceDependencies = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [
|
||||
cfg.registrationServiceUnit
|
||||
]
|
||||
++ (lib.lists.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit)
|
||||
++ (lib.lists.optional config.services.matrix-conduit.enable "matrix-conduit.service")
|
||||
++ (lib.lists.optional config.services.dendrite.enable "dendrite.service");
|
||||
|
||||
defaultText = ''
|
||||
[ cfg.registrationServiceUnit ] ++
|
||||
(lib.lists.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit) ++
|
||||
(lib.lists.optional config.services.matrix-conduit.enable "matrix-conduit.service") ++
|
||||
(lib.lists.optional config.services.dendrite.enable "dendrite.service");
|
||||
'';
|
||||
description = ''
|
||||
List of Systemd services to require and wait for when starting the application service.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
assertions = [
|
||||
{
|
||||
assertion =
|
||||
cfg.settings.homeserver.address or "" != "" && cfg.settings.homeserver.domain or "" != "";
|
||||
message = "services.mautrix-discord.settings.homeserver.{address,domain} must be set.";
|
||||
cfg.settings.homeserver.domain or "" != "" && cfg.settings.homeserver.address or "" != "";
|
||||
message = ''
|
||||
The options with information about the homeserver:
|
||||
`services.mautrix-discord.settings.homeserver.domain` and
|
||||
`services.mautrix-discord.settings.homeserver.address` have to be set.
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = cfg.settings.bridge.permissions or { } != { };
|
||||
message = ''
|
||||
The option `services.mautrix-discord.settings.bridge.permissions` has to be set.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
users.users.mautrix-discord = {
|
||||
isSystemUser = true;
|
||||
group = "mautrix-discord";
|
||||
extraGroups = [ "mautrix-discord-registration" ];
|
||||
home = dataDir;
|
||||
description = "Mautrix-Discord bridge user";
|
||||
};
|
||||
|
||||
users.groups.mautrix-discord = { };
|
||||
users.groups.mautrix-discord-registration = {
|
||||
members = lib.lists.optional config.services.matrix-synapse.enable "matrix-synapse";
|
||||
};
|
||||
|
||||
services.matrix-synapse = lib.mkIf cfg.registerToSynapse {
|
||||
settings.app_service_config_files = [ registrationFile ];
|
||||
@@ -152,9 +392,7 @@ in
|
||||
|
||||
systemd.services = {
|
||||
matrix-synapse = lib.mkIf cfg.registerToSynapse {
|
||||
serviceConfig.SupplementaryGroups = [
|
||||
"mautrix-discord"
|
||||
];
|
||||
serviceConfig.SupplementaryGroups = [ "mautrix-discord-registration" ];
|
||||
# Make synapse depend on the registration service when auto-registering
|
||||
wants = [ "mautrix-discord-registration.service" ];
|
||||
after = [ "mautrix-discord-registration.service" ];
|
||||
@@ -233,18 +471,15 @@ in
|
||||
'${settingsFile}' '${registrationFile}' > '${registrationFile}.tmp'
|
||||
mv '${registrationFile}.tmp' '${registrationFile}'
|
||||
|
||||
# Application services should not be rate limited by default.
|
||||
yq -Y '.rate_limited = false' '${registrationFile}' > '${registrationFile}.tmp'
|
||||
mv '${registrationFile}.tmp' '${registrationFile}'
|
||||
|
||||
umask $old_umask
|
||||
chown :mautrix-discord-registration '${registrationFile}'
|
||||
chmod 640 '${registrationFile}'
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
UMask = "027";
|
||||
UMask = 27;
|
||||
|
||||
User = "mautrix-discord";
|
||||
Group = "mautrix-discord";
|
||||
@@ -266,8 +501,8 @@ in
|
||||
description = "Mautrix-Discord, a Matrix-Discord puppeting/relaybot bridge";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ] ++ serviceDependencies;
|
||||
after = [ "network-online.target" ] ++ serviceDependencies;
|
||||
wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
|
||||
after = [ "network-online.target" ] ++ cfg.serviceDependencies;
|
||||
path = [
|
||||
pkgs.lottieconverter
|
||||
pkgs.ffmpeg-headless
|
||||
@@ -301,8 +536,6 @@ in
|
||||
ProtectHostname = true;
|
||||
ProtectClock = true;
|
||||
|
||||
UMask = "027";
|
||||
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallErrorNumber = "EPERM";
|
||||
SystemCallFilter = "@system-service";
|
||||
@@ -313,12 +546,10 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [
|
||||
mistyttm
|
||||
];
|
||||
doc = ./mautrix-discord.md;
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [
|
||||
mistyttm
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,411 +0,0 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.inventree;
|
||||
pkg = cfg.package;
|
||||
|
||||
mysqlLocal = cfg.database.createLocally && cfg.database.dbtype == "mysql";
|
||||
pgsqlLocal = cfg.database.createLocally && cfg.database.dbtype == "postgresql";
|
||||
|
||||
manage = pkgs.writeShellScriptBin "inventree-manage" ''
|
||||
set -a
|
||||
${lib.toShellVars cfg.settings}
|
||||
${lib.optionalString (
|
||||
cfg.database.passwordFile != null
|
||||
) ''INVENTREE_DB_PASSWORD="$(<${lib.escapeShellArg cfg.database.passwordFile})"''}
|
||||
set +a
|
||||
|
||||
pushd ${lib.escapeShellArg cfg.dataDir}
|
||||
expectedUser=${lib.escapeShellArg cfg.user}
|
||||
sudo=()
|
||||
if [[ "$USER" != "$expectedUser" ]]; then
|
||||
${
|
||||
if config.security.sudo.enable then
|
||||
''sudo+=(${config.security.wrapperDir}/sudo -u "$expectedUser" -E)''
|
||||
else
|
||||
''printf 'Aborting, inventree-manage must be run as user %s\n!' "$expectedUser" >&2; exit 2''
|
||||
}
|
||||
fi
|
||||
exec "''${sudo[@]}" ${cfg.package}/bin/inventree "$@"
|
||||
'';
|
||||
|
||||
in
|
||||
{
|
||||
meta.buildDocsInSandbox = false;
|
||||
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
kurogeek
|
||||
];
|
||||
|
||||
options.services.inventree = {
|
||||
enable = lib.mkEnableOption "inventree";
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/var/lib/inventree";
|
||||
description = "Inventree's data storage path. Will be `/var/lib/inventree` by default.";
|
||||
};
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
description = "Which package to use for the InvenTree instance.";
|
||||
default = pkgs.inventree;
|
||||
defaultText = lib.literalExpression "pkgs.inventree";
|
||||
};
|
||||
|
||||
adminPasswordFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = "/run/keys/inventree-password";
|
||||
description = "Path to a file containing admin password";
|
||||
};
|
||||
|
||||
secretKeyFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "${cfg.dataDir}/secret_key.txt";
|
||||
defaultText = lib.literalExpression ''"''${cfg.dataDir}/secret_key.txt"'';
|
||||
example = "/run/keys/inventree-secret-key";
|
||||
description = ''
|
||||
Path to a file containing the secret key
|
||||
'';
|
||||
};
|
||||
|
||||
database = {
|
||||
dbtype = lib.mkOption {
|
||||
type = lib.types.nullOr (
|
||||
lib.types.enum [
|
||||
"postgresql"
|
||||
"mysql"
|
||||
]
|
||||
);
|
||||
default = "postgresql";
|
||||
description = "Database type.";
|
||||
};
|
||||
dbhost = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "localhost";
|
||||
description = "Database host or socket path.";
|
||||
};
|
||||
dbport = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.port;
|
||||
default = null;
|
||||
example = 5432;
|
||||
description = "Database host port.";
|
||||
};
|
||||
dbname = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "inventree";
|
||||
description = "Database name.";
|
||||
};
|
||||
dbuser = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "inventree";
|
||||
description = "Database username.";
|
||||
};
|
||||
passwordFile = lib.mkOption {
|
||||
type = with lib.types; nullOr path;
|
||||
default = null;
|
||||
example = "/run/keys/inventree-dbpassword";
|
||||
description = ''
|
||||
A file containing the password corresponding to
|
||||
<option>database.dbuser</option>.
|
||||
'';
|
||||
};
|
||||
createLocally = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Create the database and database user locally.";
|
||||
};
|
||||
};
|
||||
|
||||
domain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "localhost";
|
||||
example = "inventree.example.com";
|
||||
description = ''
|
||||
The INVENTREE_SITE_URL option defines the base URL for the
|
||||
InvenTree server. This is a critical setting, and it is required
|
||||
for correct operation of the server. If not specified, the
|
||||
server will attempt to determine the site URL automatically -
|
||||
but this may not always be correct!
|
||||
|
||||
The site URL is the URL that users will use to access the
|
||||
InvenTree server. For example, if the server is accessible at
|
||||
`https://inventree.example.com`, the site URL should be set to
|
||||
`https://inventree.example.com`. Note that this is not
|
||||
necessarily the same as the internal URL that the server is
|
||||
running on - the internal URL will depend entirely on your
|
||||
server configuration and may be obscured by a reverse proxy or
|
||||
other such setup.
|
||||
'';
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "inventree";
|
||||
description = "User under which InvenTree runs.";
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "inventree";
|
||||
description = "Group under which InvenTree runs.";
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type =
|
||||
with lib.types;
|
||||
attrsOf (
|
||||
nullOr (oneOf [
|
||||
path
|
||||
str
|
||||
])
|
||||
);
|
||||
default = { };
|
||||
description = ''
|
||||
InvenTree config options.
|
||||
|
||||
See [the documentation](https://docs.inventree.org/en/stable/start/config/) for available options.
|
||||
'';
|
||||
example = {
|
||||
INVENTREE_CACHE_ENABLED = true;
|
||||
INVENTREE_CACHE_HOST = "localhost";
|
||||
|
||||
INVENTREE_EMAIL_HOST = "smtp.example.com";
|
||||
INVENTREE_EMAIL_PORT = 25;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
services.inventree.settings = {
|
||||
INVENTREE_DB_ENGINE = cfg.database.dbtype;
|
||||
INVENTREE_DB_NAME = cfg.database.dbname;
|
||||
INVENTREE_DB_HOST = cfg.database.dbhost;
|
||||
INVENTREE_DB_USER = cfg.database.dbuser;
|
||||
INVENTREE_DB_PORT = if cfg.database.dbport != null then toString cfg.database.dbport else null;
|
||||
|
||||
INVENTREE_CONFIG_FILE = lib.mkDefault "${cfg.dataDir}/config/config.yaml";
|
||||
INVENTREE_OIDC_PRIVATE_KEY_FILE = lib.mkDefault "${cfg.dataDir}/config/oidc_private_key.txt";
|
||||
INVENTREE_STATIC_ROOT = lib.mkDefault "${cfg.package}/lib/inventree/static";
|
||||
INVENTREE_MEDIA_ROOT = lib.mkDefault "${cfg.dataDir}/data/media";
|
||||
INVENTREE_BACKUP_DIR = lib.mkDefault "${cfg.dataDir}/data/backups";
|
||||
INVENTREE_SITE_URL = lib.mkDefault "http://${cfg.domain}";
|
||||
INVENTREE_PLUGIN_FILE = lib.mkDefault "${cfg.dataDir}/data/plugins/plugins.txt";
|
||||
INVENTREE_PLUGIN_DIR = lib.mkDefault "${cfg.dataDir}/data/plugins";
|
||||
INVENTREE_ADMIN_USER = lib.mkDefault "admin";
|
||||
INVENTREE_ADMIN_EMAIL = lib.mkDefault "admin@${cfg.domain}";
|
||||
INVENTREE_ADMIN_PASSWORD_FILE = lib.mkDefault cfg.adminPasswordFile;
|
||||
INVENTREE_SECRET_KEY_FILE = lib.mkDefault cfg.secretKeyFile;
|
||||
INVENTREE_AUTO_UPDATE = lib.mkDefault "false";
|
||||
};
|
||||
environment.systemPackages = [ manage ];
|
||||
systemd.tmpfiles.rules = (
|
||||
map (dir: "d ${dir} 0755 inventree inventree") [
|
||||
"${cfg.dataDir}"
|
||||
"${cfg.dataDir}/config"
|
||||
"${cfg.dataDir}/data"
|
||||
"${cfg.dataDir}/data/media"
|
||||
"${cfg.dataDir}/data/backups"
|
||||
"${cfg.dataDir}/data/plugins"
|
||||
]
|
||||
);
|
||||
|
||||
services.postgresql = lib.mkIf pgsqlLocal {
|
||||
enable = true;
|
||||
ensureDatabases = [ cfg.database.dbname ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = cfg.database.dbuser;
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
services.mysql = lib.mkIf mysqlLocal {
|
||||
enable = true;
|
||||
package = lib.mkDefault pkgs.mariadb;
|
||||
ensureDatabases = [ cfg.database.dbname ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = cfg.database.dbuser;
|
||||
ensurePermissions = {
|
||||
"${cfg.database.dbname}.*" = "ALL PRIVILEGES";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts.${cfg.domain} = {
|
||||
locations =
|
||||
let
|
||||
unixPath = config.systemd.sockets.inventree-server.socketConfig.ListenStream;
|
||||
in
|
||||
{
|
||||
"/" = {
|
||||
extraConfig = ''
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header CLIENT_IP $remote_addr;
|
||||
|
||||
proxy_pass_request_headers on;
|
||||
|
||||
proxy_redirect off;
|
||||
|
||||
client_max_body_size 100M;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
'';
|
||||
proxyPass = "http://unix:${unixPath}";
|
||||
};
|
||||
"/auth" = {
|
||||
extraConfig = ''
|
||||
internal;
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
proxy_set_header X-Original-URI $request_uri;
|
||||
'';
|
||||
proxyPass = "http://unix:${unixPath}:/auth/";
|
||||
};
|
||||
"/static/" = {
|
||||
alias = "${cfg.settings.INVENTREE_STATIC_ROOT}/";
|
||||
extraConfig = ''
|
||||
autoindex on;
|
||||
|
||||
# Caching settings
|
||||
expires 30d;
|
||||
add_header Pragma public;
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
};
|
||||
"/media/" = {
|
||||
alias = "${cfg.settings.INVENTREE_MEDIA_ROOT}/";
|
||||
extraConfig = ''
|
||||
auth_request /auth;
|
||||
add_header Content-disposition "attachment";
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.inventree-setup = {
|
||||
description = "Inventree setup";
|
||||
wantedBy = [ "inventree.target" ];
|
||||
partOf = [ "inventree.target" ];
|
||||
after = lib.optional mysqlLocal "mysql.service" ++ lib.optional pgsqlLocal "postgresql.target";
|
||||
requires = lib.optional mysqlLocal "mysql.service" ++ lib.optional pgsqlLocal "postgresql.target";
|
||||
before = [
|
||||
"inventree-server.service"
|
||||
"inventree-qcluster.service"
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
RemainAfterExit = true;
|
||||
PrivateTmp = true;
|
||||
}
|
||||
// lib.optionalAttrs (cfg.database.passwordFile != null) {
|
||||
LoadCredential = "db_password:${cfg.database.passwordFile}";
|
||||
};
|
||||
environment = cfg.settings;
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
umask u=rwx,g=,o=
|
||||
|
||||
${
|
||||
lib.optionalString (cfg.database.passwordFile != null) ''
|
||||
INVENTREE_DB_PASSWORD=$(<"$CREDENTIALS_DIRECTORY/db_password")
|
||||
''
|
||||
} \
|
||||
exec ${pkg}/bin/inventree migrate
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services.inventree-server = {
|
||||
description = "Inventree Gunicorn service";
|
||||
requiredBy = [ "inventree.target" ];
|
||||
partOf = [ "inventree.target" ];
|
||||
environment = cfg.settings;
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
StateDirectory = "inventree";
|
||||
PrivateTmp = true;
|
||||
}
|
||||
// lib.optionalAttrs (cfg.database.passwordFile != null) {
|
||||
LoadCredential = "db_password:${cfg.database.passwordFile}";
|
||||
};
|
||||
script = ''
|
||||
${
|
||||
lib.optionalString (cfg.database.passwordFile != null) ''
|
||||
INVENTREE_DB_PASSWORD=$(<"$CREDENTIALS_DIRECTORY/db_password")
|
||||
''
|
||||
} \
|
||||
exec ${pkg}/bin/gunicorn InvenTree.wsgi
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.sockets.inventree-server = {
|
||||
wantedBy = [ "sockets.target" ];
|
||||
partOf = [ "inventree.target" ];
|
||||
socketConfig.ListenStream = "/run/inventree/gunicorn.socket";
|
||||
};
|
||||
|
||||
systemd.services.inventree-qcluster = {
|
||||
description = "InvenTree qcluster server";
|
||||
requiredBy = [ "inventree.target" ];
|
||||
wantedBy = [ "inventree.target" ];
|
||||
partOf = [ "inventree.target" ];
|
||||
environment = cfg.settings;
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
StateDirectory = "inventree";
|
||||
PrivateTmp = true;
|
||||
}
|
||||
// lib.optionalAttrs (cfg.database.passwordFile != null) {
|
||||
LoadCredential = "db_password:${cfg.database.passwordFile}";
|
||||
};
|
||||
script = ''
|
||||
${
|
||||
lib.optionalString (cfg.database.passwordFile != null) ''
|
||||
INVENTREE_DB_PASSWORD=$(<"$CREDENTIALS_DIRECTORY/db_password")
|
||||
''
|
||||
} \
|
||||
exec ${pkg}/bin/inventree qcluster
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.targets.inventree = {
|
||||
description = "Target for all InvenTree services";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
};
|
||||
|
||||
users = lib.optionalAttrs (cfg.user == cfg.user) {
|
||||
users.${cfg.user} = {
|
||||
group = cfg.group;
|
||||
isSystemUser = true;
|
||||
home = cfg.dataDir;
|
||||
};
|
||||
groups.${cfg.group}.members = [ cfg.user ];
|
||||
};
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -14,14 +14,7 @@ let
|
||||
lib.generators.mkValueStringDefault { } (lib.head l)
|
||||
else
|
||||
lib.concatMapStrings (s: "\n ${lib.generators.mkValueStringDefault { } s}") l;
|
||||
mkKeyValue =
|
||||
key: value:
|
||||
lib.generators.mkKeyValueDefault { } ":" key (
|
||||
if builtins.isString value && lib.hasInfix "\n" value then
|
||||
"\n ${lib.replaceString "\n" "\n " value}"
|
||||
else
|
||||
value
|
||||
);
|
||||
mkKeyValue = lib.generators.mkKeyValueDefault { } ":";
|
||||
};
|
||||
firmwareSubmodule = lib.types.submodule (
|
||||
{ name, ... }@local:
|
||||
@@ -40,27 +33,11 @@ let
|
||||
'';
|
||||
serial = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
description = "Path to serial port this mcu is connected to. Derived from `service.klipper.settings` by default.";
|
||||
description = "Path to serial port this printer is connected to. Derived from `service.klipper.settings` by default.";
|
||||
defaultText = lib.literalExpression "config.services.klipper.settings.<name>.serial";
|
||||
default =
|
||||
if lib.hasAttrByPath [ "${mcu}" "serial" ] cfg.settings then cfg.settings."${mcu}".serial else null;
|
||||
};
|
||||
canbus_uuid = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = "CAN bus uuid of this mcu. Derived from `service.klipper.settings` by default.";
|
||||
defaultText = lib.literalExpression "config.services.klipper.settings.<name>.canbus_uuid";
|
||||
default =
|
||||
if lib.hasAttrByPath [ "${mcu}" "canbus_uuid" ] cfg.settings then
|
||||
cfg.settings."${mcu}".canbus_uuid
|
||||
else
|
||||
null;
|
||||
};
|
||||
canbusNetwork = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = "CAN bus network this mcu is connected to. Defaults to can0 if canbus_uuid is set.";
|
||||
defaultText = lib.literalExpression ''if canbus_uuid != null then "can0" else null'';
|
||||
default = if subcfg.canbus_uuid != null then "can0" else null;
|
||||
};
|
||||
configFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = "Path to firmware config which is generated using `klipper-genconf`";
|
||||
@@ -94,8 +71,6 @@ let
|
||||
klipper-firmware = subcfg.package;
|
||||
mcu = lib.strings.sanitizeDerivationName mcu;
|
||||
flashDevice = subcfg.serial;
|
||||
canbusDevice = subcfg.canbus_uuid;
|
||||
canbusNetwork = subcfg.canbusNetwork;
|
||||
firmwareConfig = subcfg.configFile;
|
||||
}
|
||||
else
|
||||
@@ -242,15 +217,12 @@ in
|
||||
}
|
||||
]
|
||||
++ lib.mapAttrsToList (mcu: firmware: {
|
||||
assertion =
|
||||
firmware.enableKlipperFlash -> (firmware.serial != null || firmware.canbus_uuid != null);
|
||||
assertion = firmware.enableKlipperFlash -> firmware.serial != null;
|
||||
message = ''
|
||||
Unable to determine the serial or canbus connection for services.klipper.firmwares."${mcu}". Please set one of the following:
|
||||
Unable to determine the serial connection for services.klipper.firmwares."${mcu}". Please set one of the following:
|
||||
|
||||
- services.klipper.firmwares."${mcu}".serial
|
||||
- services.klipper.firmwares."${mcu}".canbus_uuid
|
||||
- services.klipper.settings."${mcu}".serial
|
||||
- services.klipper.settings."${mcu}".canbus_uuid
|
||||
'';
|
||||
}) cfg.firmwares;
|
||||
|
||||
@@ -329,6 +301,7 @@ in
|
||||
|
||||
environment.systemPackages =
|
||||
let
|
||||
default = a: b: if a != null then a else b;
|
||||
genconf = pkgs.klipper-genconf.override {
|
||||
klipper = cfg.package;
|
||||
};
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.flap-alerted;
|
||||
|
||||
settingsArgs = lib.pipe cfg.settings [
|
||||
(lib.mapAttrsToList (
|
||||
name: value:
|
||||
if value == null || value == false then
|
||||
[ ]
|
||||
else if value == true then
|
||||
[ "-${name}" ]
|
||||
else
|
||||
[
|
||||
"-${name}"
|
||||
(toString value)
|
||||
]
|
||||
))
|
||||
lib.concatLists
|
||||
];
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ defelo ];
|
||||
|
||||
options.services.flap-alerted = {
|
||||
enable = lib.mkEnableOption "FlapAlerted";
|
||||
|
||||
package = lib.mkPackageOption pkgs "flap-alerted" { };
|
||||
|
||||
environmentFiles = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.path;
|
||||
default = [ ];
|
||||
example = [ "/run/secrets/flap-alerted.env" ];
|
||||
description = ''
|
||||
Files to load environment variables from.
|
||||
This is useful to avoid putting secrets into the nix store.
|
||||
See <https://github.com/Kioubit/FlapAlerted> for a list of options.
|
||||
'';
|
||||
};
|
||||
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = ''
|
||||
Extra command line arguments to pass to FlapAlerted.
|
||||
See <https://github.com/Kioubit/FlapAlerted> for a list of options.
|
||||
'';
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
description = ''
|
||||
Configuration of FlapAlerted.
|
||||
See <https://github.com/Kioubit/FlapAlerted> for a list of options.
|
||||
'';
|
||||
default = { };
|
||||
|
||||
type = lib.types.submodule {
|
||||
freeformType = lib.types.attrsOf (
|
||||
lib.types.nullOr (
|
||||
lib.types.oneOf [
|
||||
lib.types.str
|
||||
lib.types.int
|
||||
lib.types.bool
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
options = {
|
||||
asn = lib.mkOption {
|
||||
type = lib.types.ints.u32;
|
||||
description = "Your ASN number";
|
||||
};
|
||||
|
||||
bgpListenAddress = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Address to listen on for incoming BGP connections";
|
||||
default = ":1790";
|
||||
};
|
||||
|
||||
debug = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "Enable debug mode (produces a lot of output)";
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.flap-alerted = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
User = "flap-alerted";
|
||||
Group = "flap-alerted";
|
||||
DynamicUser = true;
|
||||
|
||||
EnvironmentFile = cfg.environmentFiles;
|
||||
|
||||
ExecStart = lib.escapeShellArgs ([ (lib.getExe cfg.package) ] ++ settingsArgs ++ cfg.extraArgs);
|
||||
|
||||
# Hardening
|
||||
AmbientCapabilities = "";
|
||||
CapabilityBoundingSet = [ "" ];
|
||||
DevicePolicy = "closed";
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = true;
|
||||
ProcSubset = "pid";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProtectSystem = "strict";
|
||||
RemoveIPC = true;
|
||||
RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
"~@resources"
|
||||
];
|
||||
UMask = "0077";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -93,7 +93,6 @@ in
|
||||
systemd.services.bird = {
|
||||
description = "BIRD Internet Routing Daemon";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
reloadTriggers = lib.optional cfg.autoReload config.environment.etc."bird/bird.conf".source;
|
||||
serviceConfig = {
|
||||
Type = "forking";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user