Compare commits
620 Commits
v0.20.2
...
bugfix/env
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1c6bb8cfc3 | ||
![]() |
9244ecacf0 | ||
![]() |
1df4afb53f | ||
![]() |
4991f0e484 | ||
![]() |
09fd7d68eb | ||
![]() |
2ace8a55c1 | ||
![]() |
861acb9467 | ||
![]() |
eea743de46 | ||
![]() |
e2b6e5a7ec | ||
![]() |
2f2dc3695c | ||
![]() |
6eb5e57199 | ||
![]() |
9a047eb95f | ||
![]() |
ef42fd7a2f | ||
![]() |
e642c2ea28 | ||
![]() |
f27d012e0c | ||
![]() |
c638311796 | ||
![]() |
2a02bea405 | ||
![]() |
219b42d991 | ||
![]() |
c290ec1f62 | ||
![]() |
e7ede86733 | ||
![]() |
e3e7609af4 | ||
![]() |
49d7ebec36 | ||
![]() |
7c3d82d819 | ||
![]() |
1c0fbec9ce | ||
![]() |
ca4d60ae25 | ||
![]() |
dc571e20d6 | ||
![]() |
1485275d0c | ||
![]() |
1afbf72037 | ||
![]() |
407fd80f95 | ||
![]() |
62525d9076 | ||
![]() |
c2371263d1 | ||
![]() |
5a870182ec | ||
![]() |
e33ad83256 | ||
![]() |
0352a1df5d | ||
![]() |
ade44bce62 | ||
![]() |
ddb29ebc34 | ||
![]() |
19a62630e5 | ||
![]() |
5626802aa0 | ||
![]() |
f68063afbc | ||
![]() |
8103d019d6 | ||
![]() |
ce89cdd9d7 | ||
![]() |
20d9b356f0 | ||
![]() |
3401438a3a | ||
![]() |
dcf1999d22 | ||
![]() |
9e3c3ae298 | ||
![]() |
40d6b84b4d | ||
![]() |
2db09f27af | ||
![]() |
6979d6a96f | ||
![]() |
deffd2acc9 | ||
![]() |
988f71f434 | ||
![]() |
4fe76f973a | ||
![]() |
8e4e6ad529 | ||
![]() |
3586a2dbe3 | ||
![]() |
4648939043 | ||
![]() |
746eaaf01a | ||
![]() |
bd2f78ae9a | ||
![]() |
a4ebe01dec | ||
![]() |
94e9e18558 | ||
![]() |
d2e0ac4d1f | ||
![]() |
36321fef1c | ||
![]() |
e879877878 | ||
![]() |
f0bce3eb25 | ||
![]() |
316bfd8b7d | ||
![]() |
92593fecd5 | ||
![]() |
8db5fecdf5 | ||
![]() |
eee696f320 | ||
![]() |
8689cf392f | ||
![]() |
15d4cce2eb | ||
![]() |
45fbb82d1a | ||
![]() |
2861c89b89 | ||
![]() |
135bfeeb27 | ||
![]() |
8fa9c66a7d | ||
![]() |
5e6174cbe2 | ||
![]() |
b4ad883b0d | ||
![]() |
a681111a23 | ||
![]() |
d2436afb66 | ||
![]() |
e43444cbb6 | ||
![]() |
8c0d947114 | ||
![]() |
5ba4a2b83a | ||
![]() |
da45073ef9 | ||
![]() |
61e17fb36d | ||
![]() |
9f13a90dd2 | ||
![]() |
ef4b35ea63 | ||
![]() |
66187c8a6e | ||
![]() |
c8d95512fc | ||
![]() |
c74fa648b9 | ||
![]() |
4cc5e9cac6 | ||
![]() |
41345d18f9 | ||
![]() |
0dd1316b68 | ||
![]() |
d8cc185e22 | ||
![]() |
061051270c | ||
![]() |
61445159db | ||
![]() |
7fa3c7f0fa | ||
![]() |
9c0fe30f42 | ||
![]() |
d00010819f | ||
![]() |
248b05b32a | ||
![]() |
8232e934e9 | ||
![]() |
9d005839af | ||
![]() |
a7e5c73608 | ||
![]() |
7896625919 | ||
![]() |
fb43cb8166 | ||
![]() |
28f68e5d11 | ||
![]() |
1199eeed0b | ||
![]() |
8ffeb4900b | ||
![]() |
456550da3f | ||
![]() |
b2676fe2dd | ||
![]() |
8561ec6249 | ||
![]() |
5b775d82ac | ||
![]() |
b43088cc16 | ||
![]() |
237eab136a | ||
![]() |
ffffa2794b | ||
![]() |
433b44403f | ||
![]() |
fa2e1c0653 | ||
![]() |
00257f6824 | ||
![]() |
3b8366f3d3 | ||
![]() |
a73f511404 | ||
![]() |
c823e01baf | ||
![]() |
4188080899 | ||
![]() |
ef6ea2c93f | ||
![]() |
3c672905d0 | ||
![]() |
ee106c747f | ||
![]() |
295726e6b8 | ||
![]() |
2654d64a3c | ||
![]() |
d91ec8500f | ||
![]() |
c354cc51d0 | ||
![]() |
d5747a61e7 | ||
![]() |
e88c747abc | ||
![]() |
cfe9e5bca4 | ||
![]() |
48f7655a62 | ||
![]() |
a1111a9858 | ||
![]() |
b8b9a798bf | ||
![]() |
7a1e94c775 | ||
![]() |
8c4b2173d2 | ||
![]() |
4c4cd7b3ea | ||
![]() |
e92554414b | ||
![]() |
d165e2c94b | ||
![]() |
a97bd31afe | ||
![]() |
d7719b26f9 | ||
![]() |
855c0fd9e0 | ||
![]() |
4156397027 | ||
![]() |
b4bbe5e305 | ||
![]() |
f5b595071e | ||
![]() |
b6f2184cce | ||
![]() |
9288067380 | ||
![]() |
ddfc43be96 | ||
![]() |
63cad5d338 | ||
![]() |
436ecdfb19 | ||
![]() |
06817600e4 | ||
![]() |
4ae1a73d54 | ||
![]() |
f29aab0d03 | ||
![]() |
cea1b3123e | ||
![]() |
b22ccf279d | ||
![]() |
81e15ce36e | ||
![]() |
8907e52933 | ||
![]() |
80cefedac5 | ||
![]() |
b85a66f77a | ||
![]() |
a0ba3d890a | ||
![]() |
315873cbd3 | ||
![]() |
e05095af90 | ||
![]() |
e0d6a73f96 | ||
![]() |
6ebfb41ad9 | ||
![]() |
d0aa01c807 | ||
![]() |
1265c7df47 | ||
![]() |
91e3f14959 | ||
![]() |
5f03eb650d | ||
![]() |
e0e6133444 | ||
![]() |
ee68baf254 | ||
![]() |
785c1a2070 | ||
![]() |
79656655ba | ||
![]() |
74921788a8 | ||
![]() |
b313b28e64 | ||
![]() |
5f1bc15e80 | ||
![]() |
fa9fb60df3 | ||
![]() |
e759e6c410 | ||
![]() |
f41446258a | ||
![]() |
268649654d | ||
![]() |
12e249f64e | ||
![]() |
c34cd76f2a | ||
![]() |
815b210fc8 | ||
![]() |
e5d5efb4c1 | ||
![]() |
0aa4b4d990 | ||
![]() |
01c1d334ae | ||
![]() |
717fc11a46 | ||
![]() |
d21c49e329 | ||
![]() |
6937d9dddc | ||
![]() |
4c2531d5fb | ||
![]() |
62fd890c52 | ||
![]() |
4772fd7723 | ||
![]() |
7c11faceb0 | ||
![]() |
053550e28a | ||
![]() |
3ed7258447 | ||
![]() |
a5cf5baa9e | ||
![]() |
ec8039cc74 | ||
![]() |
9bfa840c27 | ||
![]() |
9865f42335 | ||
![]() |
dba2829871 | ||
![]() |
8c0e1fbed9 | ||
![]() |
187488b75b | ||
![]() |
2aa35fef3e | ||
![]() |
d373fc36ae | ||
![]() |
e483762015 | ||
![]() |
5840a00000 | ||
![]() |
110f836927 | ||
![]() |
d6765f66ae | ||
![]() |
19dac780e8 | ||
![]() |
b82b549c59 | ||
![]() |
b376401ece | ||
![]() |
7d956dbe9e | ||
![]() |
6db1d84bb0 | ||
![]() |
2094fa3056 | ||
![]() |
3d255bc213 | ||
![]() |
5538dda722 | ||
![]() |
1c0d89bf25 | ||
![]() |
4cc0199fbb | ||
![]() |
edb8226fff | ||
![]() |
ef972cf642 | ||
![]() |
50c13541e4 | ||
![]() |
fd5d7cea6e | ||
![]() |
526314b275 | ||
![]() |
7b37c30019 | ||
![]() |
dc03c3ad9e | ||
![]() |
61b485f75d | ||
![]() |
e24151783f | ||
![]() |
ed9714e5ae | ||
![]() |
ea620a083c | ||
![]() |
504a8be666 | ||
![]() |
d460870c77 | ||
![]() |
f0f77251b3 | ||
![]() |
bdd454b70b | ||
![]() |
aea6662774 | ||
![]() |
fe6bcb36c7 | ||
![]() |
2474a2efe1 | ||
![]() |
4cfd49019c | ||
![]() |
7beae8af30 | ||
![]() |
22fc5d2039 | ||
![]() |
b70fc461a4 | ||
![]() |
e756436d7c | ||
![]() |
8dd87e2572 | ||
![]() |
853bf95bd2 | ||
![]() |
1c80d07fd2 | ||
![]() |
6fd8001604 | ||
![]() |
c08f9fd6fc | ||
![]() |
c3fb998414 | ||
![]() |
3368a98210 | ||
![]() |
606b7c7f16 | ||
![]() |
2f4e66be09 | ||
![]() |
9ce3e8707c | ||
![]() |
d6a96745ee | ||
![]() |
a0fcdd092b | ||
![]() |
e17d09e607 | ||
![]() |
847d67f223 | ||
![]() |
7ae0e06a62 | ||
![]() |
d3df97df8b | ||
![]() |
7d5d075809 | ||
![]() |
237a0d8999 | ||
![]() |
6952ed9950 | ||
![]() |
3e2d1bd413 | ||
![]() |
9dfba4659e | ||
![]() |
7fca252aa4 | ||
![]() |
fa23a0228f | ||
![]() |
ed76966a3a | ||
![]() |
2015a51d1a | ||
![]() |
34b8fe827e | ||
![]() |
6f1ed9b2e4 | ||
![]() |
dd00f50943 | ||
![]() |
f0ec625321 | ||
![]() |
d406c371a8 | ||
![]() |
42d374a34d | ||
![]() |
d90e4fcc3d | ||
![]() |
a44fde9dc9 | ||
![]() |
9ac8841dab | ||
![]() |
a1f87638ec | ||
![]() |
3b55e0a65d | ||
![]() |
42667fe7fa | ||
![]() |
cd27611d2f | ||
![]() |
b111d2172e | ||
![]() |
055263fa3c | ||
![]() |
f34f207bdc | ||
![]() |
0c9f0fd40d | ||
![]() |
24d5b1e645 | ||
![]() |
616f7bcaef | ||
![]() |
dace0316a2 | ||
![]() |
3bb86418b8 | ||
![]() |
6f6489a2c7 | ||
![]() |
543b697df1 | ||
![]() |
042dc2e1d8 | ||
![]() |
f745e49d9a | ||
![]() |
eda21cdfba | ||
![]() |
bc8b026072 | ||
![]() |
0f84782fcc | ||
![]() |
43b86ce282 | ||
![]() |
d30698d9a8 | ||
![]() |
8e9efa86c8 | ||
![]() |
84faf5a6cf | ||
![]() |
9428749a3c | ||
![]() |
efdac68c28 | ||
![]() |
5398c31e82 | ||
![]() |
188168c476 | ||
![]() |
4af84ac208 | ||
![]() |
deb8b51098 | ||
![]() |
0d582b2ea9 | ||
![]() |
f88b01c34b | ||
![]() |
0533c6a1b8 | ||
![]() |
f73d5c2b0e | ||
![]() |
567d0ee455 | ||
![]() |
577df6f498 | ||
![]() |
8790efbcfe | ||
![]() |
212b1edb6b | ||
![]() |
d85a27f317 | ||
![]() |
5622afbfd1 | ||
![]() |
f345038317 | ||
![]() |
e43d4cfee0 | ||
![]() |
7070658e2a | ||
![]() |
fc4b032fb4 | ||
![]() |
8c97d8ad3f | ||
![]() |
26107fe6b2 | ||
![]() |
9278c0df21 | ||
![]() |
37e95713f4 | ||
![]() |
3ae8a3a517 | ||
![]() |
031af84e90 | ||
![]() |
7d4b65491d | ||
![]() |
3038d1e7cd | ||
![]() |
b2e6ef97ce | ||
![]() |
e55236ce5b | ||
![]() |
68dfd6ba6e | ||
![]() |
38d2459f94 | ||
![]() |
e309f367af | ||
![]() |
3b59c95323 | ||
![]() |
fddaeadff8 | ||
![]() |
c85eaf9dc5 | ||
![]() |
ddec7f8aec | ||
![]() |
f057d7154b | ||
![]() |
a102950d67 | ||
![]() |
783be9b350 | ||
![]() |
27c8135207 | ||
![]() |
77ce4701b9 | ||
![]() |
73ad3f729e | ||
![]() |
1e7a64ad85 | ||
![]() |
3a5864bcdb | ||
![]() |
7e13a7dccb | ||
![]() |
e3249fa155 | ||
![]() |
0c20760576 | ||
![]() |
7ee7995493 | ||
![]() |
ba1fac1c31 | ||
![]() |
b05f0ecb6f | ||
![]() |
d5c66b75c3 | ||
![]() |
98303d6956 | ||
![]() |
4622d638a6 | ||
![]() |
02023265fc | ||
![]() |
8a075998f8 | ||
![]() |
f2f48b1872 | ||
![]() |
168d63c447 | ||
![]() |
c25d4cbc1d | ||
![]() |
ccb07538f7 | ||
![]() |
1356b13b2f | ||
![]() |
935f862863 | ||
![]() |
9f6d9df302 | ||
![]() |
65d33c02a1 | ||
![]() |
40073e7b21 | ||
![]() |
752e02e2f2 | ||
![]() |
d717b3a33f | ||
![]() |
9817f24c9a | ||
![]() |
1f7c4b0557 | ||
![]() |
6c42d2b7f7 | ||
![]() |
8df036a5a5 | ||
![]() |
582ebee74c | ||
![]() |
1017b9ddde | ||
![]() |
80ae73119d | ||
![]() |
1d88f690a4 | ||
![]() |
fbb271d804 | ||
![]() |
d6aac873b7 | ||
![]() |
ab3ffd9361 | ||
![]() |
3b9454a5cc | ||
![]() |
c8eb0f9361 | ||
![]() |
fb0f14eb06 | ||
![]() |
e489ee4e2e | ||
![]() |
fcd49f2f08 | ||
![]() |
b3268c2703 | ||
![]() |
d1bfcfafe3 | ||
![]() |
490c9f5e16 | ||
![]() |
85628d1474 | ||
![]() |
720c34d18d | ||
![]() |
cd175377ca | ||
![]() |
b91ec05e13 | ||
![]() |
3bb15f420b | ||
![]() |
124a81df5b | ||
![]() |
d9472c083d | ||
![]() |
ac2a5ef4dd | ||
![]() |
ea210a6acf | ||
![]() |
afb3bef7af | ||
![]() |
b5b5881426 | ||
![]() |
76fc7915a8 | ||
![]() |
e7798b619b | ||
![]() |
8ecef12a20 | ||
![]() |
694292ebbf | ||
![]() |
7f18f6f8a1 | ||
![]() |
0b12a480eb | ||
![]() |
2d91a79af3 | ||
![]() |
72fcee7227 | ||
![]() |
d147ef231f | ||
![]() |
1c7af83d32 | ||
![]() |
b982dfc071 | ||
![]() |
c0da8a00fc | ||
![]() |
3f18f689d8 | ||
![]() |
9dc4553cf3 | ||
![]() |
9a99c94b75 | ||
![]() |
682f0b2a54 | ||
![]() |
dbab0c1ff5 | ||
![]() |
2bf95f5340 | ||
![]() |
55561405b8 | ||
![]() |
8eef458cea | ||
![]() |
64eea9d996 | ||
![]() |
60b4e2128b | ||
![]() |
2f8cea2792 | ||
![]() |
06f9bcf734 | ||
![]() |
ee2725762f | ||
![]() |
eace0a177c | ||
![]() |
80c7d74707 | ||
![]() |
a6f5bf821d | ||
![]() |
b214406253 | ||
![]() |
5b003d80e5 | ||
![]() |
185b2d3ee7 | ||
![]() |
71bb2a1899 | ||
![]() |
785c31b730 | ||
![]() |
175da4a88a | ||
![]() |
73fc1ef11c | ||
![]() |
2d77e44f6f | ||
![]() |
033599c4cd | ||
![]() |
8096ed4b22 | ||
![]() |
b49bfe25af | ||
![]() |
8b2f34d802 | ||
![]() |
3daed0d6a7 | ||
![]() |
d6c1f75e8d | ||
![]() |
c80a4c1ddc | ||
![]() |
466abcb62d | ||
![]() |
69e99f0c16 | ||
![]() |
bbee6dfc58 | ||
![]() |
2d60cf120b | ||
![]() |
db17fc2f33 | ||
![]() |
c62080d498 | ||
![]() |
f9bbe549fa | ||
![]() |
55d7fec69c | ||
![]() |
e938907150 | ||
![]() |
0c40b86e96 | ||
![]() |
3d4cf0d8eb | ||
![]() |
966e19d278 | ||
![]() |
8f930462bd | ||
![]() |
bf4fccee15 | ||
![]() |
784771a008 | ||
![]() |
e4a9d9ae5b | ||
![]() |
a6886983dc | ||
![]() |
93a34a9635 | ||
![]() |
91a54029f9 | ||
![]() |
5400b49ed6 | ||
![]() |
c17fc3c0c1 | ||
![]() |
6f248836ea | ||
![]() |
693c1821b0 | ||
![]() |
62afe3bd5a | ||
![]() |
53a756d045 | ||
![]() |
321b687ae6 | ||
![]() |
c8617f0574 | ||
![]() |
7843e2ead0 | ||
![]() |
dca3d071d7 | ||
![]() |
436f077482 | ||
![]() |
ab3f705019 | ||
![]() |
d739989ec8 | ||
![]() |
52ee1967d6 | ||
![]() |
1af7284b5d | ||
![]() |
e1bcefd805 | ||
![]() |
2159b0183d | ||
![]() |
078fd225a9 | ||
![]() |
83974828c7 | ||
![]() |
2412f74557 | ||
![]() |
db06d3621d | ||
![]() |
c25170d2f9 | ||
![]() |
b3dfe13670 | ||
![]() |
6358e84b48 | ||
![]() |
8e634d8e49 | ||
![]() |
1a21376515 | ||
![]() |
bf45a2b6d3 | ||
![]() |
475ce955e7 | ||
![]() |
5e44289787 | ||
![]() |
e66888511f | ||
![]() |
e9e5beee1f | ||
![]() |
ffd134c09d | ||
![]() |
bfadd5c9a5 | ||
![]() |
16e9279420 | ||
![]() |
ac0903ef9f | ||
![]() |
648839dffd | ||
![]() |
489a604920 | ||
![]() |
2ac3435810 | ||
![]() |
69ea180d26 | ||
![]() |
f52f217df0 | ||
![]() |
df74aa5d7e | ||
![]() |
41932c53ae | ||
![]() |
4296db794f | ||
![]() |
9ab9302409 | ||
![]() |
0187376e54 | ||
![]() |
7340d2cb83 | ||
![]() |
641d4477d5 | ||
![]() |
3ff2fb69af | ||
![]() |
e3024b1bcb | ||
![]() |
e733b87865 | ||
![]() |
919985dc1b | ||
![]() |
d746f7d427 | ||
![]() |
b6deab515b | ||
![]() |
848220c4ba | ||
![]() |
98462bd27e | ||
![]() |
2e2515266d | ||
![]() |
776ab13276 | ||
![]() |
c2ce9a6d93 | ||
![]() |
4e3ed56dfa | ||
![]() |
dcfcc03497 | ||
![]() |
125c20bc06 | ||
![]() |
f7696a4480 | ||
![]() |
a5d7667cb6 | ||
![]() |
d45818ccff | ||
![]() |
bcb7af6eb3 | ||
![]() |
f438fb6c79 | ||
![]() |
371a8a361a | ||
![]() |
86b9ce1c88 | ||
![]() |
05232034f5 | ||
![]() |
7a3da0f606 | ||
![]() |
d96406a161 | ||
![]() |
ffa5962356 | ||
![]() |
67e74da3ba | ||
![]() |
9ee2d79de1 | ||
![]() |
79e4a13eee | ||
![]() |
4627438373 | ||
![]() |
badaaf7092 | ||
![]() |
815ac000cc | ||
![]() |
7bc5b26c52 | ||
![]() |
a0e7ca94b2 | ||
![]() |
e56c90d839 | ||
![]() |
54003d4d72 | ||
![]() |
c47b554fa1 | ||
![]() |
b027f64a7f | ||
![]() |
3765a5f7f8 | ||
![]() |
690661eadd | ||
![]() |
f7bbc326e4 | ||
![]() |
a184bfc1a6 | ||
![]() |
81634440fb | ||
![]() |
711d7683ac | ||
![]() |
967356bcf5 | ||
![]() |
c006ed034a | ||
![]() |
d065c65d94 | ||
![]() |
e23c372ff1 | ||
![]() |
25d2de5629 | ||
![]() |
d73a23ce35 | ||
![]() |
a62cb3c0f4 | ||
![]() |
177da4595e | ||
![]() |
e4f05129fe | ||
![]() |
c25b994917 | ||
![]() |
95c4c5270a | ||
![]() |
1cf6a15a08 | ||
![]() |
47d206611a | ||
![]() |
a6789cf653 | ||
![]() |
933cd858e0 | ||
![]() |
8856361076 | ||
![]() |
d826df7ef6 | ||
![]() |
d8a9b42da6 | ||
![]() |
7d926f86e8 | ||
![]() |
1579544d57 | ||
![]() |
1cee3fb4a5 | ||
![]() |
a8e2ad53dd | ||
![]() |
6821fa7246 | ||
![]() |
09c68da1bd | ||
![]() |
73064d62cf | ||
![]() |
168ed2a782 | ||
![]() |
9f60b29495 | ||
![]() |
7abcd78426 | ||
![]() |
d5295301de | ||
![]() |
beccc49b81 | ||
![]() |
037e7ffe33 | ||
![]() |
293da8ed20 | ||
![]() |
2780ab2f6c | ||
![]() |
1ed3c81b58 | ||
![]() |
50ce0a25b2 | ||
![]() |
d784227603 | ||
![]() |
ab9ed91539 | ||
![]() |
421256063e | ||
![]() |
75459bc70c | ||
![]() |
33752eabb8 | ||
![]() |
f1d1bb9167 | ||
![]() |
68eaff24b0 | ||
![]() |
862024cae1 | ||
![]() |
9d6bcd67c3 | ||
![]() |
d97ecfe147 | ||
![]() |
0d991de50a | ||
![]() |
4f278a0255 | ||
![]() |
6e72a3cff1 | ||
![]() |
1532c77ce6 | ||
![]() |
5ffbce275c | ||
![]() |
0e2ff2dddb | ||
![]() |
c0c446a095 | ||
![]() |
33dbd44449 | ||
![]() |
7b0979c1e9 | ||
![]() |
c9849dd41d | ||
![]() |
d44e97d3f2 | ||
![]() |
8713ab0f67 | ||
![]() |
6a47339bf8 | ||
![]() |
1c0fb6d641 | ||
![]() |
b45eee29eb | ||
![]() |
6d26274459 | ||
![]() |
2fb07de7bc | ||
![]() |
7678dc6b49 | ||
![]() |
1944dd55a7 | ||
![]() |
0b6c724743 | ||
![]() |
fa98023375 | ||
![]() |
e79a911bac | ||
![]() |
fd3efc71fd | ||
![]() |
0458de18de | ||
![]() |
f94ac8c770 | ||
![]() |
a03c28a916 | ||
![]() |
7b7fdf27f3 | ||
![]() |
192e564e26 | ||
![]() |
b8c5099cde | ||
![]() |
ea5bca9067 | ||
![]() |
e33eafd34f | ||
![]() |
e1344b5497 |
6
.github/workflows/audit.yaml
vendored
6
.github/workflows/audit.yaml
vendored
@@ -19,8 +19,8 @@ jobs:
|
||||
package-audits:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # @v2
|
||||
with:
|
||||
python-version: ${{inputs.python_version}}
|
||||
- name: Install Python packages
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
run: |
|
||||
. share/spack/setup-env.sh
|
||||
$(which spack) audit packages
|
||||
- uses: codecov/codecov-action@894ff025c7b54547a9a2a1e9f228beae737ad3c2 # @v2.1.0
|
||||
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # @v2.1.0
|
||||
if: ${{ inputs.with_coverage == 'true' }}
|
||||
with:
|
||||
flags: unittests,linux,audits
|
||||
|
26
.github/workflows/bootstrap.yml
vendored
26
.github/workflows/bootstrap.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
make patch unzip which xz python3 python3-devel tree \
|
||||
cmake bison bison-devel libstdc++-static
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup non-root user
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
make patch unzip xz-utils python3 python3-dev tree \
|
||||
cmake bison
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup non-root user
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
bzip2 curl file g++ gcc gfortran git gnupg2 gzip \
|
||||
make patch unzip xz-utils python3 python3-dev tree
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup non-root user
|
||||
@@ -133,7 +133,7 @@ jobs:
|
||||
make patch unzip which xz python3 python3-devel tree \
|
||||
cmake bison
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup repo
|
||||
@@ -158,7 +158,7 @@ jobs:
|
||||
run: |
|
||||
brew install cmake bison@2.7 tree
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
- name: Bootstrap clingo
|
||||
run: |
|
||||
source share/spack/setup-env.sh
|
||||
@@ -179,11 +179,11 @@ jobs:
|
||||
run: |
|
||||
brew install tree
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
- name: Bootstrap clingo
|
||||
run: |
|
||||
set -ex
|
||||
for ver in '3.7' '3.8' '3.9' '3.10' '3.11' ; do
|
||||
for ver in '3.6' '3.7' '3.8' '3.9' '3.10' ; do
|
||||
not_found=1
|
||||
ver_dir="$(find $RUNNER_TOOL_CACHE/Python -wholename "*/${ver}.*/*/bin" | grep . || true)"
|
||||
echo "Testing $ver_dir"
|
||||
@@ -204,7 +204,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup repo
|
||||
@@ -214,7 +214,7 @@ jobs:
|
||||
- name: Bootstrap clingo
|
||||
run: |
|
||||
set -ex
|
||||
for ver in '3.7' '3.8' '3.9' '3.10' '3.11' ; do
|
||||
for ver in '3.6' '3.7' '3.8' '3.9' '3.10' ; do
|
||||
not_found=1
|
||||
ver_dir="$(find $RUNNER_TOOL_CACHE/Python -wholename "*/${ver}.*/*/bin" | grep . || true)"
|
||||
echo "Testing $ver_dir"
|
||||
@@ -247,7 +247,7 @@ jobs:
|
||||
bzip2 curl file g++ gcc patchelf gfortran git gzip \
|
||||
make patch unzip xz-utils python3 python3-dev tree
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup non-root user
|
||||
@@ -283,7 +283,7 @@ jobs:
|
||||
make patch unzip xz-utils python3 python3-dev tree \
|
||||
gawk
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup non-root user
|
||||
@@ -316,7 +316,7 @@ jobs:
|
||||
# Remove GnuPG since we want to bootstrap it
|
||||
sudo rm -rf /usr/local/bin/gpg
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
- name: Bootstrap GnuPG
|
||||
run: |
|
||||
source share/spack/setup-env.sh
|
||||
@@ -333,7 +333,7 @@ jobs:
|
||||
# Remove GnuPG since we want to bootstrap it
|
||||
sudo rm -rf /usr/local/bin/gpg
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
- name: Bootstrap GnuPG
|
||||
run: |
|
||||
source share/spack/setup-env.sh
|
||||
|
14
.github/workflows/build-containers.yml
vendored
14
.github/workflows/build-containers.yml
vendored
@@ -49,14 +49,14 @@ jobs:
|
||||
[almalinux8, 'linux/amd64,linux/arm64,linux/ppc64le', 'almalinux:8'],
|
||||
[almalinux9, 'linux/amd64,linux/arm64,linux/ppc64le', 'almalinux:9'],
|
||||
[rockylinux8, 'linux/amd64,linux/arm64', 'rockylinux:8'],
|
||||
[rockylinux9, 'linux/amd64,linux/arm64,linux/ppc64le', 'rockylinux:9'],
|
||||
[rockylinux9, 'linux/amd64,linux/arm64', 'rockylinux:9'],
|
||||
[fedora37, 'linux/amd64,linux/arm64,linux/ppc64le', 'fedora:37'],
|
||||
[fedora38, 'linux/amd64,linux/arm64,linux/ppc64le', 'fedora:38']]
|
||||
name: Build ${{ matrix.dockerfile[0] }}
|
||||
if: github.repository == 'spack/spack'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
|
||||
- name: Set Container Tag Normal (Nightly)
|
||||
run: |
|
||||
@@ -92,13 +92,13 @@ jobs:
|
||||
path: dockerfiles
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # @v1
|
||||
uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # @v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # @v1
|
||||
uses: docker/setup-buildx-action@ecf95283f03858871ff00b787d79c419715afc34 # @v1
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # @v1
|
||||
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # @v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -106,13 +106,13 @@ jobs:
|
||||
|
||||
- name: Log in to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # @v1
|
||||
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # @v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build & Deploy ${{ matrix.dockerfile[0] }}
|
||||
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # @v2
|
||||
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 # @v2
|
||||
with:
|
||||
context: dockerfiles/${{ matrix.dockerfile[0] }}
|
||||
platforms: ${{ matrix.dockerfile[1] }}
|
||||
|
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
core: ${{ steps.filter.outputs.core }}
|
||||
packages: ${{ steps.filter.outputs.packages }}
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
31
.github/workflows/nightly-win-builds.yml
vendored
Normal file
31
.github/workflows/nightly-win-builds.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Windows Paraview Nightly
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # Run at 2 am
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell:
|
||||
powershell Invoke-Expression -Command "./share/spack/qa/windows_test_setup.ps1"; {0}
|
||||
|
||||
|
||||
jobs:
|
||||
build-paraview-deps:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Python packages
|
||||
run: |
|
||||
python -m pip install --upgrade pip six pywin32 setuptools coverage
|
||||
- name: Build Test
|
||||
run: |
|
||||
spack compiler find
|
||||
spack external find cmake ninja win-sdk win-wdk wgl msmpi
|
||||
spack -d install -y --cdash-upload-url https://cdash.spack.io/submit.php?project=Spack+on+Windows --cdash-track Nightly --only dependencies paraview
|
||||
exit 0
|
26
.github/workflows/unit_tests.yaml
vendored
26
.github/workflows/unit_tests.yaml
vendored
@@ -47,10 +47,10 @@ jobs:
|
||||
on_develop: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # @v2
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # @v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install System packages
|
||||
@@ -87,17 +87,17 @@ jobs:
|
||||
UNIT_TEST_COVERAGE: ${{ matrix.python-version == '3.11' }}
|
||||
run: |
|
||||
share/spack/qa/run-unit-tests
|
||||
- uses: codecov/codecov-action@894ff025c7b54547a9a2a1e9f228beae737ad3c2
|
||||
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d
|
||||
with:
|
||||
flags: unittests,linux,${{ matrix.concretizer }}
|
||||
# Test shell integration
|
||||
shell:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # @v2
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # @v2
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install System packages
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
COVERAGE: true
|
||||
run: |
|
||||
share/spack/qa/run-shell-tests
|
||||
- uses: codecov/codecov-action@894ff025c7b54547a9a2a1e9f228beae737ad3c2
|
||||
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d
|
||||
with:
|
||||
flags: shelltests,linux
|
||||
|
||||
@@ -133,7 +133,7 @@ jobs:
|
||||
dnf install -y \
|
||||
bzip2 curl file gcc-c++ gcc gcc-gfortran git gnupg2 gzip \
|
||||
make patch tcl unzip which xz
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
- name: Setup repo and non-root user
|
||||
run: |
|
||||
git --version
|
||||
@@ -152,10 +152,10 @@ jobs:
|
||||
clingo-cffi:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # @v2
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # @v2
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install System packages
|
||||
@@ -176,7 +176,7 @@ jobs:
|
||||
SPACK_TEST_SOLVER: clingo
|
||||
run: |
|
||||
share/spack/qa/run-unit-tests
|
||||
- uses: codecov/codecov-action@894ff025c7b54547a9a2a1e9f228beae737ad3c2 # @v2.1.0
|
||||
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # @v2.1.0
|
||||
with:
|
||||
flags: unittests,linux,clingo
|
||||
# Run unit tests on MacOS
|
||||
@@ -186,10 +186,10 @@ jobs:
|
||||
matrix:
|
||||
python-version: ["3.10"]
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # @v2
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # @v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install Python packages
|
||||
@@ -211,6 +211,6 @@ jobs:
|
||||
$(which spack) solve zlib
|
||||
common_args=(--dist loadfile --tx '4*popen//python=./bin/spack-tmpconfig python -u ./bin/spack python' -x)
|
||||
$(which spack) unit-test --cov --cov-config=pyproject.toml --cov-report=xml:coverage.xml "${common_args[@]}"
|
||||
- uses: codecov/codecov-action@894ff025c7b54547a9a2a1e9f228beae737ad3c2
|
||||
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d
|
||||
with:
|
||||
flags: unittests,macos
|
||||
|
13
.github/workflows/valid-style.yml
vendored
13
.github/workflows/valid-style.yml
vendored
@@ -18,8 +18,8 @@ jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # @v2
|
||||
with:
|
||||
python-version: '3.11'
|
||||
cache: 'pip'
|
||||
@@ -35,16 +35,16 @@ jobs:
|
||||
style:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # @v2
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # @v2
|
||||
with:
|
||||
python-version: '3.11'
|
||||
cache: 'pip'
|
||||
- name: Install Python packages
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip setuptools types-six black==23.1.0 mypy isort clingo flake8==6.0.0
|
||||
python3 -m pip install --upgrade pip setuptools types-six black==23.1.0 mypy isort clingo flake8
|
||||
- name: Setup git configuration
|
||||
run: |
|
||||
# Need this for the git tests to succeed.
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
dnf install -y \
|
||||
bzip2 curl file gcc-c++ gcc gcc-gfortran git gnupg2 gzip \
|
||||
make patch tcl unzip which xz
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # @v2
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v2
|
||||
- name: Setup repo and non-root user
|
||||
run: |
|
||||
git --version
|
||||
@@ -81,6 +81,7 @@ jobs:
|
||||
shell: runuser -u spack-test -- bash {0}
|
||||
run: |
|
||||
source share/spack/setup-env.sh
|
||||
spack debug report
|
||||
spack -d bootstrap now --dev
|
||||
spack style -t black
|
||||
spack unit-test -V
|
||||
|
16
.github/workflows/windows_python.yml
vendored
16
.github/workflows/windows_python.yml
vendored
@@ -15,10 +15,10 @@ jobs:
|
||||
unit-tests:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Python packages
|
||||
@@ -33,16 +33,16 @@ jobs:
|
||||
./share/spack/qa/validate_last_exit.ps1
|
||||
coverage combine -a
|
||||
coverage xml
|
||||
- uses: codecov/codecov-action@894ff025c7b54547a9a2a1e9f228beae737ad3c2
|
||||
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d
|
||||
with:
|
||||
flags: unittests,windows
|
||||
unit-tests-cmd:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Python packages
|
||||
@@ -57,16 +57,16 @@ jobs:
|
||||
./share/spack/qa/validate_last_exit.ps1
|
||||
coverage combine -a
|
||||
coverage xml
|
||||
- uses: codecov/codecov-action@894ff025c7b54547a9a2a1e9f228beae737ad3c2
|
||||
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d
|
||||
with:
|
||||
flags: unittests,windows
|
||||
build-abseil:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b
|
||||
- uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Python packages
|
||||
|
39
CHANGELOG.md
39
CHANGELOG.md
@@ -1,42 +1,3 @@
|
||||
# v0.20.2 (2023-10-03)
|
||||
|
||||
## Features in this release
|
||||
|
||||
Spack now supports Python 3.12 (#40155)
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Improve escaping in Tcl module files (#38375)
|
||||
- Make repo cache work on repositories with zero mtime (#39214)
|
||||
- Ignore errors for newer, incompatible buildcache version (#40279)
|
||||
- Print an error when git is required, but missing (#40254)
|
||||
- Ensure missing build dependencies get installed when using `spack install --overwrite` (#40252)
|
||||
- Fix an issue where Spack freezes when the build process unexpectedly exits (#39015)
|
||||
- Fix a bug where installation failures cause an unrelated `NameError` to be thrown (#39017)
|
||||
- Fix an issue where Spack package versions would be incorrectly derived from git tags (#39414)
|
||||
- Fix a bug triggered when file locking fails internally (#39188)
|
||||
- Prevent "spack external find" to error out when a directory cannot be accessed (#38755)
|
||||
- Fix multiple performance regressions in environments (#38771)
|
||||
- Add more ignored modules to `pyproject.toml` for `mypy` (#38769)
|
||||
|
||||
# v0.20.1 (2023-07-10)
|
||||
|
||||
## Spack Bugfixes
|
||||
|
||||
- Spec removed from an environment where not actually removed if `--force` was not given (#37877)
|
||||
- Speed-up module file generation (#37739)
|
||||
- Hotfix for a few recipes that treat CMake as a link dependency (#35816)
|
||||
- Fix re-running stand-alone test a second time, which was getting a trailing spurious failure (#37840)
|
||||
- Fixed reading JSON manifest on Cray, reporting non-concrete specs (#37909)
|
||||
- Fixed a few bugs when generating Dockerfiles from Spack (#37766,#37769)
|
||||
- Fixed a few long-standing bugs when generating module files (#36678,#38347,#38465,#38455)
|
||||
- Fixed issues with building Python extensions using an external Python (#38186)
|
||||
- Fixed compiler removal from command line (#38057)
|
||||
- Show external status as [e] (#33792)
|
||||
- Backported `archspec` fixes (#37793)
|
||||
- Improved a few error messages (#37791)
|
||||
|
||||
|
||||
# v0.20.0 (2023-05-21)
|
||||
|
||||
`v0.20.0` is a major feature release.
|
||||
|
@@ -143,6 +143,26 @@ The OS that are currently supported are summarized in the table below:
|
||||
* - Amazon Linux 2
|
||||
- ``amazonlinux:2``
|
||||
- ``spack/amazon-linux``
|
||||
* - AlmaLinux 8
|
||||
- ``almalinux:8``
|
||||
- ``spack/almalinux8``
|
||||
* - AlmaLinux 9
|
||||
- ``almalinux:9``
|
||||
- ``spack/almalinux9``
|
||||
* - Rocky Linux 8
|
||||
- ``rockylinux:8``
|
||||
- ``spack/rockylinux8``
|
||||
* - Rocky Linux 9
|
||||
- ``rockylinux:9``
|
||||
- ``spack/rockylinux9``
|
||||
* - Fedora Linux 37
|
||||
- ``fedora:37``
|
||||
- ``spack/fedora37``
|
||||
* - Fedora Linux 38
|
||||
- ``fedora:38``
|
||||
- ``spack/fedora38``
|
||||
|
||||
|
||||
|
||||
All the images are tagged with the corresponding release of Spack:
|
||||
|
||||
|
@@ -916,9 +916,9 @@ function, as shown in the example below:
|
||||
.. code-block:: yaml
|
||||
|
||||
projections:
|
||||
zlib: "{name}-{version}"
|
||||
^mpi: "{name}-{version}/{^mpi.name}-{^mpi.version}-{compiler.name}-{compiler.version}"
|
||||
all: "{name}-{version}/{compiler.name}-{compiler.version}"
|
||||
zlib: {name}-{version}
|
||||
^mpi: {name}-{version}/{^mpi.name}-{^mpi.version}-{compiler.name}-{compiler.version}
|
||||
all: {name}-{version}/{compiler.name}-{compiler.version}
|
||||
|
||||
The entries in the projections configuration file must all be either
|
||||
specs or the keyword ``all``. For each spec, the projection used will
|
||||
@@ -1132,11 +1132,11 @@ index once every package is pushed. Note how this target uses the generated
|
||||
example/push/%: example/install/%
|
||||
@mkdir -p $(dir $@)
|
||||
$(info About to push $(SPEC) to a buildcache)
|
||||
$(SPACK) -e . buildcache create --allow-root --only=package --directory $(BUILDCACHE_DIR) /$(HASH)
|
||||
$(SPACK) -e . buildcache push --allow-root --only=package $(BUILDCACHE_DIR) /$(HASH)
|
||||
@touch $@
|
||||
|
||||
push: $(addprefix example/push/,$(example/SPACK_PACKAGE_IDS))
|
||||
$(info Updating the buildcache index)
|
||||
$(SPACK) -e . buildcache update-index --directory $(BUILDCACHE_DIR)
|
||||
$(SPACK) -e . buildcache update-index $(BUILDCACHE_DIR)
|
||||
$(info Done!)
|
||||
@touch $@
|
||||
|
@@ -317,7 +317,7 @@ installed, but you know that new compilers have been added to your
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ module load gcc-4.9.0
|
||||
$ module load gcc/4.9.0
|
||||
$ spack compiler find
|
||||
==> Added 1 new compiler to ~/.spack/linux/compilers.yaml
|
||||
gcc@4.9.0
|
||||
|
@@ -76,6 +76,7 @@ or refer to the full manual below.
|
||||
chain
|
||||
extensions
|
||||
pipelines
|
||||
signing
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
@@ -35,27 +35,27 @@ showing lots of installed packages:
|
||||
$ module avail
|
||||
|
||||
--------------------------------------------------------------- ~/spack/share/spack/modules/linux-ubuntu14-x86_64 ---------------------------------------------------------------
|
||||
autoconf-2.69-gcc-4.8-qextxkq hwloc-1.11.6-gcc-6.3.0-akcisez m4-1.4.18-gcc-4.8-ev2znoc openblas-0.2.19-gcc-6.3.0-dhkmed6 py-setuptools-34.2.0-gcc-6.3.0-fadur4s
|
||||
automake-1.15-gcc-4.8-maqvukj isl-0.18-gcc-4.8-afi6taq m4-1.4.18-gcc-6.3.0-uppywnz openmpi-2.1.0-gcc-6.3.0-go2s4z5 py-six-1.10.0-gcc-6.3.0-p4dhkaw
|
||||
binutils-2.28-gcc-4.8-5s7c6rs libiconv-1.15-gcc-4.8-at46wg3 mawk-1.3.4-gcc-4.8-acjez57 openssl-1.0.2k-gcc-4.8-dkls5tk python-2.7.13-gcc-6.3.0-tyehea7
|
||||
bison-3.0.4-gcc-4.8-ek4luo5 libpciaccess-0.13.4-gcc-6.3.0-gmufnvh mawk-1.3.4-gcc-6.3.0-ostdoms openssl-1.0.2k-gcc-6.3.0-gxgr5or readline-7.0-gcc-4.8-xhufqhn
|
||||
bzip2-1.0.6-gcc-4.8-iffrxzn libsigsegv-2.11-gcc-4.8-pp2cvte mpc-1.0.3-gcc-4.8-g5mztc5 pcre-8.40-gcc-4.8-r5pbrxb readline-7.0-gcc-6.3.0-zzcyicg
|
||||
bzip2-1.0.6-gcc-6.3.0-bequudr libsigsegv-2.11-gcc-6.3.0-7enifnh mpfr-3.1.5-gcc-4.8-o7xm7az perl-5.24.1-gcc-4.8-dg5j65u sqlite-3.8.5-gcc-6.3.0-6zoruzj
|
||||
cmake-3.7.2-gcc-6.3.0-fowuuby libtool-2.4.6-gcc-4.8-7a523za mpich-3.2-gcc-6.3.0-dmvd3aw perl-5.24.1-gcc-6.3.0-6uzkpt6 tar-1.29-gcc-4.8-wse2ass
|
||||
curl-7.53.1-gcc-4.8-3fz46n6 libtool-2.4.6-gcc-6.3.0-n7zmbzt ncurses-6.0-gcc-4.8-dcpe7ia pkg-config-0.29.2-gcc-4.8-ib33t75 tcl-8.6.6-gcc-4.8-tfxzqbr
|
||||
expat-2.2.0-gcc-4.8-mrv6bd4 libxml2-2.9.4-gcc-4.8-ryzxnsu ncurses-6.0-gcc-6.3.0-ucbhcdy pkg-config-0.29.2-gcc-6.3.0-jpgubk3 util-macros-1.19.1-gcc-6.3.0-xorz2x2
|
||||
flex-2.6.3-gcc-4.8-yf345oo libxml2-2.9.4-gcc-6.3.0-rltzsdh netlib-lapack-3.6.1-gcc-6.3.0-js33dog py-appdirs-1.4.0-gcc-6.3.0-jxawmw7 xz-5.2.3-gcc-4.8-mew4log
|
||||
gcc-6.3.0-gcc-4.8-24puqve lmod-7.4.1-gcc-4.8-je4srhr netlib-scalapack-2.0.2-gcc-6.3.0-5aidk4l py-numpy-1.12.0-gcc-6.3.0-oemmoeu xz-5.2.3-gcc-6.3.0-3vqeuvb
|
||||
gettext-0.19.8.1-gcc-4.8-yymghlh lua-5.3.4-gcc-4.8-im75yaz netlib-scalapack-2.0.2-gcc-6.3.0-hjsemcn py-packaging-16.8-gcc-6.3.0-i2n3dtl zip-3.0-gcc-4.8-rwar22d
|
||||
gmp-6.1.2-gcc-4.8-5ub2wu5 lua-luafilesystem-1_6_3-gcc-4.8-wkey3nl netlib-scalapack-2.0.2-gcc-6.3.0-jva724b py-pyparsing-2.1.10-gcc-6.3.0-tbo6gmw zlib-1.2.11-gcc-4.8-pgxsxv7
|
||||
help2man-1.47.4-gcc-4.8-kcnqmau lua-luaposix-33.4.0-gcc-4.8-mdod2ry netlib-scalapack-2.0.2-gcc-6.3.0-rgqfr6d py-scipy-0.19.0-gcc-6.3.0-kr7nat4 zlib-1.2.11-gcc-6.3.0-7cqp6cj
|
||||
autoconf/2.69-gcc-4.8-qextxkq hwloc/1.11.6-gcc-6.3.0-akcisez m4/1.4.18-gcc-4.8-ev2znoc openblas/0.2.19-gcc-6.3.0-dhkmed6 py-setuptools/34.2.0-gcc-6.3.0-fadur4s
|
||||
automake/1.15-gcc-4.8-maqvukj isl/0.18-gcc-4.8-afi6taq m4/1.4.18-gcc-6.3.0-uppywnz openmpi/2.1.0-gcc-6.3.0-go2s4z5 py-six/1.10.0-gcc-6.3.0-p4dhkaw
|
||||
binutils/2.28-gcc-4.8-5s7c6rs libiconv/1.15-gcc-4.8-at46wg3 mawk/1.3.4-gcc-4.8-acjez57 openssl/1.0.2k-gcc-4.8-dkls5tk python/2.7.13-gcc-6.3.0-tyehea7
|
||||
bison/3.0.4-gcc-4.8-ek4luo5 libpciaccess/0.13.4-gcc-6.3.0-gmufnvh mawk/1.3.4-gcc-6.3.0-ostdoms openssl/1.0.2k-gcc-6.3.0-gxgr5or readline/7.0-gcc-4.8-xhufqhn
|
||||
bzip2/1.0.6-gcc-4.8-iffrxzn libsigsegv/2.11-gcc-4.8-pp2cvte mpc/1.0.3-gcc-4.8-g5mztc5 pcre/8.40-gcc-4.8-r5pbrxb readline/7.0-gcc-6.3.0-zzcyicg
|
||||
bzip2/1.0.6-gcc-6.3.0-bequudr libsigsegv/2.11-gcc-6.3.0-7enifnh mpfr/3.1.5-gcc-4.8-o7xm7az perl/5.24.1-gcc-4.8-dg5j65u sqlite/3.8.5-gcc-6.3.0-6zoruzj
|
||||
cmake/3.7.2-gcc-6.3.0-fowuuby libtool/2.4.6-gcc-4.8-7a523za mpich/3.2-gcc-6.3.0-dmvd3aw perl/5.24.1-gcc-6.3.0-6uzkpt6 tar/1.29-gcc-4.8-wse2ass
|
||||
curl/7.53.1-gcc-4.8-3fz46n6 libtool/2.4.6-gcc-6.3.0-n7zmbzt ncurses/6.0-gcc-4.8-dcpe7ia pkg-config/0.29.2-gcc-4.8-ib33t75 tcl/8.6.6-gcc-4.8-tfxzqbr
|
||||
expat/2.2.0-gcc-4.8-mrv6bd4 libxml2/2.9.4-gcc-4.8-ryzxnsu ncurses/6.0-gcc-6.3.0-ucbhcdy pkg-config/0.29.2-gcc-6.3.0-jpgubk3 util-macros/1.19.1-gcc-6.3.0-xorz2x2
|
||||
flex/2.6.3-gcc-4.8-yf345oo libxml2/2.9.4-gcc-6.3.0-rltzsdh netlib-lapack/3.6.1-gcc-6.3.0-js33dog py-appdirs/1.4.0-gcc-6.3.0-jxawmw7 xz/5.2.3-gcc-4.8-mew4log
|
||||
gcc/6.3.0-gcc-4.8-24puqve lmod/7.4.1-gcc-4.8-je4srhr netlib-scalapack/2.0.2-gcc-6.3.0-5aidk4l py-numpy/1.12.0-gcc-6.3.0-oemmoeu xz/5.2.3-gcc-6.3.0-3vqeuvb
|
||||
gettext/0.19.8.1-gcc-4.8-yymghlh lua/5.3.4-gcc-4.8-im75yaz netlib-scalapack/2.0.2-gcc-6.3.0-hjsemcn py-packaging/16.8-gcc-6.3.0-i2n3dtl zip/3.0-gcc-4.8-rwar22d
|
||||
gmp/6.1.2-gcc-4.8-5ub2wu5 lua-luafilesystem/1_6_3-gcc-4.8-wkey3nl netlib-scalapack/2.0.2-gcc-6.3.0-jva724b py-pyparsing/2.1.10-gcc-6.3.0-tbo6gmw zlib/1.2.11-gcc-4.8-pgxsxv7
|
||||
help2man/1.47.4-gcc-4.8-kcnqmau lua-luaposix/33.4.0-gcc-4.8-mdod2ry netlib-scalapack/2.0.2-gcc-6.3.0-rgqfr6d py-scipy/0.19.0-gcc-6.3.0-kr7nat4 zlib/1.2.11-gcc-6.3.0-7cqp6cj
|
||||
|
||||
The names should look familiar, as they resemble the output from ``spack find``.
|
||||
For example, you could type the following command to load the ``cmake`` module:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ module load cmake-3.7.2-gcc-6.3.0-fowuuby
|
||||
$ module load cmake/3.7.2-gcc-6.3.0-fowuuby
|
||||
|
||||
Neither of these is particularly pretty, easy to remember, or easy to
|
||||
type. Luckily, Spack offers many facilities for customizing the module
|
||||
@@ -779,35 +779,35 @@ cut-and-pasted into a shell script. For example:
|
||||
|
||||
$ spack module tcl loads --dependencies py-numpy git
|
||||
# bzip2@1.0.6%gcc@4.9.3=linux-x86_64
|
||||
module load bzip2-1.0.6-gcc-4.9.3-ktnrhkrmbbtlvnagfatrarzjojmkvzsx
|
||||
module load bzip2/1.0.6-gcc-4.9.3-ktnrhkrmbbtlvnagfatrarzjojmkvzsx
|
||||
# ncurses@6.0%gcc@4.9.3=linux-x86_64
|
||||
module load ncurses-6.0-gcc-4.9.3-kaazyneh3bjkfnalunchyqtygoe2mncv
|
||||
module load ncurses/6.0-gcc-4.9.3-kaazyneh3bjkfnalunchyqtygoe2mncv
|
||||
# zlib@1.2.8%gcc@4.9.3=linux-x86_64
|
||||
module load zlib-1.2.8-gcc-4.9.3-v3ufwaahjnviyvgjcelo36nywx2ufj7z
|
||||
module load zlib/1.2.8-gcc-4.9.3-v3ufwaahjnviyvgjcelo36nywx2ufj7z
|
||||
# sqlite@3.8.5%gcc@4.9.3=linux-x86_64
|
||||
module load sqlite-3.8.5-gcc-4.9.3-a3eediswgd5f3rmto7g3szoew5nhehbr
|
||||
module load sqlite/3.8.5-gcc-4.9.3-a3eediswgd5f3rmto7g3szoew5nhehbr
|
||||
# readline@6.3%gcc@4.9.3=linux-x86_64
|
||||
module load readline-6.3-gcc-4.9.3-se6r3lsycrwxyhreg4lqirp6xixxejh3
|
||||
module load readline/6.3-gcc-4.9.3-se6r3lsycrwxyhreg4lqirp6xixxejh3
|
||||
# python@3.5.1%gcc@4.9.3=linux-x86_64
|
||||
module load python-3.5.1-gcc-4.9.3-5q5rsrtjld4u6jiicuvtnx52m7tfhegi
|
||||
module load python/3.5.1-gcc-4.9.3-5q5rsrtjld4u6jiicuvtnx52m7tfhegi
|
||||
# py-setuptools@20.5%gcc@4.9.3=linux-x86_64
|
||||
module load py-setuptools-20.5-gcc-4.9.3-4qr2suj6p6glepnedmwhl4f62x64wxw2
|
||||
module load py-setuptools/20.5-gcc-4.9.3-4qr2suj6p6glepnedmwhl4f62x64wxw2
|
||||
# py-nose@1.3.7%gcc@4.9.3=linux-x86_64
|
||||
module load py-nose-1.3.7-gcc-4.9.3-pwhtjw2dvdvfzjwuuztkzr7b4l6zepli
|
||||
module load py-nose/1.3.7-gcc-4.9.3-pwhtjw2dvdvfzjwuuztkzr7b4l6zepli
|
||||
# openblas@0.2.17%gcc@4.9.3+shared=linux-x86_64
|
||||
module load openblas-0.2.17-gcc-4.9.3-pw6rmlom7apfsnjtzfttyayzc7nx5e7y
|
||||
module load openblas/0.2.17-gcc-4.9.3-pw6rmlom7apfsnjtzfttyayzc7nx5e7y
|
||||
# py-numpy@1.11.0%gcc@4.9.3+blas+lapack=linux-x86_64
|
||||
module load py-numpy-1.11.0-gcc-4.9.3-mulodttw5pcyjufva4htsktwty4qd52r
|
||||
module load py-numpy/1.11.0-gcc-4.9.3-mulodttw5pcyjufva4htsktwty4qd52r
|
||||
# curl@7.47.1%gcc@4.9.3=linux-x86_64
|
||||
module load curl-7.47.1-gcc-4.9.3-ohz3fwsepm3b462p5lnaquv7op7naqbi
|
||||
module load curl/7.47.1-gcc-4.9.3-ohz3fwsepm3b462p5lnaquv7op7naqbi
|
||||
# autoconf@2.69%gcc@4.9.3=linux-x86_64
|
||||
module load autoconf-2.69-gcc-4.9.3-bkibjqhgqm5e3o423ogfv2y3o6h2uoq4
|
||||
module load autoconf/2.69-gcc-4.9.3-bkibjqhgqm5e3o423ogfv2y3o6h2uoq4
|
||||
# cmake@3.5.0%gcc@4.9.3~doc+ncurses+openssl~qt=linux-x86_64
|
||||
module load cmake-3.5.0-gcc-4.9.3-x7xnsklmgwla3ubfgzppamtbqk5rwn7t
|
||||
module load cmake/3.5.0-gcc-4.9.3-x7xnsklmgwla3ubfgzppamtbqk5rwn7t
|
||||
# expat@2.1.0%gcc@4.9.3=linux-x86_64
|
||||
module load expat-2.1.0-gcc-4.9.3-6pkz2ucnk2e62imwakejjvbv6egncppd
|
||||
module load expat/2.1.0-gcc-4.9.3-6pkz2ucnk2e62imwakejjvbv6egncppd
|
||||
# git@2.8.0-rc2%gcc@4.9.3+curl+expat=linux-x86_64
|
||||
module load git-2.8.0-rc2-gcc-4.9.3-3bib4hqtnv5xjjoq5ugt3inblt4xrgkd
|
||||
module load git/2.8.0-rc2-gcc-4.9.3-3bib4hqtnv5xjjoq5ugt3inblt4xrgkd
|
||||
|
||||
The script may be further edited by removing unnecessary modules.
|
||||
|
||||
@@ -826,12 +826,12 @@ For example, consider the following on one system:
|
||||
.. code-block:: console
|
||||
|
||||
$ module avail
|
||||
linux-SuSE11-x86_64/antlr-2.7.7-gcc-5.3.0-bdpl46y
|
||||
linux-SuSE11-x86_64/antlr/2.7.7-gcc-5.3.0-bdpl46y
|
||||
|
||||
$ spack module tcl loads antlr # WRONG!
|
||||
# antlr@2.7.7%gcc@5.3.0~csharp+cxx~java~python arch=linux-SuSE11-x86_64
|
||||
module load antlr-2.7.7-gcc-5.3.0-bdpl46y
|
||||
module load antlr/2.7.7-gcc-5.3.0-bdpl46y
|
||||
|
||||
$ spack module tcl loads --prefix linux-SuSE11-x86_64/ antlr
|
||||
# antlr@2.7.7%gcc@5.3.0~csharp+cxx~java~python arch=linux-SuSE11-x86_64
|
||||
module load linux-SuSE11-x86_64/antlr-2.7.7-gcc-5.3.0-bdpl46y
|
||||
module load linux-SuSE11-x86_64/antlr/2.7.7-gcc-5.3.0-bdpl46y
|
||||
|
@@ -3071,7 +3071,7 @@ follows:
|
||||
# The library provided by the bar virtual package
|
||||
@property
|
||||
def bar_libs(self):
|
||||
return find_libraries("libFooBar", root=sef.home, recursive=True)
|
||||
return find_libraries("libFooBar", root=self.home, recursive=True)
|
||||
|
||||
# The baz virtual package home
|
||||
@property
|
||||
|
@@ -1,8 +1,8 @@
|
||||
sphinx==6.2.1
|
||||
sphinxcontrib-programoutput==0.17
|
||||
sphinx_design==0.4.1
|
||||
sphinx-rtd-theme==1.2.1
|
||||
python-levenshtein==0.21.0
|
||||
sphinx-rtd-theme==1.2.2
|
||||
python-levenshtein==0.21.1
|
||||
docutils==0.18.1
|
||||
pygments==2.15.1
|
||||
urllib3==2.0.2
|
||||
urllib3==2.0.3
|
||||
|
484
lib/spack/docs/signing.rst
Normal file
484
lib/spack/docs/signing.rst
Normal file
@@ -0,0 +1,484 @@
|
||||
.. Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
|
||||
Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
|
||||
SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
.. _signing:
|
||||
|
||||
=====================
|
||||
Spack Package Signing
|
||||
=====================
|
||||
|
||||
The goal of package signing in Spack is to provide data integrity
|
||||
assurances around official packages produced by the automated Spack CI
|
||||
pipelines. These assurances directly address the security of Spack’s
|
||||
software supply chain by explaining why a security-conscious user can
|
||||
be reasonably justified in the belief that packages installed via Spack
|
||||
have an uninterrupted auditable trail back to change management
|
||||
decisions judged to be appropriate by the Spack maintainers. This is
|
||||
achieved through cryptographic signing of packages built by Spack CI
|
||||
pipelines based on code that has been transparently reviewed and
|
||||
approved on GitHub. This document describes the signing process for
|
||||
interested users.
|
||||
|
||||
.. _risks:
|
||||
|
||||
------------------------------
|
||||
Risks, Impact and Threat Model
|
||||
------------------------------
|
||||
|
||||
This document addresses the approach taken to safeguard Spack’s
|
||||
reputation with regard to the integrity of the package data produced by
|
||||
Spack’s CI pipelines. It does not address issues of data confidentiality
|
||||
(Spack is intended to be largely open source) or availability (efforts
|
||||
are described elsewhere). With that said the main reputational risk can
|
||||
be broadly categorized as a loss of faith in the data integrity due to a
|
||||
breach of the private key used to sign packages. Remediation of a
|
||||
private key breach would require republishing the public key with a
|
||||
revocation certificate, generating a new signing key, an assessment and
|
||||
potential rebuild/resigning of all packages since the key was breached,
|
||||
and finally direct intervention by every spack user to update their copy
|
||||
of Spack’s public keys used for local verification.
|
||||
|
||||
The primary threat model used in mitigating the risks of these stated
|
||||
impacts is one of individual error not malicious intent or insider
|
||||
threat. The primary objective is to avoid the above impacts by making a
|
||||
private key breach nearly impossible due to oversight or configuration
|
||||
error. Obvious and straightforward measures are taken to mitigate issues
|
||||
of malicious interference in data integrity and insider threats but
|
||||
these attack vectors are not systematically addressed. It should be hard
|
||||
to exfiltrate the private key intentionally, and almost impossible to
|
||||
leak the key by accident.
|
||||
|
||||
.. _overview:
|
||||
|
||||
-----------------
|
||||
Pipeline Overview
|
||||
-----------------
|
||||
|
||||
Spack pipelines build software through progressive stages where packages
|
||||
in later stages nominally depend on packages built in earlier stages.
|
||||
For both technical and design reasons these dependencies are not
|
||||
implemented through the default GitLab artifacts mechanism; instead
|
||||
built packages are uploaded to AWS S3 mirrors (buckets) where they are
|
||||
retrieved by subsequent stages in the pipeline. Two broad categories of
|
||||
pipelines exist: Pull Request (PR) pipelines and Develop/Release
|
||||
pipelines.
|
||||
|
||||
- PR pipelines are launched in response to pull requests made by
|
||||
trusted and untrusted users. Packages built on these pipelines upload
|
||||
code to quarantined AWS S3 locations which cache the built packages
|
||||
for the purposes of review and iteration on the changes proposed in
|
||||
the pull request. Packages built on PR pipelines can come from
|
||||
untrusted users so signing of these pipelines is not implemented.
|
||||
Jobs in these pipelines are executed via normal GitLab runners both
|
||||
within the AWS GitLab infrastructure and at affiliated institutions.
|
||||
- Develop and Release pipelines **sign** the packages they produce and carry
|
||||
strong integrity assurances that trace back to auditable change management
|
||||
decisions. These pipelines only run after members from a trusted group of
|
||||
reviewers verify that the proposed changes in a pull request are appropriate.
|
||||
Once the PR is merged, or a release is cut, a pipeline is run on protected
|
||||
GitLab runners which provide access to the required signing keys within the
|
||||
job. Intermediary keys are used to sign packages in each stage of the
|
||||
pipeline as they are built and a final job officially signs each package
|
||||
external to any specific packages’ build environment. An intermediate key
|
||||
exists in the AWS infrastructure and for each affiliated instritution that
|
||||
maintains protected runners. The runners that execute these pipelines
|
||||
exclusively accept jobs from protected branches meaning the intermediate keys
|
||||
are never exposed to unreviewed code and the official keys are never exposed
|
||||
to any specific build environment.
|
||||
|
||||
.. _key_architecture:
|
||||
|
||||
----------------
|
||||
Key Architecture
|
||||
----------------
|
||||
|
||||
Spack’s CI process uses public-key infrastructure (PKI) based on GNU Privacy
|
||||
Guard (gpg) keypairs to sign public releases of spack package metadata, also
|
||||
called specs. Two classes of GPG keys are involved in the process to reduce the
|
||||
impact of an individual private key compromise, these key classes are the
|
||||
*Intermediate CI Key* and *Reputational Key*. Each of these keys has signing
|
||||
sub-keys that are used exclusively for signing packages. This can be confusing
|
||||
so for the purpose of this explanation we’ll refer to Root and Signing keys.
|
||||
Each key has a private and a public component as well as one or more identities
|
||||
and zero or more signatures.
|
||||
|
||||
-------------------
|
||||
Intermediate CI Key
|
||||
-------------------
|
||||
|
||||
The Intermediate key class is used to sign and verify packages between stages
|
||||
within a develop or release pipeline. An intermediate key exists for the AWS
|
||||
infrastructure as well as each affiliated institution that maintains protected
|
||||
runners. These intermediate keys are made available to the GitLab execution
|
||||
environment building the package so that the package’s dependencies may be
|
||||
verified by the Signing Intermediate CI Public Key and the final package may be
|
||||
signed by the Signing Intermediate CI Private Key.
|
||||
|
||||
|
||||
+---------------------------------------------------------------------------------------------------------+
|
||||
| **Intermediate CI Key (GPG)** |
|
||||
+==================================================+======================================================+
|
||||
| Root Intermediate CI Private Key (RSA 4096)# | Root Intermediate CI Public Key (RSA 4096) |
|
||||
+--------------------------------------------------+------------------------------------------------------+
|
||||
| Signing Intermediate CI Private Key (RSA 4096) | Signing Intermediate CI Public Key (RSA 4096) |
|
||||
+--------------------------------------------------+------------------------------------------------------+
|
||||
| Identity: “Intermediate CI Key <maintainers@spack.io>” |
|
||||
+---------------------------------------------------------------------------------------------------------+
|
||||
| Signatures: None |
|
||||
+---------------------------------------------------------------------------------------------------------+
|
||||
|
||||
|
||||
The *Root intermediate CI Private Key*\ Is stripped out of the GPG key and
|
||||
stored offline completely separate from Spack’s infrastructure. This allows the
|
||||
core development team to append revocation certificates to the GPG key and
|
||||
issue new sub-keys for use in the pipeline. It is our expectation that this
|
||||
will happen on a semi regular basis. A corollary of this is that *this key
|
||||
should not be used to verify package integrity outside the internal CI process.*
|
||||
|
||||
----------------
|
||||
Reputational Key
|
||||
----------------
|
||||
|
||||
The Reputational Key is the public facing key used to sign complete groups of
|
||||
development and release packages. Only one key pair exsits in this class of
|
||||
keys. In contrast to the Intermediate CI Key the Reputational Key *should* be
|
||||
used to verify package integrity. At the end of develop and release pipeline a
|
||||
final pipeline job pulls down all signed package metadata built by the pipeline,
|
||||
verifies they were signed with an Intermediate CI Key, then strips the
|
||||
Intermediate CI Key signature from the package and re-signs them with the
|
||||
Signing Reputational Private Key. The officially signed packages are then
|
||||
uploaded back to the AWS S3 mirror. Please note that separating use of the
|
||||
reputational key into this final job is done to prevent leakage of the key in a
|
||||
spack package. Because the Signing Reputational Private Key is never exposed to
|
||||
a build job it cannot accidentally end up in any built package.
|
||||
|
||||
|
||||
+---------------------------------------------------------------------------------------------------------+
|
||||
| **Reputational Key (GPG)** |
|
||||
+==================================================+======================================================+
|
||||
| Root Reputational Private Key (RSA 4096)# | Root Reputational Public Key (RSA 4096) |
|
||||
+--------------------------------------------------+------------------------------------------------------+
|
||||
| Signing Reputational Private Key (RSA 4096) | Signing Reputational Public Key (RSA 4096) |
|
||||
+--------------------------------------------------+------------------------------------------------------+
|
||||
| Identity: “Spack Project <maintainers@spack.io>” |
|
||||
+---------------------------------------------------------------------------------------------------------+
|
||||
| Signatures: Signed by core development team [#f1]_ |
|
||||
+---------------------------------------------------------------------------------------------------------+
|
||||
|
||||
The Root Reputational Private Key is stripped out of the GPG key and stored
|
||||
offline completely separate from Spack’s infrastructure. This allows the core
|
||||
development team to append revocation certificates to the GPG key in the
|
||||
unlikely event that the Signing Reputation Private Key is compromised. In
|
||||
general it is the expectation that rotating this key will happen infrequently if
|
||||
at all. This should allow relatively transparent verification for the end-user
|
||||
community without needing deep familiarity with GnuPG or Public Key
|
||||
Infrastructure.
|
||||
|
||||
|
||||
.. _build_cache_format:
|
||||
|
||||
------------------
|
||||
Build Cache Format
|
||||
------------------
|
||||
|
||||
A binary package consists of a metadata file unambiguously defining the
|
||||
built package (and including other details such as how to relocate it)
|
||||
and the installation directory of the package stored as a compressed
|
||||
archive file. The metadata files can either be unsigned, in which case
|
||||
the contents are simply the json-serialized concrete spec plus metadata,
|
||||
or they can be signed, in which case the json-serialized concrete spec
|
||||
plus metadata is wrapped in a gpg cleartext signature. Built package
|
||||
metadata files are named to indicate the operating system and
|
||||
architecture for which the package was built as well as the compiler
|
||||
used to build it and the packages name and version. For example::
|
||||
|
||||
linux-ubuntu18.04-haswell-gcc-7.5.0-zlib-1.2.12-llv2ysfdxnppzjrt5ldybb5c52qbmoow.spec.json.sig
|
||||
|
||||
would contain the concrete spec and binary metadata for a binary package
|
||||
of ``zlib@1.2.12``, built for the ``ubuntu`` operating system and ``haswell``
|
||||
architecture. The id of the built package exists in the name of the file
|
||||
as well (after the package name and version) and in this case begins
|
||||
with ``llv2ys``. The id distinguishes a particular built package from all
|
||||
other built packages with the same os/arch, compiler, name, and version.
|
||||
Below is an example of a signed binary package metadata file. Such a
|
||||
file would live in the ``build_cache`` directory of a binary mirror::
|
||||
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
{
|
||||
"spec": {
|
||||
<concrete-spec-contents-omitted>
|
||||
},
|
||||
|
||||
"buildcache_layout_version": 1,
|
||||
"binary_cache_checksum": {
|
||||
"hash_algorithm": "sha256",
|
||||
"hash": "4f1e46452c35a5e61bcacca205bae1bfcd60a83a399af201a29c95b7cc3e1423"
|
||||
},
|
||||
|
||||
"buildinfo": {
|
||||
"relative_prefix":
|
||||
"linux-ubuntu18.04-haswell/gcc-7.5.0/zlib-1.2.12-llv2ysfdxnppzjrt5ldybb5c52qbmoow",
|
||||
"relative_rpaths": false
|
||||
}
|
||||
}
|
||||
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
iQGzBAEBCgAdFiEETZn0sLle8jIrdAPLx/P+voVcifMFAmKAGvwACgkQx/P+voVc
|
||||
ifNoVgv/VrhA+wurVs5GB9PhmMA1m5U/AfXZb4BElDRwpT8ZcTPIv5X8xtv60eyn
|
||||
4EOneGVbZoMThVxgev/NKARorGmhFXRqhWf+jknJZ1dicpqn/qpv34rELKUpgXU+
|
||||
QDQ4d1P64AIdTczXe2GI9ZvhOo6+bPvK7LIsTkBbtWmopkomVxF0LcMuxAVIbA6b
|
||||
887yBvVO0VGlqRnkDW7nXx49r3AG2+wDcoU1f8ep8QtjOcMNaPTPJ0UnjD0VQGW6
|
||||
4ZFaGZWzdo45MY6tF3o5mqM7zJkVobpoW3iUz6J5tjz7H/nMlGgMkUwY9Kxp2PVH
|
||||
qoj6Zip3LWplnl2OZyAY+vflPFdFh12Xpk4FG7Sxm/ux0r+l8tCAPvtw+G38a5P7
|
||||
QEk2JBr8qMGKASmnRlJUkm1vwz0a95IF3S9YDfTAA2vz6HH3PtsNLFhtorfx8eBi
|
||||
Wn5aPJAGEPOawEOvXGGbsH4cDEKPeN0n6cy1k92uPEmBLDVsdnur8q42jk5c2Qyx
|
||||
j3DXty57
|
||||
=3gvm
|
||||
-----END PGP SIGNATURE-----
|
||||
|
||||
If a user has trusted the public key associated with the private key
|
||||
used to sign the above spec file, the signature can be verified with
|
||||
gpg, as follows::
|
||||
|
||||
$ gpg –verify linux-ubuntu18.04-haswell-gcc-7.5.0-zlib-1.2.12-llv2ysfdxnppzjrt5ldybb5c52qbmoow.spec.json.sig
|
||||
|
||||
The metadata (regardless whether signed or unsigned) contains the checksum
|
||||
of the ``.spack`` file containing the actual installation. The checksum should
|
||||
be compared to a checksum computed locally on the ``.spack`` file to ensure the
|
||||
contents have not changed since the binary spec plus metadata were signed. The
|
||||
``.spack`` files are actually tarballs containing the compressed archive of the
|
||||
install tree. These files, along with the metadata files, live within the
|
||||
``build_cache`` directory of the mirror, and together are organized as follows::
|
||||
|
||||
build_cache/
|
||||
# unsigned metadata (for indexing, contains sha256 of .spack file)
|
||||
<arch>-<compiler>-<name>-<ver>-24zvipcqgg2wyjpvdq2ajy5jnm564hen.spec.json
|
||||
# clearsigned metadata (same as above, but signed)
|
||||
<arch>-<compiler>-<name>-<ver>-24zvipcqgg2wyjpvdq2ajy5jnm564hen.spec.json.sig
|
||||
<arch>/
|
||||
<compiler>/
|
||||
<name>-<ver>/
|
||||
# tar.gz-compressed prefix (may support more compression formats later)
|
||||
<arch>-<compiler>-<name>-<ver>-24zvipcqgg2wyjpvdq2ajy5jnm564hen.spack
|
||||
|
||||
Uncompressing and extracting the ``.spack`` file results in the install tree.
|
||||
This is in contrast to previous versions of spack, where the ``.spack`` file
|
||||
contained a (duplicated) metadata file, a signature file and a nested tarball
|
||||
containing the install tree.
|
||||
|
||||
.. _internal_implementation:
|
||||
|
||||
-----------------------
|
||||
Internal Implementation
|
||||
-----------------------
|
||||
|
||||
The technical implementation of the pipeline signing process includes components
|
||||
defined in Amazon Web Services, the Kubernetes cluster, at affilicated
|
||||
institutions, and the GitLab/GitLab Runner deployment. We present the techincal
|
||||
implementation in two interdependent sections. The first addresses how secrets
|
||||
are managed through the lifecycle of a develop or release pipeline. The second
|
||||
section describes how Gitlab Runner and pipelines are configured and managed to
|
||||
support secure automated signing.
|
||||
|
||||
Secrets Management
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As stated above the Root Private Keys (intermediate and reputational)
|
||||
are stripped from the GPG keys and stored outside Spack’s
|
||||
infrastructure.
|
||||
|
||||
.. warning::
|
||||
**TODO**
|
||||
- Explanation here about where and how access is handled for these keys.
|
||||
- Both Root private keys are protected with strong passwords
|
||||
- Who has access to these and how?
|
||||
|
||||
**Intermediate CI Key**
|
||||
-----------------------
|
||||
|
||||
Multiple intermediate CI signing keys exist, one Intermediate CI Key for jobs
|
||||
run in AWS, and one key for each affiliated institution (e.g. Univerity of
|
||||
Oregon). Here we describe how the Intermediate CI Key is managed in AWS:
|
||||
|
||||
The Intermediate CI Key (including the Signing Intermediate CI Private Key is
|
||||
exported as an ASCII armored file and stored in a Kubernetes secret called
|
||||
``spack-intermediate-ci-signing-key``. For convenience sake, this same secret
|
||||
contains an ASCII-armored export of just the *public* components of the
|
||||
Reputational Key. This secret also contains the *public* components of each of
|
||||
the affiliated institutions' Intermediate CI Key. These are potentially needed
|
||||
to verify dependent packages which may have been found in the public mirror or
|
||||
built by a protected job running on an affiliated institution's infrastrcuture
|
||||
in an earlier stage of the pipeline.
|
||||
|
||||
Procedurally the ``spack-intermediate-ci-signing-key`` secret is used in
|
||||
the following way:
|
||||
|
||||
1. A ``large-arm-prot`` or ``large-x86-prot`` protected runner picks up
|
||||
a job tagged ``protected`` from a protected GitLab branch. (See
|
||||
`Protected Runners and Reserved Tags <#_8bawjmgykv0b>`__).
|
||||
2. Based on its configuration, the runner creates a job Pod in the
|
||||
pipeline namespace and mounts the spack-intermediate-ci-signing-key
|
||||
Kubernetes secret into the build container
|
||||
3. The Intermediate CI Key, affiliated institutions' public key and the
|
||||
Reputational Public Key are imported into a keyring by the ``spack gpg …``
|
||||
sub-command. This is initiated by the job’s build script which is created by
|
||||
the generate job at the beginning of the pipeline.
|
||||
4. Assuming the package has dependencies those specs are verified using
|
||||
the keyring.
|
||||
5. The package is built and the spec.json is generated
|
||||
6. The spec.json is signed by the keyring and uploaded to the mirror’s
|
||||
build cache.
|
||||
|
||||
**Reputational Key**
|
||||
--------------------
|
||||
|
||||
Because of the increased impact to end users in the case of a private
|
||||
key breach, the Reputational Key is managed separately from the
|
||||
Intermediate CI Keys and has additional controls. First, the Reputational
|
||||
Key was generated outside of Spack’s infrastructure and has been signed
|
||||
by the core development team. The Reputational Key (along with the
|
||||
Signing Reputational Private Key) was then ASCII armor exported to a
|
||||
file. Unlike the Intermediate CI Key this exported file is not stored as
|
||||
a base64 encoded secret in Kubernetes. Instead\ *the key file
|
||||
itself*\ is encrypted and stored in Kubernetes as the
|
||||
``spack-signing-key-encrypted`` secret in the pipeline namespace.
|
||||
|
||||
The encryption of the exported Reputational Key (including the Signing
|
||||
Reputational Private Key) is handled by `AWS Key Management Store (KMS) data
|
||||
keys
|
||||
<https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#data-keys>`__.
|
||||
The private key material is decrypted and imported at the time of signing into a
|
||||
memory mounted temporary directory holding the keychain. The signing job uses
|
||||
the `AWS Encryption SDK
|
||||
<https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/crypto-cli.html>`__
|
||||
(i.e. ``aws-encryption-cli``) to decrypt the Reputational Key. Permission to
|
||||
decrypt the key is granted to the job Pod through a Kubernetes service account
|
||||
specifically used for this, and only this, function. Finally, for convenience
|
||||
sake, this same secret contains an ASCII-armored export of the *public*
|
||||
components of the Intermediate CI Keys and the Reputational Key. This allows the
|
||||
signing script to verify that packages were built by the pipeline (both on AWS
|
||||
or at affiliated institutions), or signed previously as a part of a different
|
||||
pipeline. This is is done *before* importing decrypting and importing the
|
||||
Signing Reputational Private Key material and officially signing the packages.
|
||||
|
||||
Procedurally the ``spack-singing-key-encrypted`` secret is used in the
|
||||
following way:
|
||||
|
||||
1. The ``spack-package-signing-gitlab-runner`` protected runner picks
|
||||
up a job tagged ``notary`` from a protected GitLab branch (See
|
||||
`Protected Runners and Reserved Tags <#_8bawjmgykv0b>`__).
|
||||
2. Based on its configuration, the runner creates a job pod in the
|
||||
pipeline namespace. The job is run in a stripped down purpose-built
|
||||
image ``ghcr.io/spack/notary:latest`` Docker image. The runner is
|
||||
configured to only allow running jobs with this image.
|
||||
3. The runner also mounts the ``spack-signing-key-encrypted`` secret to
|
||||
a path on disk. Note that this becomes several files on disk, the
|
||||
public components of the Intermediate CI Keys, the public components
|
||||
of the Reputational CI, and an AWS KMS encrypted file containing the
|
||||
Singing Reputational Private Key.
|
||||
4. In addition to the secret, the runner creates a tmpfs memory mounted
|
||||
directory where the GnuPG keyring will be created to verify, and
|
||||
then resign the package specs.
|
||||
5. The job script syncs all spec.json.sig files from the build cache to
|
||||
a working directory in the job’s execution environment.
|
||||
6. The job script then runs the ``sign.sh`` script built into the
|
||||
notary Docker image.
|
||||
7. The ``sign.sh`` script imports the public components of the
|
||||
Reputational and Intermediate CI Keys and uses them to verify good
|
||||
signatures on the spec.json.sig files. If any signed spec does not
|
||||
verify the job immediately fails.
|
||||
8. Assuming all specs are verified, the ``sign.sh`` script then unpacks
|
||||
the spec json data from the signed file in preparation for being
|
||||
re-signed with the Reputational Key.
|
||||
9. The private components of the Reputational Key are decrypted to
|
||||
standard out using ``aws-encryption-cli`` directly into a ``gpg
|
||||
–import …`` statement which imports the key into the
|
||||
keyring mounted in-memory.
|
||||
10. The private key is then used to sign each of the json specs and the
|
||||
keyring is removed from disk.
|
||||
11. The re-signed json specs are resynced to the AWS S3 Mirror and the
|
||||
public signing of the packages for the develop or release pipeline
|
||||
that created them is complete.
|
||||
|
||||
Non service-account access to the private components of the Reputational
|
||||
Key that are managed through access to the symmetric secret in KMS used
|
||||
to encrypt the data key (which in turn is used to encrypt the GnuPG key
|
||||
- See:\ `Encryption SDK
|
||||
Documentation <https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/crypto-cli-examples.html#cli-example-encrypt-file>`__).
|
||||
A small trusted subset of the core development team are the only
|
||||
individuals with access to this symmetric key.
|
||||
|
||||
.. _protected_runners:
|
||||
|
||||
Protected Runners and Reserved Tags
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Spack has a large number of Gitlab Runners operating in its build farm.
|
||||
These include runners deployed in the AWS Kubernetes cluster as well as
|
||||
runners deployed at affiliated institutions. The majority of runners are
|
||||
shared runners that operate across projects in gitlab.spack.io. These
|
||||
runners pick up jobs primarily from the spack/spack project and execute
|
||||
them in PR pipelines.
|
||||
|
||||
A small number of runners operating on AWS and at affiliated institutions are
|
||||
registered as specific *protected* runners on the spack/spack project. In
|
||||
addition to protected runners there are protected branches on the spack/spack
|
||||
project. These are the ``develop`` branch, any release branch (i.e. managed with
|
||||
the ``releases/v*`` wildcard) and any tag branch (managed with the ``v*``
|
||||
wildcard) Finally Spack’s pipeline generation code reserves certain tags to make
|
||||
sure jobs are routed to the correct runners, these tags are ``public``,
|
||||
``protected``, and ``notary``. Understanding how all this works together to
|
||||
protect secrets and provide integrity assurances can be a little confusing so
|
||||
lets break these down:
|
||||
|
||||
- **Protected Branches**- Protected branches in Spack prevent anyone
|
||||
other than Maintainers in GitLab from pushing code. In the case of
|
||||
Spack the only Maintainer level entity pushing code to protected
|
||||
branches is Spack bot. Protecting branches also marks them in such a
|
||||
way that Protected Runners will only run jobs from those branches
|
||||
- **Protected Runners**- Protected Runners only run jobs from protected
|
||||
branches. Because protected runners have access to secrets, it's critical
|
||||
that they not run Jobs from untrusted code (i.e. PR branches). If they did it
|
||||
would be possible for a PR branch to tag a job in such a way that a protected
|
||||
runner executed that job and mounted secrets into a code execution
|
||||
environment that had not been reviewed by Spack maintainers. Note however
|
||||
that in the absence of tagging used to route jobs, public runners *could* run
|
||||
jobs from protected branches. No secrets would be at risk of being breached
|
||||
because non-protected runners do not have access to those secrets; lack of
|
||||
secrets would, however, cause the jobs to fail.
|
||||
- **Reserved Tags**- To mitigate the issue of public runners picking up
|
||||
protected jobs Spack uses a small set of “reserved” job tags (Note that these
|
||||
are *job* tags not git tags). These tags are “public”, “private”, and
|
||||
“notary.” The majority of jobs executed in Spack’s GitLab instance are
|
||||
executed via a ``generate`` job. The generate job code systematically ensures
|
||||
that no user defined configuration sets these tags. Instead, the ``generate``
|
||||
job sets these tags based on rules related to the branch where this pipeline
|
||||
originated. If the job is a part of a pipeline on a PR branch it sets the
|
||||
``public`` tag. If the job is part of a pipeline on a protected branch it
|
||||
sets the ``protected`` tag. Finally if the job is the package signing job and
|
||||
it is running on a pipeline that is part of a protected branch then it sets
|
||||
the ``notary`` tag.
|
||||
|
||||
Protected Runners are configured to only run jobs from protected branches. Only
|
||||
jobs running in pipelines on protected branches are tagged with ``protected`` or
|
||||
``notary`` tags. This tightly couples jobs on protected branches to protected
|
||||
runners that provide access to the secrets required to sign the built packages.
|
||||
The secrets are can **only** be accessed via:
|
||||
|
||||
1. Runners under direct control of the core development team.
|
||||
2. Runners under direct control of trusted maintainers at affiliated institutions.
|
||||
3. By code running the automated pipeline that has been reviewed by the
|
||||
Spack maintainers and judged to be appropriate.
|
||||
|
||||
Other attempts (either through malicious intent or incompetence) can at
|
||||
worst grab jobs intended for protected runners which will cause those
|
||||
jobs to fail alerting both Spack maintainers and the core development
|
||||
team.
|
||||
|
||||
.. [#f1]
|
||||
The Reputational Key has also cross signed core development team
|
||||
keys.
|
@@ -139,7 +139,7 @@ def get_fh(self, path):
|
||||
def release_by_stat(self, stat):
|
||||
key = (stat.st_dev, stat.st_ino, os.getpid())
|
||||
open_file = self._descriptors.get(key)
|
||||
assert open_file, "Attempted to close non-existing inode: %s" % stat.st_ino
|
||||
assert open_file, "Attempted to close non-existing inode: %s" % stat.st_inode
|
||||
|
||||
open_file.refs -= 1
|
||||
if not open_file.refs:
|
||||
|
@@ -4,7 +4,7 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
#: PEP440 canonical <major>.<minor>.<micro>.<devN> string
|
||||
__version__ = "0.20.2"
|
||||
__version__ = "0.21.0.dev0"
|
||||
spack_version = __version__
|
||||
|
||||
|
||||
|
@@ -199,11 +199,11 @@ def _associate_built_specs_with_mirror(self, cache_key, mirror_url):
|
||||
with self._index_file_cache.read_transaction(cache_key):
|
||||
db._read_from_file(cache_path)
|
||||
except spack_db.InvalidDatabaseVersionError as e:
|
||||
tty.warn(
|
||||
msg = (
|
||||
f"you need a newer Spack version to read the buildcache index for the "
|
||||
f"following mirror: '{mirror_url}'. {e.database_version_message}"
|
||||
)
|
||||
return
|
||||
raise BuildcacheIndexError(msg) from e
|
||||
|
||||
spec_list = db.query_local(installed=False, in_buildcache=True)
|
||||
|
||||
@@ -760,13 +760,12 @@ def hashes_to_prefixes(spec):
|
||||
}
|
||||
|
||||
|
||||
def get_buildinfo_dict(spec, rel=False):
|
||||
def get_buildinfo_dict(spec):
|
||||
"""Create metadata for a tarball"""
|
||||
manifest = get_buildfile_manifest(spec)
|
||||
|
||||
return {
|
||||
"sbang_install_path": spack.hooks.sbang.sbang_install_path(),
|
||||
"relative_rpaths": rel,
|
||||
"buildpath": spack.store.layout.root,
|
||||
"spackprefix": spack.paths.prefix,
|
||||
"relative_prefix": os.path.relpath(spec.prefix, spack.store.layout.root),
|
||||
@@ -1209,9 +1208,6 @@ class PushOptions(NamedTuple):
|
||||
#: Overwrite existing tarball/metadata files in buildcache
|
||||
force: bool = False
|
||||
|
||||
#: Whether to use relative RPATHs
|
||||
relative: bool = False
|
||||
|
||||
#: Allow absolute paths to package prefixes when creating a tarball
|
||||
allow_root: bool = False
|
||||
|
||||
@@ -1281,41 +1277,17 @@ def _build_tarball_in_stage_dir(spec: Spec, out_url: str, stage_dir: str, option
|
||||
raise NoOverwriteException(url_util.format(remote_specfile_path))
|
||||
|
||||
pkg_dir = os.path.basename(spec.prefix.rstrip(os.path.sep))
|
||||
workdir = os.path.join(stage_dir, pkg_dir)
|
||||
|
||||
# TODO: We generally don't want to mutate any files, but when using relative
|
||||
# mode, Spack unfortunately *does* mutate rpaths and links ahead of time.
|
||||
# For now, we only make a full copy of the spec prefix when in relative mode.
|
||||
|
||||
if options.relative:
|
||||
# tarfile is used because it preserves hardlink etc best.
|
||||
binaries_dir = workdir
|
||||
temp_tarfile_name = tarball_name(spec, ".tar")
|
||||
temp_tarfile_path = os.path.join(tarfile_dir, temp_tarfile_name)
|
||||
with closing(tarfile.open(temp_tarfile_path, "w")) as tar:
|
||||
tar.add(name="%s" % spec.prefix, arcname=".")
|
||||
with closing(tarfile.open(temp_tarfile_path, "r")) as tar:
|
||||
tar.extractall(workdir)
|
||||
os.remove(temp_tarfile_path)
|
||||
else:
|
||||
binaries_dir = spec.prefix
|
||||
binaries_dir = spec.prefix
|
||||
|
||||
# create info for later relocation and create tar
|
||||
buildinfo = get_buildinfo_dict(spec, options.relative)
|
||||
buildinfo = get_buildinfo_dict(spec)
|
||||
|
||||
# optionally make the paths in the binaries relative to each other
|
||||
# in the spack install tree before creating tarball
|
||||
if options.relative:
|
||||
make_package_relative(workdir, spec, buildinfo, options.allow_root)
|
||||
elif not options.allow_root:
|
||||
if not options.allow_root:
|
||||
ensure_package_relocatable(buildinfo, binaries_dir)
|
||||
|
||||
_do_create_tarball(tarfile_path, binaries_dir, pkg_dir, buildinfo)
|
||||
|
||||
# remove copy of install directory
|
||||
if options.relative:
|
||||
shutil.rmtree(workdir)
|
||||
|
||||
# get the sha256 checksum of the tarball
|
||||
checksum = checksum_tarball(tarfile_path)
|
||||
|
||||
@@ -1336,7 +1308,6 @@ def _build_tarball_in_stage_dir(spec: Spec, out_url: str, stage_dir: str, option
|
||||
# This will be used to determine is the directory layout has changed.
|
||||
buildinfo = {}
|
||||
buildinfo["relative_prefix"] = os.path.relpath(spec.prefix, spack.store.layout.root)
|
||||
buildinfo["relative_rpaths"] = options.relative
|
||||
spec_dict["buildinfo"] = buildinfo
|
||||
|
||||
with open(specfile_path, "w") as outfile:
|
||||
@@ -1596,35 +1567,6 @@ def download_tarball(spec, unsigned=False, mirrors_for_spec=None):
|
||||
return None
|
||||
|
||||
|
||||
def make_package_relative(workdir, spec, buildinfo, allow_root):
|
||||
"""
|
||||
Change paths in binaries to relative paths. Change absolute symlinks
|
||||
to relative symlinks.
|
||||
"""
|
||||
prefix = spec.prefix
|
||||
old_layout_root = buildinfo["buildpath"]
|
||||
orig_path_names = list()
|
||||
cur_path_names = list()
|
||||
for filename in buildinfo["relocate_binaries"]:
|
||||
orig_path_names.append(os.path.join(prefix, filename))
|
||||
cur_path_names.append(os.path.join(workdir, filename))
|
||||
|
||||
platform = spack.platforms.by_name(spec.platform)
|
||||
if "macho" in platform.binary_formats:
|
||||
relocate.make_macho_binaries_relative(cur_path_names, orig_path_names, old_layout_root)
|
||||
|
||||
if "elf" in platform.binary_formats:
|
||||
relocate.make_elf_binaries_relative(cur_path_names, orig_path_names, old_layout_root)
|
||||
|
||||
allow_root or relocate.ensure_binaries_are_relocatable(cur_path_names)
|
||||
orig_path_names = list()
|
||||
cur_path_names = list()
|
||||
for linkname in buildinfo.get("relocate_links", []):
|
||||
orig_path_names.append(os.path.join(prefix, linkname))
|
||||
cur_path_names.append(os.path.join(workdir, linkname))
|
||||
relocate.make_link_relative(cur_path_names, orig_path_names)
|
||||
|
||||
|
||||
def ensure_package_relocatable(buildinfo, binaries_dir):
|
||||
"""Check if package binaries are relocatable."""
|
||||
binaries = [os.path.join(binaries_dir, f) for f in buildinfo["relocate_binaries"]]
|
||||
|
@@ -175,12 +175,12 @@ def black_root_spec() -> str:
|
||||
|
||||
def flake8_root_spec() -> str:
|
||||
"""Return the root spec used to bootstrap flake8"""
|
||||
return _root_spec("py-flake8")
|
||||
return _root_spec("py-flake8@3.8.2:")
|
||||
|
||||
|
||||
def pytest_root_spec() -> str:
|
||||
"""Return the root spec used to bootstrap flake8"""
|
||||
return _root_spec("py-pytest")
|
||||
return _root_spec("py-pytest@6.2.4:")
|
||||
|
||||
|
||||
def ensure_environment_dependencies() -> None:
|
||||
|
@@ -589,7 +589,6 @@ def set_module_variables_for_package(pkg):
|
||||
|
||||
# TODO: make these build deps that can be installed if not found.
|
||||
m.make = MakeExecutable("make", jobs)
|
||||
m.gmake = MakeExecutable("gmake", jobs)
|
||||
m.ninja = MakeExecutable("ninja", jobs, supports_jobserver=False)
|
||||
# TODO: johnwparent: add package or builder support to define these build tools
|
||||
# for now there is no entrypoint for builders to define these on their
|
||||
@@ -1028,7 +1027,7 @@ def get_cmake_prefix_path(pkg):
|
||||
|
||||
|
||||
def _setup_pkg_and_run(
|
||||
serialized_pkg, function, kwargs, write_pipe, input_multiprocess_fd, jsfd1, jsfd2
|
||||
serialized_pkg, function, kwargs, child_pipe, input_multiprocess_fd, jsfd1, jsfd2
|
||||
):
|
||||
context = kwargs.get("context", "build")
|
||||
|
||||
@@ -1049,12 +1048,12 @@ def _setup_pkg_and_run(
|
||||
pkg, dirty=kwargs.get("dirty", False), context=context
|
||||
)
|
||||
return_value = function(pkg, kwargs)
|
||||
write_pipe.send(return_value)
|
||||
child_pipe.send(return_value)
|
||||
|
||||
except StopPhase as e:
|
||||
# Do not create a full ChildError from this, it's not an error
|
||||
# it's a control statement.
|
||||
write_pipe.send(e)
|
||||
child_pipe.send(e)
|
||||
except BaseException:
|
||||
# catch ANYTHING that goes wrong in the child process
|
||||
exc_type, exc, tb = sys.exc_info()
|
||||
@@ -1103,10 +1102,10 @@ def _setup_pkg_and_run(
|
||||
context,
|
||||
package_context,
|
||||
)
|
||||
write_pipe.send(ce)
|
||||
child_pipe.send(ce)
|
||||
|
||||
finally:
|
||||
write_pipe.close()
|
||||
child_pipe.close()
|
||||
if input_multiprocess_fd is not None:
|
||||
input_multiprocess_fd.close()
|
||||
|
||||
@@ -1150,7 +1149,7 @@ def child_fun():
|
||||
For more information on `multiprocessing` child process creation
|
||||
mechanisms, see https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods
|
||||
"""
|
||||
read_pipe, write_pipe = multiprocessing.Pipe(duplex=False)
|
||||
parent_pipe, child_pipe = multiprocessing.Pipe()
|
||||
input_multiprocess_fd = None
|
||||
jobserver_fd1 = None
|
||||
jobserver_fd2 = None
|
||||
@@ -1175,7 +1174,7 @@ def child_fun():
|
||||
serialized_pkg,
|
||||
function,
|
||||
kwargs,
|
||||
write_pipe,
|
||||
child_pipe,
|
||||
input_multiprocess_fd,
|
||||
jobserver_fd1,
|
||||
jobserver_fd2,
|
||||
@@ -1184,12 +1183,6 @@ def child_fun():
|
||||
|
||||
p.start()
|
||||
|
||||
# We close the writable end of the pipe now to be sure that p is the
|
||||
# only process which owns a handle for it. This ensures that when p
|
||||
# closes its handle for the writable end, read_pipe.recv() will
|
||||
# promptly report the readable end as being ready.
|
||||
write_pipe.close()
|
||||
|
||||
except InstallError as e:
|
||||
e.pkg = pkg
|
||||
raise
|
||||
@@ -1199,16 +1192,7 @@ def child_fun():
|
||||
if input_multiprocess_fd is not None:
|
||||
input_multiprocess_fd.close()
|
||||
|
||||
def exitcode_msg(p):
|
||||
typ = "exit" if p.exitcode >= 0 else "signal"
|
||||
return f"{typ} {abs(p.exitcode)}"
|
||||
|
||||
try:
|
||||
child_result = read_pipe.recv()
|
||||
except EOFError:
|
||||
p.join()
|
||||
raise InstallError(f"The process has stopped unexpectedly ({exitcode_msg(p)})")
|
||||
|
||||
child_result = parent_pipe.recv()
|
||||
p.join()
|
||||
|
||||
# If returns a StopPhase, raise it
|
||||
@@ -1228,10 +1212,6 @@ def exitcode_msg(p):
|
||||
child_result.print_context()
|
||||
raise child_result
|
||||
|
||||
# Fallback. Usually caught beforehand in EOFError above.
|
||||
if p.exitcode != 0:
|
||||
raise InstallError(f"The process failed unexpectedly ({exitcode_msg(p)})")
|
||||
|
||||
return child_result
|
||||
|
||||
|
||||
@@ -1276,8 +1256,9 @@ def make_stack(tb, stack=None):
|
||||
func = getattr(obj, tb.tb_frame.f_code.co_name, "")
|
||||
if func:
|
||||
typename, *_ = func.__qualname__.partition(".")
|
||||
if isinstance(obj, CONTEXT_BASES) and typename not in basenames:
|
||||
break
|
||||
|
||||
if isinstance(obj, CONTEXT_BASES) and typename not in basenames:
|
||||
break
|
||||
else:
|
||||
return None
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import collections.abc
|
||||
import os
|
||||
from typing import Tuple
|
||||
|
||||
@@ -13,21 +14,24 @@
|
||||
from .cmake import CMakeBuilder, CMakePackage
|
||||
|
||||
|
||||
def cmake_cache_path(name, value, comment=""):
|
||||
def cmake_cache_path(name, value, comment="", force=False):
|
||||
"""Generate a string for a cmake cache variable"""
|
||||
return 'set({0} "{1}" CACHE PATH "{2}")\n'.format(name, value, comment)
|
||||
force_str = " FORCE" if force else ""
|
||||
return 'set({0} "{1}" CACHE PATH "{2}"{3})\n'.format(name, value, comment, force_str)
|
||||
|
||||
|
||||
def cmake_cache_string(name, value, comment=""):
|
||||
def cmake_cache_string(name, value, comment="", force=False):
|
||||
"""Generate a string for a cmake cache variable"""
|
||||
return 'set({0} "{1}" CACHE STRING "{2}")\n'.format(name, value, comment)
|
||||
force_str = " FORCE" if force else ""
|
||||
return 'set({0} "{1}" CACHE STRING "{2}"{3})\n'.format(name, value, comment, force_str)
|
||||
|
||||
|
||||
def cmake_cache_option(name, boolean_value, comment=""):
|
||||
def cmake_cache_option(name, boolean_value, comment="", force=False):
|
||||
"""Generate a string for a cmake configuration option"""
|
||||
|
||||
value = "ON" if boolean_value else "OFF"
|
||||
return 'set({0} {1} CACHE BOOL "{2}")\n'.format(name, value, comment)
|
||||
force_str = " FORCE" if force else ""
|
||||
return 'set({0} {1} CACHE BOOL "{2}"{3})\n'.format(name, value, comment, force_str)
|
||||
|
||||
|
||||
class CachedCMakeBuilder(CMakeBuilder):
|
||||
@@ -63,6 +67,34 @@ def cache_name(self):
|
||||
def cache_path(self):
|
||||
return os.path.join(self.pkg.stage.source_path, self.cache_name)
|
||||
|
||||
# Implement a version of the define_from_variant for Cached packages
|
||||
def define_cmake_cache_from_variant(self, cmake_var, variant=None, comment=""):
|
||||
"""Return a Cached CMake field from the given variant's value.
|
||||
See define_from_variant in lib/spack/spack/build_systems/cmake.py package
|
||||
"""
|
||||
|
||||
if variant is None:
|
||||
variant = cmake_var.lower()
|
||||
|
||||
if variant not in self.pkg.variants:
|
||||
raise KeyError('"{0}" is not a variant of "{1}"'.format(variant, self.pkg.name))
|
||||
|
||||
if variant not in self.pkg.spec.variants:
|
||||
return ""
|
||||
|
||||
value = self.pkg.spec.variants[variant].value
|
||||
field = None
|
||||
if isinstance(value, bool):
|
||||
field = cmake_cache_option(cmake_var, value, comment)
|
||||
else:
|
||||
if isinstance(value, collections.abc.Sequence) and not isinstance(value, str):
|
||||
value = ";".join(str(v) for v in value)
|
||||
else:
|
||||
value = str(value)
|
||||
field = cmake_cache_string(cmake_var, value, comment)
|
||||
|
||||
return field
|
||||
|
||||
def initconfig_compiler_entries(self):
|
||||
# This will tell cmake to use the Spack compiler wrappers when run
|
||||
# through Spack, but use the underlying compiler when run outside of
|
||||
@@ -130,6 +162,17 @@ def initconfig_compiler_entries(self):
|
||||
libs_string = libs_format_string.format(lang)
|
||||
entries.append(cmake_cache_string(libs_string, libs_flags))
|
||||
|
||||
# Set the generator in the cached config
|
||||
if self.spec.satisfies("generator=make"):
|
||||
entries.append(cmake_cache_string("CMAKE_GENERATOR", "Unix Makefiles"))
|
||||
if self.spec.satisfies("generator=ninja"):
|
||||
entries.append(cmake_cache_string("CMAKE_GENERATOR", "Ninja"))
|
||||
entries.append(
|
||||
cmake_cache_string(
|
||||
"CMAKE_MAKE_PROGRAM", "{0}/ninja".format(spec["ninja"].prefix.bin)
|
||||
)
|
||||
)
|
||||
|
||||
return entries
|
||||
|
||||
def initconfig_mpi_entries(self):
|
||||
@@ -195,26 +238,57 @@ def initconfig_hardware_entries(self):
|
||||
"#------------------{0}\n".format("-" * 60),
|
||||
]
|
||||
|
||||
# Provide standard CMake arguments for dependent CachedCMakePackages
|
||||
if spec.satisfies("^cuda"):
|
||||
entries.append("#------------------{0}".format("-" * 30))
|
||||
entries.append("# Cuda")
|
||||
entries.append("#------------------{0}\n".format("-" * 30))
|
||||
|
||||
cudatoolkitdir = spec["cuda"].prefix
|
||||
entries.append(cmake_cache_path("CUDA_TOOLKIT_ROOT_DIR", cudatoolkitdir))
|
||||
cudacompiler = "${CUDA_TOOLKIT_ROOT_DIR}/bin/nvcc"
|
||||
entries.append(cmake_cache_path("CMAKE_CUDA_COMPILER", cudacompiler))
|
||||
entries.append(cmake_cache_path("CUDAToolkit_ROOT", cudatoolkitdir))
|
||||
entries.append(cmake_cache_path("CMAKE_CUDA_COMPILER", "${CUDAToolkit_ROOT}/bin/nvcc"))
|
||||
entries.append(cmake_cache_path("CMAKE_CUDA_HOST_COMPILER", "${CMAKE_CXX_COMPILER}"))
|
||||
# Include the deprecated CUDA_TOOLKIT_ROOT_DIR for supporting BLT packages
|
||||
entries.append(cmake_cache_path("CUDA_TOOLKIT_ROOT_DIR", cudatoolkitdir))
|
||||
|
||||
archs = spec.variants["cuda_arch"].value
|
||||
if archs[0] != "none":
|
||||
arch_str = ";".join(archs)
|
||||
entries.append(
|
||||
cmake_cache_string("CMAKE_CUDA_ARCHITECTURES", "{0}".format(arch_str))
|
||||
)
|
||||
|
||||
if "+rocm" in spec:
|
||||
entries.append("#------------------{0}".format("-" * 30))
|
||||
entries.append("# ROCm")
|
||||
entries.append("#------------------{0}\n".format("-" * 30))
|
||||
|
||||
# Explicitly setting HIP_ROOT_DIR may be a patch that is no longer necessary
|
||||
entries.append(cmake_cache_path("HIP_ROOT_DIR", "{0}".format(spec["hip"].prefix)))
|
||||
entries.append(
|
||||
cmake_cache_path("HIP_CXX_COMPILER", "{0}".format(self.spec["hip"].hipcc))
|
||||
)
|
||||
archs = self.spec.variants["amdgpu_target"].value
|
||||
if archs[0] != "none":
|
||||
arch_str = ";".join(archs)
|
||||
entries.append(
|
||||
cmake_cache_string("CMAKE_HIP_ARCHITECTURES", "{0}".format(arch_str))
|
||||
)
|
||||
entries.append(cmake_cache_string("AMDGPU_TARGETS", "{0}".format(arch_str)))
|
||||
entries.append(cmake_cache_string("GPU_TARGETS", "{0}".format(arch_str)))
|
||||
|
||||
return entries
|
||||
|
||||
def std_initconfig_entries(self):
|
||||
cmake_prefix_path_env = os.environ["CMAKE_PREFIX_PATH"]
|
||||
cmake_prefix_path = cmake_prefix_path_env.replace(os.pathsep, ";")
|
||||
return [
|
||||
"#------------------{0}".format("-" * 60),
|
||||
"# !!!! This is a generated file, edit at own risk !!!!",
|
||||
"#------------------{0}".format("-" * 60),
|
||||
"# CMake executable path: {0}".format(self.pkg.spec["cmake"].command.path),
|
||||
"#------------------{0}\n".format("-" * 60),
|
||||
cmake_cache_path("CMAKE_PREFIX_PATH", cmake_prefix_path),
|
||||
]
|
||||
|
||||
def initconfig_package_entries(self):
|
||||
|
@@ -5,6 +5,7 @@
|
||||
import collections.abc
|
||||
import inspect
|
||||
import os
|
||||
import pathlib
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
@@ -15,7 +16,6 @@
|
||||
import spack.build_environment
|
||||
import spack.builder
|
||||
import spack.package_base
|
||||
import spack.util.path
|
||||
from spack.directives import build_system, conflicts, depends_on, variant
|
||||
from spack.multimethod import when
|
||||
|
||||
@@ -271,7 +271,7 @@ def std_args(pkg, generator=None):
|
||||
args = [
|
||||
"-G",
|
||||
generator,
|
||||
define("CMAKE_INSTALL_PREFIX", pkg.prefix),
|
||||
define("CMAKE_INSTALL_PREFIX", pathlib.Path(pkg.prefix).as_posix()),
|
||||
define("CMAKE_BUILD_TYPE", build_type),
|
||||
define("BUILD_TESTING", pkg.run_tests),
|
||||
]
|
||||
|
@@ -223,7 +223,7 @@ def update_external_dependencies(self, extendee_spec=None):
|
||||
|
||||
python.external_path = self.spec.external_path
|
||||
python._mark_concrete()
|
||||
self.spec.add_dependency_edge(python, deptypes=("build", "link", "run"))
|
||||
self.spec.add_dependency_edge(python, deptypes=("build", "link", "run"), virtuals=())
|
||||
|
||||
|
||||
class PythonPackage(PythonExtension):
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
import llnl.util.lang as lang
|
||||
|
||||
from spack.directives import extends, maintainers
|
||||
from spack.directives import extends
|
||||
|
||||
from .generic import GenericBuilder, Package
|
||||
|
||||
@@ -71,8 +71,6 @@ class RPackage(Package):
|
||||
|
||||
GenericBuilder = RBuilder
|
||||
|
||||
maintainers("glennpj")
|
||||
|
||||
#: This attribute is used in UI queries that need to know the build
|
||||
#: system base class
|
||||
build_system_class = "RPackage"
|
||||
|
@@ -10,6 +10,7 @@
|
||||
from llnl.util.filesystem import find, join_path, working_dir
|
||||
|
||||
import spack.builder
|
||||
import spack.install_test
|
||||
import spack.package_base
|
||||
from spack.directives import build_system, depends_on, extends
|
||||
from spack.multimethod import when
|
||||
@@ -30,8 +31,8 @@ class SIPPackage(spack.package_base.PackageBase):
|
||||
#: Name of private sip module to install alongside package
|
||||
sip_module = "sip"
|
||||
|
||||
#: Callback names for install-time test
|
||||
install_time_test_callbacks = ["test"]
|
||||
#: Callback names for install-time testing
|
||||
install_time_test_callbacks = ["test_imports"]
|
||||
#: Legacy buildsystem attribute used to deserialize and install old specs
|
||||
legacy_buildsystem = "sip"
|
||||
|
||||
@@ -87,18 +88,20 @@ def python(self, *args, **kwargs):
|
||||
"""The python ``Executable``."""
|
||||
inspect.getmodule(self).python(*args, **kwargs)
|
||||
|
||||
def test(self):
|
||||
def test_imports(self):
|
||||
"""Attempts to import modules of the installed package."""
|
||||
|
||||
# Make sure we are importing the installed modules,
|
||||
# not the ones in the source directory
|
||||
python = inspect.getmodule(self).python
|
||||
for module in self.import_modules:
|
||||
self.run_test(
|
||||
inspect.getmodule(self).python.path,
|
||||
["-c", "import {0}".format(module)],
|
||||
with spack.install_test.test_part(
|
||||
self,
|
||||
"test_imports_{0}".format(module),
|
||||
purpose="checking import of {0}".format(module),
|
||||
work_dir="spack-test",
|
||||
)
|
||||
):
|
||||
python("-c", "import {0}".format(module))
|
||||
|
||||
|
||||
@spack.builder.builder("sip")
|
||||
|
@@ -751,7 +751,7 @@ def generate_gitlab_ci_yaml(
|
||||
env.concretize()
|
||||
env.write()
|
||||
|
||||
yaml_root = ev.config_dict(env.manifest)
|
||||
yaml_root = env.manifest[ev.TOP_LEVEL_KEY]
|
||||
|
||||
# Get the joined "ci" config with all of the current scopes resolved
|
||||
ci_config = cfg.get("ci")
|
||||
@@ -946,7 +946,7 @@ def generate_gitlab_ci_yaml(
|
||||
# Add config scopes to environment
|
||||
env_includes = env_yaml_root["spack"].get("include", [])
|
||||
cli_scopes = [
|
||||
os.path.abspath(s.path)
|
||||
os.path.relpath(s.path, concrete_env_dir)
|
||||
for s in cfg.scopes().values()
|
||||
if type(s) == cfg.ImmutableConfigScope
|
||||
and s.path not in env_includes
|
||||
@@ -1095,7 +1095,7 @@ def generate_gitlab_ci_yaml(
|
||||
raise AttributeError
|
||||
|
||||
def main_script_replacements(cmd):
|
||||
return cmd.replace("{env_dir}", concrete_env_dir)
|
||||
return cmd.replace("{env_dir}", rel_concrete_env_dir)
|
||||
|
||||
job_object["script"] = _unpack_script(
|
||||
job_object["script"], op=main_script_replacements
|
||||
|
@@ -43,13 +43,6 @@ def setup_parser(subparser):
|
||||
subparsers = subparser.add_subparsers(help="buildcache sub-commands")
|
||||
|
||||
push = subparsers.add_parser("push", aliases=["create"], help=push_fn.__doc__)
|
||||
# TODO: remove from Spack 0.21
|
||||
push.add_argument(
|
||||
"-r",
|
||||
"--rel",
|
||||
action="store_true",
|
||||
help="make all rpaths relative before creating tarballs. (deprecated)",
|
||||
)
|
||||
push.add_argument("-f", "--force", action="store_true", help="overwrite tarball if it exists.")
|
||||
push.add_argument(
|
||||
"-u", "--unsigned", action="store_true", help="push unsigned buildcache tarballs"
|
||||
@@ -63,37 +56,7 @@ def setup_parser(subparser):
|
||||
push.add_argument(
|
||||
"-k", "--key", metavar="key", type=str, default=None, help="Key for signing."
|
||||
)
|
||||
output = push.add_mutually_exclusive_group(required=False)
|
||||
# TODO: remove from Spack 0.21
|
||||
output.add_argument(
|
||||
"-d",
|
||||
"--directory",
|
||||
metavar="directory",
|
||||
dest="mirror_flag",
|
||||
type=arguments.mirror_directory,
|
||||
help="local directory where buildcaches will be written. (deprecated)",
|
||||
)
|
||||
# TODO: remove from Spack 0.21
|
||||
output.add_argument(
|
||||
"-m",
|
||||
"--mirror-name",
|
||||
metavar="mirror-name",
|
||||
dest="mirror_flag",
|
||||
type=arguments.mirror_name,
|
||||
help="name of the mirror where buildcaches will be written. (deprecated)",
|
||||
)
|
||||
# TODO: remove from Spack 0.21
|
||||
output.add_argument(
|
||||
"--mirror-url",
|
||||
metavar="mirror-url",
|
||||
dest="mirror_flag",
|
||||
type=arguments.mirror_url,
|
||||
help="URL of the mirror where buildcaches will be written. (deprecated)",
|
||||
)
|
||||
# Unfortunately we cannot add this to the mutually exclusive group above,
|
||||
# because we have further positional arguments.
|
||||
# TODO: require from Spack 0.21
|
||||
push.add_argument("mirror", type=str, help="Mirror name, path, or URL.", nargs="?")
|
||||
push.add_argument("mirror", type=str, help="Mirror name, path, or URL.")
|
||||
push.add_argument(
|
||||
"--update-index",
|
||||
"--rebuild-index",
|
||||
@@ -127,13 +90,6 @@ def setup_parser(subparser):
|
||||
install.add_argument(
|
||||
"-m", "--multiple", action="store_true", help="allow all matching packages "
|
||||
)
|
||||
# TODO: remove from Spack 0.21
|
||||
install.add_argument(
|
||||
"-a",
|
||||
"--allow-root",
|
||||
action="store_true",
|
||||
help="allow install root string in binary files after RPATH substitution. (deprecated)",
|
||||
)
|
||||
install.add_argument(
|
||||
"-u",
|
||||
"--unsigned",
|
||||
@@ -272,71 +228,17 @@ def setup_parser(subparser):
|
||||
default=None,
|
||||
help="A quoted glob pattern identifying copy manifest files",
|
||||
)
|
||||
source = sync.add_mutually_exclusive_group(required=False)
|
||||
# TODO: remove in Spack 0.21
|
||||
source.add_argument(
|
||||
"--src-directory",
|
||||
metavar="DIRECTORY",
|
||||
dest="src_mirror_flag",
|
||||
type=arguments.mirror_directory,
|
||||
help="Source mirror as a local file path (deprecated)",
|
||||
)
|
||||
# TODO: remove in Spack 0.21
|
||||
source.add_argument(
|
||||
"--src-mirror-name",
|
||||
metavar="MIRROR_NAME",
|
||||
dest="src_mirror_flag",
|
||||
type=arguments.mirror_name,
|
||||
help="Name of the source mirror (deprecated)",
|
||||
)
|
||||
# TODO: remove in Spack 0.21
|
||||
source.add_argument(
|
||||
"--src-mirror-url",
|
||||
metavar="MIRROR_URL",
|
||||
dest="src_mirror_flag",
|
||||
type=arguments.mirror_url,
|
||||
help="URL of the source mirror (deprecated)",
|
||||
)
|
||||
# TODO: only support this in 0.21
|
||||
source.add_argument(
|
||||
sync.add_argument(
|
||||
"src_mirror",
|
||||
metavar="source mirror",
|
||||
type=arguments.mirror_name_or_url,
|
||||
help="Source mirror name, path, or URL",
|
||||
nargs="?",
|
||||
)
|
||||
dest = sync.add_mutually_exclusive_group(required=False)
|
||||
# TODO: remove in Spack 0.21
|
||||
dest.add_argument(
|
||||
"--dest-directory",
|
||||
metavar="DIRECTORY",
|
||||
dest="dest_mirror_flag",
|
||||
type=arguments.mirror_directory,
|
||||
help="Destination mirror as a local file path (deprecated)",
|
||||
)
|
||||
# TODO: remove in Spack 0.21
|
||||
dest.add_argument(
|
||||
"--dest-mirror-name",
|
||||
metavar="MIRROR_NAME",
|
||||
type=arguments.mirror_name,
|
||||
dest="dest_mirror_flag",
|
||||
help="Name of the destination mirror (deprecated)",
|
||||
)
|
||||
# TODO: remove in Spack 0.21
|
||||
dest.add_argument(
|
||||
"--dest-mirror-url",
|
||||
metavar="MIRROR_URL",
|
||||
dest="dest_mirror_flag",
|
||||
type=arguments.mirror_url,
|
||||
help="URL of the destination mirror (deprecated)",
|
||||
)
|
||||
# TODO: only support this in 0.21
|
||||
dest.add_argument(
|
||||
sync.add_argument(
|
||||
"dest_mirror",
|
||||
metavar="destination mirror",
|
||||
type=arguments.mirror_name_or_url,
|
||||
help="Destination mirror name, path, or URL",
|
||||
nargs="?",
|
||||
)
|
||||
sync.set_defaults(func=sync_fn)
|
||||
|
||||
@@ -344,39 +246,8 @@ def setup_parser(subparser):
|
||||
update_index = subparsers.add_parser(
|
||||
"update-index", aliases=["rebuild-index"], help=update_index_fn.__doc__
|
||||
)
|
||||
update_index_out = update_index.add_mutually_exclusive_group(required=True)
|
||||
# TODO: remove in Spack 0.21
|
||||
update_index_out.add_argument(
|
||||
"-d",
|
||||
"--directory",
|
||||
metavar="directory",
|
||||
dest="mirror_flag",
|
||||
type=arguments.mirror_directory,
|
||||
help="local directory where buildcaches will be written (deprecated)",
|
||||
)
|
||||
# TODO: remove in Spack 0.21
|
||||
update_index_out.add_argument(
|
||||
"-m",
|
||||
"--mirror-name",
|
||||
metavar="mirror-name",
|
||||
dest="mirror_flag",
|
||||
type=arguments.mirror_name,
|
||||
help="name of the mirror where buildcaches will be written (deprecated)",
|
||||
)
|
||||
# TODO: remove in Spack 0.21
|
||||
update_index_out.add_argument(
|
||||
"--mirror-url",
|
||||
metavar="mirror-url",
|
||||
dest="mirror_flag",
|
||||
type=arguments.mirror_url,
|
||||
help="URL of the mirror where buildcaches will be written (deprecated)",
|
||||
)
|
||||
# TODO: require from Spack 0.21
|
||||
update_index_out.add_argument(
|
||||
"mirror",
|
||||
type=arguments.mirror_name_or_url,
|
||||
help="Destination mirror name, path, or URL",
|
||||
nargs="?",
|
||||
update_index.add_argument(
|
||||
"mirror", type=arguments.mirror_name_or_url, help="Destination mirror name, path, or URL"
|
||||
)
|
||||
update_index.add_argument(
|
||||
"-k",
|
||||
@@ -436,32 +307,12 @@ def _concrete_spec_from_args(args):
|
||||
|
||||
def push_fn(args):
|
||||
"""create a binary package and push it to a mirror"""
|
||||
if args.mirror_flag:
|
||||
mirror = args.mirror_flag
|
||||
elif not args.mirror:
|
||||
raise ValueError("No mirror provided")
|
||||
else:
|
||||
mirror = arguments.mirror_name_or_url(args.mirror)
|
||||
|
||||
if args.mirror_flag:
|
||||
tty.warn(
|
||||
"Using flags to specify mirrors is deprecated and will be removed in "
|
||||
"Spack 0.21, use positional arguments instead."
|
||||
)
|
||||
|
||||
if args.rel:
|
||||
tty.warn("The --rel flag is deprecated and will be removed in Spack 0.21")
|
||||
|
||||
# TODO: remove this in 0.21. If we have mirror_flag, the first
|
||||
# spec is in the positional mirror arg due to argparse limitations.
|
||||
input_specs = args.specs
|
||||
if args.mirror_flag and args.mirror:
|
||||
input_specs.insert(0, args.mirror)
|
||||
mirror = arguments.mirror_name_or_url(args.mirror)
|
||||
|
||||
url = mirror.push_url
|
||||
|
||||
specs = bindist.specs_to_be_packaged(
|
||||
_matching_specs(input_specs, args.spec_file),
|
||||
_matching_specs(args.specs, args.spec_file),
|
||||
root="package" in args.things_to_install,
|
||||
dependencies="dependencies" in args.things_to_install,
|
||||
)
|
||||
@@ -486,7 +337,6 @@ def push_fn(args):
|
||||
url,
|
||||
bindist.PushOptions(
|
||||
force=args.force,
|
||||
relative=args.rel,
|
||||
unsigned=args.unsigned,
|
||||
allow_root=args.allow_root,
|
||||
key=args.key,
|
||||
@@ -524,9 +374,6 @@ def install_fn(args):
|
||||
if not args.specs:
|
||||
tty.die("a spec argument is required to install from a buildcache")
|
||||
|
||||
if args.allow_root:
|
||||
tty.warn("The --allow-root flag is deprecated and will be removed in Spack 0.21")
|
||||
|
||||
query = bindist.BinaryCacheQuery(all_architectures=args.otherarch)
|
||||
matches = spack.store.find(args.specs, multiple=args.multiple, query_fn=query)
|
||||
for match in matches:
|
||||
@@ -710,21 +557,8 @@ def sync_fn(args):
|
||||
manifest_copy(glob.glob(args.manifest_glob))
|
||||
return 0
|
||||
|
||||
# If no manifest_glob, require a source and dest mirror.
|
||||
# TODO: Simplify in Spack 0.21
|
||||
if not (args.src_mirror_flag or args.src_mirror) or not (
|
||||
args.dest_mirror_flag or args.dest_mirror
|
||||
):
|
||||
raise ValueError("Source and destination mirror are required.")
|
||||
|
||||
if args.src_mirror_flag or args.dest_mirror_flag:
|
||||
tty.warn(
|
||||
"Using flags to specify mirrors is deprecated and will be removed in "
|
||||
"Spack 0.21, use positional arguments instead."
|
||||
)
|
||||
|
||||
src_mirror = args.src_mirror_flag if args.src_mirror_flag else args.src_mirror
|
||||
dest_mirror = args.dest_mirror_flag if args.dest_mirror_flag else args.dest_mirror
|
||||
src_mirror = args.src_mirror
|
||||
dest_mirror = args.dest_mirror
|
||||
|
||||
src_mirror_url = src_mirror.fetch_url
|
||||
dest_mirror_url = dest_mirror.push_url
|
||||
@@ -803,13 +637,7 @@ def update_index(mirror: spack.mirror.Mirror, update_keys=False):
|
||||
|
||||
def update_index_fn(args):
|
||||
"""Update a buildcache index."""
|
||||
if args.mirror_flag:
|
||||
tty.warn(
|
||||
"Using flags to specify mirrors is deprecated and will be removed in "
|
||||
"Spack 0.21, use positional arguments instead."
|
||||
)
|
||||
mirror = args.mirror_flag if args.mirror_flag else args.mirror
|
||||
update_index(mirror, update_keys=args.keys)
|
||||
update_index(args.mirror, update_keys=args.keys)
|
||||
|
||||
|
||||
def buildcache(parser, args):
|
||||
|
@@ -228,7 +228,7 @@ def ci_reindex(args):
|
||||
Use the active, gitlab-enabled environment to rebuild the buildcache
|
||||
index for the associated mirror."""
|
||||
env = spack.cmd.require_active_env(cmd_name="ci rebuild-index")
|
||||
yaml_root = ev.config_dict(env.manifest)
|
||||
yaml_root = env.manifest[ev.TOP_LEVEL_KEY]
|
||||
|
||||
if "mirrors" not in yaml_root or len(yaml_root["mirrors"].values()) < 1:
|
||||
tty.die("spack ci rebuild-index requires an env containing a mirror")
|
||||
|
@@ -349,7 +349,7 @@ def install_status():
|
||||
"-I",
|
||||
"--install-status",
|
||||
action="store_true",
|
||||
default=False,
|
||||
default=True,
|
||||
help="show install status of packages. packages can be: "
|
||||
"installed [+], missing and needed by an installed package [-], "
|
||||
"installed in and upstream instance [^], "
|
||||
@@ -357,6 +357,17 @@ def install_status():
|
||||
)
|
||||
|
||||
|
||||
@arg
|
||||
def no_install_status():
|
||||
return Args(
|
||||
"--no-install-status",
|
||||
dest="install_status",
|
||||
action="store_false",
|
||||
default=True,
|
||||
help="do not show install status annotations",
|
||||
)
|
||||
|
||||
|
||||
@arg
|
||||
def no_checksum():
|
||||
return Args(
|
||||
|
@@ -715,7 +715,7 @@ def __call__(self, stage, url):
|
||||
output = tar("--exclude=*/*/*", "-tf", stage.archive_file, output=str)
|
||||
except ProcessError:
|
||||
output = ""
|
||||
lines = output.split("\n")
|
||||
lines = output.splitlines()
|
||||
|
||||
# Determine the build system based on the files contained
|
||||
# in the archive.
|
||||
|
@@ -44,7 +44,11 @@ def setup_parser(subparser):
|
||||
)
|
||||
|
||||
# Below are arguments w.r.t. spec display (like spack spec)
|
||||
arguments.add_common_arguments(subparser, ["long", "very_long", "install_status"])
|
||||
arguments.add_common_arguments(subparser, ["long", "very_long"])
|
||||
|
||||
install_status_group = subparser.add_mutually_exclusive_group()
|
||||
arguments.add_common_arguments(install_status_group, ["install_status", "no_install_status"])
|
||||
|
||||
subparser.add_argument(
|
||||
"-y",
|
||||
"--yaml",
|
||||
|
@@ -31,7 +31,11 @@ def setup_parser(subparser):
|
||||
for further documentation regarding the spec syntax, see:
|
||||
spack help --spec
|
||||
"""
|
||||
arguments.add_common_arguments(subparser, ["long", "very_long", "install_status"])
|
||||
arguments.add_common_arguments(subparser, ["long", "very_long"])
|
||||
|
||||
install_status_group = subparser.add_mutually_exclusive_group()
|
||||
arguments.add_common_arguments(install_status_group, ["install_status", "no_install_status"])
|
||||
|
||||
format_group = subparser.add_mutually_exclusive_group()
|
||||
format_group.add_argument(
|
||||
"-y",
|
||||
|
@@ -151,7 +151,11 @@ def setup_custom_environment(self, pkg, env):
|
||||
arch = arch.replace("-", "_")
|
||||
# vcvars can target specific sdk versions, force it to pick up concretized sdk
|
||||
# version, if needed by spec
|
||||
sdk_ver = "" if "win-sdk" not in pkg.spec else pkg.spec["win-sdk"].version.string + ".0"
|
||||
sdk_ver = (
|
||||
""
|
||||
if "win-sdk" not in pkg.spec or pkg.name == "win-sdk"
|
||||
else pkg.spec["win-sdk"].version.string + ".0"
|
||||
)
|
||||
# provide vcvars with msvc version selected by concretization,
|
||||
# not whatever it happens to pick up on the system (highest available version)
|
||||
out = subprocess.check_output( # novermin
|
||||
|
@@ -81,7 +81,7 @@
|
||||
# Same as above, but including keys for environments
|
||||
# this allows us to unify config reading between configs and environments
|
||||
all_schemas = copy.deepcopy(section_schemas)
|
||||
all_schemas.update(dict((key, spack.schema.env.schema) for key in spack.schema.env.keys))
|
||||
all_schemas.update({spack.schema.env.TOP_LEVEL_KEY: spack.schema.env.schema})
|
||||
|
||||
#: Path to the default configuration
|
||||
configuration_defaults_path = ("defaults", os.path.join(spack.paths.etc_path, "defaults"))
|
||||
@@ -111,14 +111,6 @@
|
||||
overrides_base_name = "overrides-"
|
||||
|
||||
|
||||
def first_existing(dictionary, keys):
|
||||
"""Get the value of the first key in keys that is in the dictionary."""
|
||||
try:
|
||||
return next(k for k in keys if k in dictionary)
|
||||
except StopIteration:
|
||||
raise KeyError("None of %s is in dict!" % str(keys))
|
||||
|
||||
|
||||
class ConfigScope(object):
|
||||
"""This class represents a configuration scope.
|
||||
|
||||
@@ -838,12 +830,10 @@ def _config():
|
||||
|
||||
def add_from_file(filename, scope=None):
|
||||
"""Add updates to a config from a filename"""
|
||||
import spack.environment as ev
|
||||
|
||||
# Get file as config dict
|
||||
# Extract internal attributes, if we are dealing with an environment
|
||||
data = read_config_file(filename)
|
||||
if any(k in data for k in spack.schema.env.keys):
|
||||
data = ev.config_dict(data)
|
||||
if spack.schema.env.TOP_LEVEL_KEY in data:
|
||||
data = data[spack.schema.env.TOP_LEVEL_KEY]
|
||||
|
||||
# update all sections from config dict
|
||||
# We have to iterate on keys to keep overrides from the file
|
||||
|
@@ -37,7 +37,7 @@ def validate(configuration_file):
|
||||
config = syaml.load(f)
|
||||
|
||||
# Ensure we have a "container" attribute with sensible defaults set
|
||||
env_dict = ev.config_dict(config)
|
||||
env_dict = config[ev.TOP_LEVEL_KEY]
|
||||
env_dict.setdefault(
|
||||
"container", {"format": "docker", "images": {"os": "ubuntu:22.04", "spack": "develop"}}
|
||||
)
|
||||
|
@@ -50,7 +50,7 @@ def create(configuration, last_phase=None):
|
||||
configuration (dict): how to generate the current recipe
|
||||
last_phase (str): last phase to be printed or None to print them all
|
||||
"""
|
||||
name = ev.config_dict(configuration)["container"]["format"]
|
||||
name = configuration[ev.TOP_LEVEL_KEY]["container"]["format"]
|
||||
return _writer_factory[name](configuration, last_phase)
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ class PathContext(tengine.Context):
|
||||
template_name: Optional[str] = None
|
||||
|
||||
def __init__(self, config, last_phase):
|
||||
self.config = ev.config_dict(config)
|
||||
self.config = config[ev.TOP_LEVEL_KEY]
|
||||
self.container_config = self.config["container"]
|
||||
|
||||
# Operating system tag as written in the configuration file
|
||||
|
@@ -164,7 +164,10 @@ def entries_to_specs(entries):
|
||||
continue
|
||||
parent_spec = spec_dict[entry["hash"]]
|
||||
dep_spec = spec_dict[dep_hash]
|
||||
parent_spec._add_dependency(dep_spec, deptypes=deptypes)
|
||||
parent_spec._add_dependency(dep_spec, deptypes=deptypes, virtuals=())
|
||||
|
||||
for spec in spec_dict.values():
|
||||
spack.spec.reconstruct_virtuals_on_edges(spec)
|
||||
|
||||
return spec_dict
|
||||
|
||||
|
@@ -60,7 +60,7 @@
|
||||
# DB version. This is stuck in the DB file to track changes in format.
|
||||
# Increment by one when the database format changes.
|
||||
# Versions before 5 were not integers.
|
||||
_db_version = vn.Version("6")
|
||||
_db_version = vn.Version("7")
|
||||
|
||||
# For any version combinations here, skip reindex when upgrading.
|
||||
# Reindexing can take considerable time and is not always necessary.
|
||||
@@ -72,6 +72,7 @@
|
||||
# version is saved to disk the first time the DB is written.
|
||||
(vn.Version("0.9.3"), vn.Version("5")),
|
||||
(vn.Version("5"), vn.Version("6")),
|
||||
(vn.Version("6"), vn.Version("7")),
|
||||
]
|
||||
|
||||
# Default timeout for spack database locks in seconds or None (no timeout).
|
||||
@@ -105,7 +106,11 @@
|
||||
|
||||
|
||||
def reader(version):
|
||||
reader_cls = {vn.Version("5"): spack.spec.SpecfileV1, vn.Version("6"): spack.spec.SpecfileV3}
|
||||
reader_cls = {
|
||||
vn.Version("5"): spack.spec.SpecfileV1,
|
||||
vn.Version("6"): spack.spec.SpecfileV3,
|
||||
vn.Version("7"): spack.spec.SpecfileV4,
|
||||
}
|
||||
return reader_cls[version]
|
||||
|
||||
|
||||
@@ -743,7 +748,9 @@ def _assign_dependencies(self, spec_reader, hash_key, installs, data):
|
||||
spec_node_dict = spec_node_dict[spec.name]
|
||||
if "dependencies" in spec_node_dict:
|
||||
yaml_deps = spec_node_dict["dependencies"]
|
||||
for dname, dhash, dtypes, _ in spec_reader.read_specfile_dep_specs(yaml_deps):
|
||||
for dname, dhash, dtypes, _, virtuals in spec_reader.read_specfile_dep_specs(
|
||||
yaml_deps
|
||||
):
|
||||
# It is important that we always check upstream installations
|
||||
# in the same order, and that we always check the local
|
||||
# installation first: if a downstream Spack installs a package
|
||||
@@ -766,7 +773,7 @@ def _assign_dependencies(self, spec_reader, hash_key, installs, data):
|
||||
tty.warn(msg)
|
||||
continue
|
||||
|
||||
spec._add_dependency(child, deptypes=dtypes)
|
||||
spec._add_dependency(child, deptypes=dtypes, virtuals=virtuals)
|
||||
|
||||
def _read_from_file(self, filename):
|
||||
"""Fill database from file, do not maintain old data.
|
||||
@@ -1172,7 +1179,7 @@ def _add(
|
||||
for dep in spec.edges_to_dependencies(deptype=_tracked_deps):
|
||||
dkey = dep.spec.dag_hash()
|
||||
upstream, record = self.query_by_spec_hash(dkey)
|
||||
new_spec._add_dependency(record.spec, deptypes=dep.deptypes)
|
||||
new_spec._add_dependency(record.spec, deptypes=dep.deptypes, virtuals=dep.virtuals)
|
||||
if not upstream:
|
||||
record.ref_count += 1
|
||||
|
||||
|
@@ -112,15 +112,10 @@ def path_to_dict(search_paths):
|
||||
# Reverse order of search directories so that a lib in the first
|
||||
# entry overrides later entries
|
||||
for search_path in reversed(search_paths):
|
||||
try:
|
||||
for lib in os.listdir(search_path):
|
||||
lib_path = os.path.join(search_path, lib)
|
||||
if llnl.util.filesystem.is_readable_file(lib_path):
|
||||
path_to_lib[lib_path] = lib
|
||||
except OSError as e:
|
||||
msg = f"cannot scan '{search_path}' for external software: {str(e)}"
|
||||
llnl.util.tty.debug(msg)
|
||||
|
||||
for lib in os.listdir(search_path):
|
||||
lib_path = os.path.join(search_path, lib)
|
||||
if llnl.util.filesystem.is_readable_file(lib_path):
|
||||
path_to_lib[lib_path] = lib
|
||||
return path_to_lib
|
||||
|
||||
|
||||
|
@@ -337,6 +337,7 @@
|
||||
"""
|
||||
|
||||
from .environment import (
|
||||
TOP_LEVEL_KEY,
|
||||
Environment,
|
||||
SpackEnvironmentError,
|
||||
SpackEnvironmentViewError,
|
||||
@@ -345,7 +346,6 @@
|
||||
active_environment,
|
||||
all_environment_names,
|
||||
all_environments,
|
||||
config_dict,
|
||||
create,
|
||||
create_in_dir,
|
||||
deactivate,
|
||||
@@ -369,6 +369,7 @@
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"TOP_LEVEL_KEY",
|
||||
"Environment",
|
||||
"SpackEnvironmentError",
|
||||
"SpackEnvironmentViewError",
|
||||
@@ -377,7 +378,6 @@
|
||||
"active_environment",
|
||||
"all_environment_names",
|
||||
"all_environments",
|
||||
"config_dict",
|
||||
"create",
|
||||
"create_in_dir",
|
||||
"deactivate",
|
||||
|
@@ -39,6 +39,7 @@
|
||||
import spack.stage
|
||||
import spack.store
|
||||
import spack.subprocess_context
|
||||
import spack.traverse
|
||||
import spack.user_environment as uenv
|
||||
import spack.util.cpus
|
||||
import spack.util.environment
|
||||
@@ -50,9 +51,9 @@
|
||||
import spack.util.spack_yaml as syaml
|
||||
import spack.util.url
|
||||
import spack.version
|
||||
from spack import traverse
|
||||
from spack.filesystem_view import SimpleFilesystemView, inverse_view_func_parser, view_func_parser
|
||||
from spack.installer import PackageInstaller
|
||||
from spack.schema.env import TOP_LEVEL_KEY
|
||||
from spack.spec import Spec
|
||||
from spack.spec_list import InvalidSpecConstraintError, SpecList
|
||||
from spack.util.path import substitute_path_variables
|
||||
@@ -124,7 +125,7 @@ def default_manifest_yaml():
|
||||
valid_environment_name_re = r"^\w[\w-]*$"
|
||||
|
||||
#: version of the lockfile format. Must increase monotonically.
|
||||
lockfile_format_version = 4
|
||||
lockfile_format_version = 5
|
||||
|
||||
|
||||
READER_CLS = {
|
||||
@@ -132,6 +133,7 @@ def default_manifest_yaml():
|
||||
2: spack.spec.SpecfileV1,
|
||||
3: spack.spec.SpecfileV2,
|
||||
4: spack.spec.SpecfileV3,
|
||||
5: spack.spec.SpecfileV4,
|
||||
}
|
||||
|
||||
|
||||
@@ -361,19 +363,6 @@ def ensure_env_root_path_exists():
|
||||
fs.mkdirp(env_root_path())
|
||||
|
||||
|
||||
def config_dict(yaml_data):
|
||||
"""Get the configuration scope section out of an spack.yaml"""
|
||||
# TODO (env:): Remove env: as a possible top level keyword in v0.21
|
||||
key = spack.config.first_existing(yaml_data, spack.schema.env.keys)
|
||||
if key == "env":
|
||||
msg = (
|
||||
"using 'env:' as a top-level attribute of a Spack environment is deprecated and "
|
||||
"will be removed in Spack v0.21. Please use 'spack:' instead."
|
||||
)
|
||||
warnings.warn(msg)
|
||||
return yaml_data[key]
|
||||
|
||||
|
||||
def all_environment_names():
|
||||
"""List the names of environments that currently exist."""
|
||||
# just return empty if the env path does not exist. A read-only
|
||||
@@ -437,6 +426,32 @@ def _is_dev_spec_and_has_changed(spec):
|
||||
return mtime > record.installation_time
|
||||
|
||||
|
||||
def _spec_needs_overwrite(spec, changed_dev_specs):
|
||||
"""Check whether the current spec needs to be overwritten because either it has
|
||||
changed itself or one of its dependencies have changed
|
||||
"""
|
||||
# if it's not installed, we don't need to overwrite it
|
||||
if not spec.installed:
|
||||
return False
|
||||
|
||||
# If the spec itself has changed this is a trivial decision
|
||||
if spec in changed_dev_specs:
|
||||
return True
|
||||
|
||||
# if spec and all deps aren't dev builds, we don't need to overwrite it
|
||||
if not any(spec.satisfies(c) for c in ("dev_path=*", "^dev_path=*")):
|
||||
return False
|
||||
|
||||
# If any dep needs overwrite, or any dep is missing and is a dev build then
|
||||
# overwrite this package
|
||||
if any(
|
||||
((not dep.installed) and dep.satisfies("dev_path=*"))
|
||||
or _spec_needs_overwrite(dep, changed_dev_specs)
|
||||
for dep in spec.traverse(root=False)
|
||||
):
|
||||
return True
|
||||
|
||||
|
||||
def _error_on_nonempty_view_dir(new_root):
|
||||
"""Defensively error when the target view path already exists and is not an
|
||||
empty directory. This usually happens when the view symlink was removed, but
|
||||
@@ -621,16 +636,18 @@ def specs_for_view(self, concretized_root_specs):
|
||||
From the list of concretized user specs in the environment, flatten
|
||||
the dags, and filter selected, installed specs, remove duplicates on dag hash.
|
||||
"""
|
||||
dag_hash = lambda spec: spec.dag_hash()
|
||||
|
||||
# With deps, requires traversal
|
||||
if self.link == "all" or self.link == "run":
|
||||
deptype = ("run") if self.link == "run" else ("link", "run")
|
||||
specs = list(
|
||||
traverse.traverse_nodes(
|
||||
concretized_root_specs, deptype=deptype, key=traverse.by_dag_hash
|
||||
spack.traverse.traverse_nodes(
|
||||
concretized_root_specs, deptype=deptype, key=dag_hash
|
||||
)
|
||||
)
|
||||
else:
|
||||
specs = list(dedupe(concretized_root_specs, key=traverse.by_dag_hash))
|
||||
specs = list(dedupe(concretized_root_specs, key=dag_hash))
|
||||
|
||||
# Filter selected, installed specs
|
||||
with spack.store.db.read_transaction():
|
||||
@@ -793,8 +810,8 @@ def write_transaction(self):
|
||||
def _construct_state_from_manifest(self):
|
||||
"""Read manifest file and set up user specs."""
|
||||
self.spec_lists = collections.OrderedDict()
|
||||
|
||||
for item in config_dict(self.manifest).get("definitions", []):
|
||||
env_configuration = self.manifest[TOP_LEVEL_KEY]
|
||||
for item in env_configuration.get("definitions", []):
|
||||
entry = copy.deepcopy(item)
|
||||
when = _eval_conditional(entry.pop("when", "True"))
|
||||
assert len(entry) == 1
|
||||
@@ -806,13 +823,13 @@ def _construct_state_from_manifest(self):
|
||||
else:
|
||||
self.spec_lists[name] = user_specs
|
||||
|
||||
spec_list = config_dict(self.manifest).get(user_speclist_name, [])
|
||||
spec_list = env_configuration.get(user_speclist_name, [])
|
||||
user_specs = SpecList(
|
||||
user_speclist_name, [s for s in spec_list if s], self.spec_lists.copy()
|
||||
)
|
||||
self.spec_lists[user_speclist_name] = user_specs
|
||||
|
||||
enable_view = config_dict(self.manifest).get("view")
|
||||
enable_view = env_configuration.get("view")
|
||||
# enable_view can be boolean, string, or None
|
||||
if enable_view is True or enable_view is None:
|
||||
self.views = {default_view_name: ViewDescriptor(self.path, self.view_path_default)}
|
||||
@@ -827,14 +844,11 @@ def _construct_state_from_manifest(self):
|
||||
else:
|
||||
self.views = {}
|
||||
|
||||
# Retrieve the current concretization strategy
|
||||
configuration = config_dict(self.manifest)
|
||||
|
||||
# Retrieve unification scheme for the concretizer
|
||||
self.unify = spack.config.get("concretizer:unify", False)
|
||||
|
||||
# Retrieve dev-build packages:
|
||||
self.dev_specs = copy.deepcopy(configuration.get("develop", {}))
|
||||
self.dev_specs = copy.deepcopy(env_configuration.get("develop", {}))
|
||||
for name, entry in self.dev_specs.items():
|
||||
# spec must include a concrete version
|
||||
assert Spec(entry["spec"]).versions.concrete_range_as_version
|
||||
@@ -954,7 +968,7 @@ def included_config_scopes(self):
|
||||
|
||||
# load config scopes added via 'include:', in reverse so that
|
||||
# highest-precedence scopes are last.
|
||||
includes = config_dict(self.manifest).get("include", [])
|
||||
includes = self.manifest[TOP_LEVEL_KEY].get("include", [])
|
||||
missing = []
|
||||
for i, config_path in enumerate(reversed(includes)):
|
||||
# allow paths to contain spack config/environment variables, etc.
|
||||
@@ -1047,10 +1061,7 @@ def env_file_config_scope(self):
|
||||
"""Get the configuration scope for the environment's manifest file."""
|
||||
config_name = self.env_file_config_scope_name()
|
||||
return spack.config.SingleFileScope(
|
||||
config_name,
|
||||
self.manifest_path,
|
||||
spack.schema.env.schema,
|
||||
[spack.config.first_existing(self.manifest, spack.schema.env.keys)],
|
||||
config_name, self.manifest_path, spack.schema.env.schema, [TOP_LEVEL_KEY]
|
||||
)
|
||||
|
||||
def config_scopes(self):
|
||||
@@ -1538,12 +1549,13 @@ def _concretize_separately(self, tests=False):
|
||||
for h in self.specs_by_hash:
|
||||
current_spec, computed_spec = self.specs_by_hash[h], by_hash[h]
|
||||
for node in computed_spec.traverse():
|
||||
test_deps = node.dependencies(deptype="test")
|
||||
for test_dependency in test_deps:
|
||||
test_edges = node.edges_to_dependencies(deptype="test")
|
||||
for current_edge in test_edges:
|
||||
test_dependency = current_edge.spec
|
||||
if test_dependency in current_spec[node.name]:
|
||||
continue
|
||||
current_spec[node.name].add_dependency_edge(
|
||||
test_dependency.copy(), deptypes="test"
|
||||
test_dependency.copy(), deptypes="test", virtuals=current_edge.virtuals
|
||||
)
|
||||
|
||||
results = [
|
||||
@@ -1796,29 +1808,17 @@ def _add_concrete_spec(self, spec, concrete, new=True):
|
||||
self.specs_by_hash[h] = concrete
|
||||
|
||||
def _get_overwrite_specs(self):
|
||||
# Find all dev specs that were modified.
|
||||
changed_dev_specs = [
|
||||
s
|
||||
for s in traverse.traverse_nodes(
|
||||
self.concrete_roots(), order="breadth", key=traverse.by_dag_hash
|
||||
)
|
||||
if _is_dev_spec_and_has_changed(s)
|
||||
]
|
||||
# Collect all specs in the environment first before checking which ones
|
||||
# to rebuild to avoid checking the same specs multiple times
|
||||
specs_to_check = set()
|
||||
for dag_hash in self.concretized_order:
|
||||
root_spec = self.specs_by_hash[dag_hash]
|
||||
specs_to_check.update(root_spec.traverse(root=True))
|
||||
|
||||
changed_dev_specs = set(s for s in specs_to_check if _is_dev_spec_and_has_changed(s))
|
||||
|
||||
# Collect their hashes, and the hashes of their installed parents.
|
||||
# Notice: with order=breadth all changed dev specs are at depth 0,
|
||||
# even if they occur as parents of one another.
|
||||
return [
|
||||
spec.dag_hash()
|
||||
for depth, spec in traverse.traverse_nodes(
|
||||
changed_dev_specs,
|
||||
root=True,
|
||||
order="breadth",
|
||||
depth=True,
|
||||
direction="parents",
|
||||
key=traverse.by_dag_hash,
|
||||
)
|
||||
if depth == 0 or spec.installed
|
||||
s.dag_hash() for s in specs_to_check if _spec_needs_overwrite(s, changed_dev_specs)
|
||||
]
|
||||
|
||||
def _install_log_links(self, spec):
|
||||
@@ -1925,7 +1925,7 @@ def install_specs(self, specs=None, **install_args):
|
||||
def all_specs(self):
|
||||
"""Return all specs, even those a user spec would shadow."""
|
||||
roots = [self.specs_by_hash[h] for h in self.concretized_order]
|
||||
specs = [s for s in traverse.traverse_nodes(roots, key=traverse.by_dag_hash)]
|
||||
specs = [s for s in spack.traverse.traverse_nodes(roots, lambda s: s.dag_hash())]
|
||||
specs.sort()
|
||||
return specs
|
||||
|
||||
@@ -1971,18 +1971,13 @@ def concrete_roots(self):
|
||||
roots *without* associated user spec"""
|
||||
return [root for _, root in self.concretized_specs()]
|
||||
|
||||
def get_by_hash(self, dag_hash: str) -> List[Spec]:
|
||||
# If it's not a partial hash prefix we can early exit
|
||||
early_exit = len(dag_hash) == 32
|
||||
matches = []
|
||||
for spec in traverse.traverse_nodes(
|
||||
self.concrete_roots(), key=traverse.by_dag_hash, order="breadth"
|
||||
):
|
||||
def get_by_hash(self, dag_hash):
|
||||
matches = {}
|
||||
roots = [self.specs_by_hash[h] for h in self.concretized_order]
|
||||
for spec in spack.traverse.traverse_nodes(roots, key=lambda s: s.dag_hash()):
|
||||
if spec.dag_hash().startswith(dag_hash):
|
||||
matches.append(spec)
|
||||
if early_exit:
|
||||
break
|
||||
return matches
|
||||
matches[spec.dag_hash()] = spec
|
||||
return list(matches.values())
|
||||
|
||||
def get_one_by_hash(self, dag_hash):
|
||||
"""Returns the single spec from the environment which matches the
|
||||
@@ -1994,14 +1989,11 @@ def get_one_by_hash(self, dag_hash):
|
||||
|
||||
def all_matching_specs(self, *specs: spack.spec.Spec) -> List[Spec]:
|
||||
"""Returns all concretized specs in the environment satisfying any of the input specs"""
|
||||
# Look up abstract hashes ahead of time, to avoid O(n^2) traversal.
|
||||
specs = [s.lookup_hash() for s in specs]
|
||||
|
||||
# Avoid double lookup by directly calling _satisfies.
|
||||
key = lambda s: s.dag_hash()
|
||||
return [
|
||||
s
|
||||
for s in traverse.traverse_nodes(self.concrete_roots(), key=traverse.by_dag_hash)
|
||||
if any(s._satisfies(t) for t in specs)
|
||||
for s in spack.traverse.traverse_nodes(self.concrete_roots(), key=key)
|
||||
if any(s.satisfies(t) for t in specs)
|
||||
]
|
||||
|
||||
@spack.repo.autospec
|
||||
@@ -2025,9 +2017,9 @@ def matching_spec(self, spec):
|
||||
env_root_to_user = {root.dag_hash(): user for user, root in self.concretized_specs()}
|
||||
root_matches, dep_matches = [], []
|
||||
|
||||
for env_spec in traverse.traverse_nodes(
|
||||
for env_spec in spack.traverse.traverse_nodes(
|
||||
specs=[root for _, root in self.concretized_specs()],
|
||||
key=traverse.by_dag_hash,
|
||||
key=lambda s: s.dag_hash(),
|
||||
order="breadth",
|
||||
):
|
||||
if not env_spec.satisfies(spec):
|
||||
@@ -2101,8 +2093,8 @@ def _get_environment_specs(self, recurse_dependencies=True):
|
||||
|
||||
if recurse_dependencies:
|
||||
specs.extend(
|
||||
traverse.traverse_nodes(
|
||||
specs, root=False, deptype=("link", "run"), key=traverse.by_dag_hash
|
||||
spack.traverse.traverse_nodes(
|
||||
specs, root=False, deptype=("link", "run"), key=lambda s: s.dag_hash()
|
||||
)
|
||||
)
|
||||
|
||||
@@ -2111,7 +2103,9 @@ def _get_environment_specs(self, recurse_dependencies=True):
|
||||
def _to_lockfile_dict(self):
|
||||
"""Create a dictionary to store a lockfile for this environment."""
|
||||
concrete_specs = {}
|
||||
for s in traverse.traverse_nodes(self.specs_by_hash.values(), key=traverse.by_dag_hash):
|
||||
for s in spack.traverse.traverse_nodes(
|
||||
self.specs_by_hash.values(), key=lambda s: s.dag_hash()
|
||||
):
|
||||
spec_dict = s.node_dict_with_hashes(hash=ht.dag_hash)
|
||||
# Assumes no legacy formats, since this was just created.
|
||||
spec_dict[ht.dag_hash.name] = s.dag_hash()
|
||||
@@ -2192,9 +2186,9 @@ def _read_lockfile_dict(self, d):
|
||||
# and add them to the spec
|
||||
for lockfile_key, node_dict in json_specs_by_hash.items():
|
||||
name, data = reader.name_and_data(node_dict)
|
||||
for _, dep_hash, deptypes, _ in reader.dependencies_from_node_dict(data):
|
||||
for _, dep_hash, deptypes, _, virtuals in reader.dependencies_from_node_dict(data):
|
||||
specs_by_hash[lockfile_key]._add_dependency(
|
||||
specs_by_hash[dep_hash], deptypes=deptypes
|
||||
specs_by_hash[dep_hash], deptypes=deptypes, virtuals=virtuals
|
||||
)
|
||||
|
||||
# Traverse the root specs one at a time in the order they appear.
|
||||
@@ -2268,7 +2262,7 @@ def ensure_env_directory_exists(self, dot_env: bool = False) -> None:
|
||||
|
||||
def update_environment_repository(self) -> None:
|
||||
"""Updates the repository associated with the environment."""
|
||||
for spec in traverse.traverse_nodes(self.new_specs):
|
||||
for spec in spack.traverse.traverse_nodes(self.new_specs):
|
||||
if not spec.concrete:
|
||||
raise ValueError("specs passed to environment.write() must be concrete!")
|
||||
|
||||
@@ -2386,17 +2380,28 @@ def _concretize_from_constraints(spec_constraints, tests=False):
|
||||
# Accept only valid constraints from list and concretize spec
|
||||
# Get the named spec even if out of order
|
||||
root_spec = [s for s in spec_constraints if s.name]
|
||||
if len(root_spec) != 1:
|
||||
m = "The constraints %s are not a valid spec " % spec_constraints
|
||||
m += "concretization target. all specs must have a single name "
|
||||
m += "constraint for concretization."
|
||||
raise InvalidSpecConstraintError(m)
|
||||
spec_constraints.remove(root_spec[0])
|
||||
hash_spec = [s for s in spec_constraints if s.abstract_hash]
|
||||
|
||||
error_message = "The constraints %s are not a valid spec " % spec_constraints
|
||||
error_message += "concretization target. all specs must have a single name "
|
||||
error_message += "constraint for concretization."
|
||||
|
||||
if len(root_spec) > 1:
|
||||
raise InvalidSpecConstraintError(error_message)
|
||||
|
||||
if len(root_spec) < 1:
|
||||
if len(hash_spec) < 1:
|
||||
raise InvalidSpecConstraintError(error_message)
|
||||
|
||||
if root_spec:
|
||||
spec_constraints.remove(root_spec[0])
|
||||
|
||||
root_spec = root_spec[0] if root_spec else Spec()
|
||||
|
||||
invalid_constraints = []
|
||||
while True:
|
||||
# Attach all anonymous constraints to one named spec
|
||||
s = root_spec[0].copy()
|
||||
s = root_spec.copy()
|
||||
for c in spec_constraints:
|
||||
if c not in invalid_constraints:
|
||||
s.constrain(c)
|
||||
@@ -2674,8 +2679,8 @@ def add_user_spec(self, user_spec: str) -> None:
|
||||
Args:
|
||||
user_spec: user spec to be appended
|
||||
"""
|
||||
config_dict(self.pristine_yaml_content).setdefault("specs", []).append(user_spec)
|
||||
config_dict(self.yaml_content).setdefault("specs", []).append(user_spec)
|
||||
self.pristine_configuration.setdefault("specs", []).append(user_spec)
|
||||
self.configuration.setdefault("specs", []).append(user_spec)
|
||||
self.changed = True
|
||||
|
||||
def remove_user_spec(self, user_spec: str) -> None:
|
||||
@@ -2688,8 +2693,8 @@ def remove_user_spec(self, user_spec: str) -> None:
|
||||
SpackEnvironmentError: when the user spec is not in the list
|
||||
"""
|
||||
try:
|
||||
config_dict(self.pristine_yaml_content)["specs"].remove(user_spec)
|
||||
config_dict(self.yaml_content)["specs"].remove(user_spec)
|
||||
self.pristine_configuration["specs"].remove(user_spec)
|
||||
self.configuration["specs"].remove(user_spec)
|
||||
except ValueError as e:
|
||||
msg = f"cannot remove {user_spec} from {self}, no such spec exists"
|
||||
raise SpackEnvironmentError(msg) from e
|
||||
@@ -2706,8 +2711,8 @@ def override_user_spec(self, user_spec: str, idx: int) -> None:
|
||||
SpackEnvironmentError: when the user spec cannot be overridden
|
||||
"""
|
||||
try:
|
||||
config_dict(self.pristine_yaml_content)["specs"][idx] = user_spec
|
||||
config_dict(self.yaml_content)["specs"][idx] = user_spec
|
||||
self.pristine_configuration["specs"][idx] = user_spec
|
||||
self.configuration["specs"][idx] = user_spec
|
||||
except ValueError as e:
|
||||
msg = f"cannot override {user_spec} from {self}"
|
||||
raise SpackEnvironmentError(msg) from e
|
||||
@@ -2723,14 +2728,14 @@ def add_definition(self, user_spec: str, list_name: str) -> None:
|
||||
Raises:
|
||||
SpackEnvironmentError: is no valid definition exists already
|
||||
"""
|
||||
defs = config_dict(self.pristine_yaml_content).get("definitions", [])
|
||||
defs = self.pristine_configuration.get("definitions", [])
|
||||
msg = f"cannot add {user_spec} to the '{list_name}' definition, no valid list exists"
|
||||
|
||||
for idx, item in self._iterate_on_definitions(defs, list_name=list_name, err_msg=msg):
|
||||
item[list_name].append(user_spec)
|
||||
break
|
||||
|
||||
config_dict(self.yaml_content)["definitions"][idx][list_name].append(user_spec)
|
||||
self.configuration["definitions"][idx][list_name].append(user_spec)
|
||||
self.changed = True
|
||||
|
||||
def remove_definition(self, user_spec: str, list_name: str) -> None:
|
||||
@@ -2744,7 +2749,7 @@ def remove_definition(self, user_spec: str, list_name: str) -> None:
|
||||
SpackEnvironmentError: if the user spec cannot be removed from the list,
|
||||
or the list does not exist
|
||||
"""
|
||||
defs = config_dict(self.pristine_yaml_content).get("definitions", [])
|
||||
defs = self.pristine_configuration.get("definitions", [])
|
||||
msg = (
|
||||
f"cannot remove {user_spec} from the '{list_name}' definition, "
|
||||
f"no valid list exists"
|
||||
@@ -2757,7 +2762,7 @@ def remove_definition(self, user_spec: str, list_name: str) -> None:
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
config_dict(self.yaml_content)["definitions"][idx][list_name].remove(user_spec)
|
||||
self.configuration["definitions"][idx][list_name].remove(user_spec)
|
||||
self.changed = True
|
||||
|
||||
def override_definition(self, user_spec: str, *, override: str, list_name: str) -> None:
|
||||
@@ -2772,7 +2777,7 @@ def override_definition(self, user_spec: str, *, override: str, list_name: str)
|
||||
Raises:
|
||||
SpackEnvironmentError: if the user spec cannot be overridden
|
||||
"""
|
||||
defs = config_dict(self.pristine_yaml_content).get("definitions", [])
|
||||
defs = self.pristine_configuration.get("definitions", [])
|
||||
msg = f"cannot override {user_spec} with {override} in the '{list_name}' definition"
|
||||
|
||||
for idx, item in self._iterate_on_definitions(defs, list_name=list_name, err_msg=msg):
|
||||
@@ -2783,7 +2788,7 @@ def override_definition(self, user_spec: str, *, override: str, list_name: str)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
config_dict(self.yaml_content)["definitions"][idx][list_name][sub_index] = override
|
||||
self.configuration["definitions"][idx][list_name][sub_index] = override
|
||||
self.changed = True
|
||||
|
||||
def _iterate_on_definitions(self, definitions, *, list_name, err_msg):
|
||||
@@ -2815,24 +2820,24 @@ def set_default_view(self, view: Union[bool, str, pathlib.Path, Dict[str, str]])
|
||||
True the default view is used for the environment, if False there's no view.
|
||||
"""
|
||||
if isinstance(view, dict):
|
||||
config_dict(self.pristine_yaml_content)["view"][default_view_name].update(view)
|
||||
config_dict(self.yaml_content)["view"][default_view_name].update(view)
|
||||
self.pristine_configuration["view"][default_view_name].update(view)
|
||||
self.configuration["view"][default_view_name].update(view)
|
||||
self.changed = True
|
||||
return
|
||||
|
||||
if not isinstance(view, bool):
|
||||
view = str(view)
|
||||
|
||||
config_dict(self.pristine_yaml_content)["view"] = view
|
||||
config_dict(self.yaml_content)["view"] = view
|
||||
self.pristine_configuration["view"] = view
|
||||
self.configuration["view"] = view
|
||||
self.changed = True
|
||||
|
||||
def remove_default_view(self) -> None:
|
||||
"""Removes the default view from the manifest file"""
|
||||
view_data = config_dict(self.pristine_yaml_content).get("view")
|
||||
view_data = self.pristine_configuration.get("view")
|
||||
if isinstance(view_data, collections.abc.Mapping):
|
||||
config_dict(self.pristine_yaml_content)["view"].pop(default_view_name)
|
||||
config_dict(self.yaml_content)["view"].pop(default_view_name)
|
||||
self.pristine_configuration["view"].pop(default_view_name)
|
||||
self.configuration["view"].pop(default_view_name)
|
||||
self.changed = True
|
||||
return
|
||||
|
||||
@@ -2849,12 +2854,10 @@ def add_develop_spec(self, pkg_name: str, entry: Dict[str, str]) -> None:
|
||||
if entry["path"] == pkg_name:
|
||||
entry.pop("path")
|
||||
|
||||
config_dict(self.pristine_yaml_content).setdefault("develop", {}).setdefault(
|
||||
pkg_name, {}
|
||||
).update(entry)
|
||||
config_dict(self.yaml_content).setdefault("develop", {}).setdefault(pkg_name, {}).update(
|
||||
self.pristine_configuration.setdefault("develop", {}).setdefault(pkg_name, {}).update(
|
||||
entry
|
||||
)
|
||||
self.configuration.setdefault("develop", {}).setdefault(pkg_name, {}).update(entry)
|
||||
self.changed = True
|
||||
|
||||
def remove_develop_spec(self, pkg_name: str) -> None:
|
||||
@@ -2867,11 +2870,11 @@ def remove_develop_spec(self, pkg_name: str) -> None:
|
||||
SpackEnvironmentError: if there is nothing to remove
|
||||
"""
|
||||
try:
|
||||
del config_dict(self.pristine_yaml_content)["develop"][pkg_name]
|
||||
del self.pristine_configuration["develop"][pkg_name]
|
||||
except KeyError as e:
|
||||
msg = f"cannot remove '{pkg_name}' from develop specs in {self}, entry does not exist"
|
||||
raise SpackEnvironmentError(msg) from e
|
||||
del config_dict(self.yaml_content)["develop"][pkg_name]
|
||||
del self.configuration["develop"][pkg_name]
|
||||
self.changed = True
|
||||
|
||||
def absolutify_dev_paths(self, init_file_dir: Union[str, pathlib.Path]) -> None:
|
||||
@@ -2882,11 +2885,11 @@ def absolutify_dev_paths(self, init_file_dir: Union[str, pathlib.Path]) -> None:
|
||||
init_file_dir: directory with the "spack.yaml" used to initialize the environment.
|
||||
"""
|
||||
init_file_dir = pathlib.Path(init_file_dir).absolute()
|
||||
for _, entry in config_dict(self.pristine_yaml_content).get("develop", {}).items():
|
||||
for _, entry in self.pristine_configuration.get("develop", {}).items():
|
||||
expanded_path = os.path.normpath(str(init_file_dir / entry["path"]))
|
||||
entry["path"] = str(expanded_path)
|
||||
|
||||
for _, entry in config_dict(self.yaml_content).get("develop", {}).items():
|
||||
for _, entry in self.configuration.get("develop", {}).items():
|
||||
expanded_path = os.path.normpath(str(init_file_dir / entry["path"]))
|
||||
entry["path"] = str(expanded_path)
|
||||
self.changed = True
|
||||
@@ -2900,6 +2903,16 @@ def flush(self) -> None:
|
||||
_write_yaml(self.pristine_yaml_content, f)
|
||||
self.changed = False
|
||||
|
||||
@property
|
||||
def pristine_configuration(self):
|
||||
"""Return the dictionaries in the pristine YAML, without the top level attribute"""
|
||||
return self.pristine_yaml_content[TOP_LEVEL_KEY]
|
||||
|
||||
@property
|
||||
def configuration(self):
|
||||
"""Return the dictionaries in the YAML, without the top level attribute"""
|
||||
return self.yaml_content[TOP_LEVEL_KEY]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.yaml_content)
|
||||
|
||||
|
@@ -763,11 +763,7 @@ def version_from_git(git_exe):
|
||||
@property
|
||||
def git(self):
|
||||
if not self._git:
|
||||
try:
|
||||
self._git = spack.util.git.git(required=True)
|
||||
except CommandNotFoundError as exc:
|
||||
tty.error(str(exc))
|
||||
raise
|
||||
self._git = spack.util.git.git()
|
||||
|
||||
# Disable advice for a quieter fetch
|
||||
# https://github.com/git/git/blob/master/Documentation/RelNotes/1.7.2.txt
|
||||
|
@@ -544,6 +544,7 @@ def _static_edges(specs, deptype):
|
||||
spack.spec.Spec(parent_name),
|
||||
spack.spec.Spec(dependency_name),
|
||||
deptypes=deptype,
|
||||
virtuals=(),
|
||||
)
|
||||
|
||||
|
||||
|
@@ -231,7 +231,9 @@ def _packages_needed_to_bootstrap_compiler(compiler, architecture, pkgs):
|
||||
dep.concretize()
|
||||
# mark compiler as depended-on by the packages that use it
|
||||
for pkg in pkgs:
|
||||
dep._dependents.add(spack.spec.DependencySpec(pkg.spec, dep, deptypes=("build",)))
|
||||
dep._dependents.add(
|
||||
spack.spec.DependencySpec(pkg.spec, dep, deptypes=("build",), virtuals=())
|
||||
)
|
||||
packages = [(s.package, False) for s in dep.traverse(order="post", root=False)]
|
||||
|
||||
packages.append((dep.package, True))
|
||||
@@ -2436,11 +2438,10 @@ def get_deptypes(self, pkg):
|
||||
else:
|
||||
cache_only = self.install_args.get("dependencies_cache_only")
|
||||
|
||||
# Include build dependencies if pkg is going to be built from sources, or
|
||||
# if build deps are explicitly requested.
|
||||
if include_build_deps or not (
|
||||
cache_only or pkg.spec.installed and not pkg.spec.dag_hash() in self.overwrite
|
||||
):
|
||||
# Include build dependencies if pkg is not installed and cache_only
|
||||
# is False, or if build depdencies are explicitly called for
|
||||
# by include_build_deps.
|
||||
if include_build_deps or not (cache_only or pkg.spec.installed):
|
||||
deptypes.append("build")
|
||||
if self.run_tests(pkg):
|
||||
deptypes.append("test")
|
||||
|
@@ -393,7 +393,7 @@ class BaseConfiguration(object):
|
||||
querying easier. It needs to be sub-classed for specific module types.
|
||||
"""
|
||||
|
||||
default_projections = {"all": "{name}-{version}-{compiler.name}-{compiler.version}"}
|
||||
default_projections = {"all": "{name}/{version}-{compiler.name}-{compiler.version}"}
|
||||
|
||||
def __init__(self, spec, module_set_name, explicit=None):
|
||||
# Module where type(self) is defined
|
||||
@@ -671,12 +671,6 @@ def configure_options(self):
|
||||
# the configure option section
|
||||
return None
|
||||
|
||||
def modification_needs_formatting(self, modification):
|
||||
"""Returns True if environment modification entry needs to be formatted."""
|
||||
return (
|
||||
not isinstance(modification, (spack.util.environment.SetEnv)) or not modification.raw
|
||||
)
|
||||
|
||||
@tengine.context_property
|
||||
@memoized
|
||||
def environment_modifications(self):
|
||||
@@ -740,12 +734,11 @@ def environment_modifications(self):
|
||||
_check_tokens_are_valid(x.name, message=msg)
|
||||
# Transform them
|
||||
x.name = spec.format(x.name, transform=transform)
|
||||
if self.modification_needs_formatting(x):
|
||||
try:
|
||||
# Not every command has a value
|
||||
x.value = spec.format(x.value)
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
# Not every command has a value
|
||||
x.value = spec.format(x.value)
|
||||
except AttributeError:
|
||||
pass
|
||||
x.name = str(x.name).replace("-", "_")
|
||||
|
||||
return [(type(x).__name__, x) for x in env if x.name not in exclude]
|
||||
|
@@ -108,6 +108,5 @@
|
||||
# These are just here for editor support; they will be replaced when the build env
|
||||
# is set up.
|
||||
make = MakeExecutable("make", jobs=1)
|
||||
gmake = MakeExecutable("gmake", jobs=1)
|
||||
ninja = MakeExecutable("ninja", jobs=1)
|
||||
configure = Executable(join_path(".", "configure"))
|
||||
|
@@ -291,7 +291,7 @@ def next_spec(
|
||||
if root_spec.concrete:
|
||||
raise spack.spec.RedundantSpecError(root_spec, "^" + str(dependency))
|
||||
|
||||
root_spec._add_dependency(dependency, deptypes=())
|
||||
root_spec._add_dependency(dependency, deptypes=(), virtuals=())
|
||||
|
||||
else:
|
||||
break
|
||||
|
@@ -292,8 +292,8 @@ def from_json(stream, repository):
|
||||
index.providers = _transform(
|
||||
providers,
|
||||
lambda vpkg, plist: (
|
||||
spack.spec.SpecfileV3.from_node_dict(vpkg),
|
||||
set(spack.spec.SpecfileV3.from_node_dict(p) for p in plist),
|
||||
spack.spec.SpecfileV4.from_node_dict(vpkg),
|
||||
set(spack.spec.SpecfileV4.from_node_dict(p) for p in plist),
|
||||
),
|
||||
)
|
||||
return index
|
||||
|
@@ -6,7 +6,6 @@
|
||||
import itertools
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
from collections import OrderedDict
|
||||
|
||||
import macholib.mach_o
|
||||
@@ -356,13 +355,7 @@ def _set_elf_rpaths(target, rpaths):
|
||||
# Join the paths using ':' as a separator
|
||||
rpaths_str = ":".join(rpaths)
|
||||
|
||||
# If we're relocating patchelf itself, make a copy and use it
|
||||
bak_path = None
|
||||
if target.endswith("/bin/patchelf"):
|
||||
bak_path = target + ".bak"
|
||||
shutil.copy(target, bak_path)
|
||||
|
||||
patchelf, output = executable.Executable(bak_path or _patchelf()), None
|
||||
patchelf, output = executable.Executable(_patchelf()), None
|
||||
try:
|
||||
# TODO: revisit the use of --force-rpath as it might be conditional
|
||||
# TODO: if we want to support setting RUNPATH from binary packages
|
||||
@@ -371,9 +364,6 @@ def _set_elf_rpaths(target, rpaths):
|
||||
except executable.ProcessError as e:
|
||||
msg = "patchelf --force-rpath --set-rpath {0} failed with error {1}"
|
||||
tty.warn(msg.format(target, e))
|
||||
finally:
|
||||
if bak_path and os.path.exists(bak_path):
|
||||
os.remove(bak_path)
|
||||
return output
|
||||
|
||||
|
||||
@@ -686,7 +676,7 @@ def is_relocatable(spec):
|
||||
Raises:
|
||||
ValueError: if the spec is not installed
|
||||
"""
|
||||
if not spec.installed:
|
||||
if not spec.install_status():
|
||||
raise ValueError("spec is not installed [{0}]".format(str(spec)))
|
||||
|
||||
if spec.external or spec.virtual:
|
||||
|
@@ -24,7 +24,7 @@
|
||||
import traceback
|
||||
import types
|
||||
import uuid
|
||||
from typing import Any, Dict, List, Union
|
||||
from typing import Dict, Union
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
import llnl.util.lang
|
||||
@@ -424,7 +424,7 @@ def _create_new_cache(self) -> Dict[str, os.stat_result]:
|
||||
def last_mtime(self):
|
||||
return max(sinfo.st_mtime for sinfo in self._packages_to_stats.values())
|
||||
|
||||
def modified_since(self, since: float) -> List[str]:
|
||||
def modified_since(self, since):
|
||||
return [name for name, sinfo in self._packages_to_stats.items() if sinfo.st_mtime > since]
|
||||
|
||||
def __getitem__(self, item):
|
||||
@@ -550,34 +550,35 @@ class RepoIndex(object):
|
||||
when they're needed.
|
||||
|
||||
``Indexers`` should be added to the ``RepoIndex`` using
|
||||
``add_indexer(name, indexer)``, and they should support the interface
|
||||
``add_index(name, indexer)``, and they should support the interface
|
||||
defined by ``Indexer``, so that the ``RepoIndex`` can read, generate,
|
||||
and update stored indices.
|
||||
|
||||
Generated indexes are accessed by name via ``__getitem__()``."""
|
||||
Generated indexes are accessed by name via ``__getitem__()``.
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
package_checker: FastPackageChecker,
|
||||
namespace: str,
|
||||
cache: spack.util.file_cache.FileCache,
|
||||
):
|
||||
"""
|
||||
|
||||
def __init__(self, package_checker, namespace, cache):
|
||||
self.checker = package_checker
|
||||
self.packages_path = self.checker.packages_path
|
||||
if sys.platform == "win32":
|
||||
self.packages_path = spack.util.path.convert_to_posix_path(self.packages_path)
|
||||
self.namespace = namespace
|
||||
|
||||
self.indexers: Dict[str, Indexer] = {}
|
||||
self.indexes: Dict[str, Any] = {}
|
||||
self.indexers = {}
|
||||
self.indexes = {}
|
||||
self.cache = cache
|
||||
|
||||
def add_indexer(self, name: str, indexer: Indexer):
|
||||
def add_indexer(self, name, indexer):
|
||||
"""Add an indexer to the repo index.
|
||||
|
||||
Arguments:
|
||||
name: name of this indexer
|
||||
indexer: object implementing the ``Indexer`` interface"""
|
||||
name (str): name of this indexer
|
||||
|
||||
indexer (object): an object that supports create(), read(),
|
||||
write(), and get_index() operations
|
||||
|
||||
"""
|
||||
self.indexers[name] = indexer
|
||||
|
||||
def __getitem__(self, name):
|
||||
@@ -598,15 +599,17 @@ def _build_all_indexes(self):
|
||||
because the main bottleneck here is loading all the packages. It
|
||||
can take tens of seconds to regenerate sequentially, and we'd
|
||||
rather only pay that cost once rather than on several
|
||||
invocations."""
|
||||
invocations.
|
||||
|
||||
"""
|
||||
for name, indexer in self.indexers.items():
|
||||
self.indexes[name] = self._build_index(name, indexer)
|
||||
|
||||
def _build_index(self, name: str, indexer: Indexer):
|
||||
def _build_index(self, name, indexer):
|
||||
"""Determine which packages need an update, and update indexes."""
|
||||
|
||||
# Filename of the provider index cache (we assume they're all json)
|
||||
cache_filename = f"{name}/{self.namespace}-index.json"
|
||||
cache_filename = "{0}/{1}-index.json".format(name, self.namespace)
|
||||
|
||||
# Compute which packages needs to be updated in the cache
|
||||
index_mtime = self.cache.mtime(cache_filename)
|
||||
@@ -630,7 +633,8 @@ def _build_index(self, name: str, indexer: Indexer):
|
||||
needs_update = self.checker.modified_since(new_index_mtime)
|
||||
|
||||
for pkg_name in needs_update:
|
||||
indexer.update(f"{self.namespace}.{pkg_name}")
|
||||
namespaced_name = "%s.%s" % (self.namespace, pkg_name)
|
||||
indexer.update(namespaced_name)
|
||||
|
||||
indexer.write(new)
|
||||
|
||||
@@ -1235,7 +1239,7 @@ def get_pkg_class(self, pkg_name):
|
||||
try:
|
||||
module = importlib.import_module(fullname)
|
||||
except ImportError:
|
||||
raise UnknownPackageError(pkg_name)
|
||||
raise UnknownPackageError(fullname)
|
||||
except Exception as e:
|
||||
msg = f"cannot load package '{pkg_name}' from the '{self.namespace}' repository: {e}"
|
||||
raise RepoError(msg) from e
|
||||
|
@@ -209,7 +209,7 @@ def update(data):
|
||||
# Warn if deprecated section is still in the environment
|
||||
ci_env = ev.active_environment()
|
||||
if ci_env:
|
||||
env_config = ev.config_dict(ci_env.manifest)
|
||||
env_config = ci_env.manifest[ev.TOP_LEVEL_KEY]
|
||||
if "gitlab-ci" in env_config:
|
||||
tty.die("Error: `gitlab-ci` section detected with `ci`, these are not compatible")
|
||||
|
||||
|
@@ -15,8 +15,8 @@
|
||||
import spack.schema.packages
|
||||
import spack.schema.projections
|
||||
|
||||
#: legal first keys in the schema
|
||||
keys = ("spack", "env")
|
||||
#: Top level key in a manifest file
|
||||
TOP_LEVEL_KEY = "spack"
|
||||
|
||||
spec_list_schema = {
|
||||
"type": "array",
|
||||
@@ -47,8 +47,8 @@
|
||||
"title": "Spack environment file schema",
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
"patternProperties": {
|
||||
"^env|spack$": {
|
||||
"properties": {
|
||||
"spack": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"additionalProperties": False,
|
||||
|
@@ -2500,10 +2500,15 @@ def depends_on(self, pkg, dep, type):
|
||||
assert len(dependencies) < 2, msg
|
||||
|
||||
if not dependencies:
|
||||
self._specs[pkg].add_dependency_edge(self._specs[dep], deptypes=(type,))
|
||||
self._specs[pkg].add_dependency_edge(self._specs[dep], deptypes=(type,), virtuals=())
|
||||
else:
|
||||
# TODO: This assumes that each solve unifies dependencies
|
||||
dependencies[0].add_type(type)
|
||||
dependencies[0].update_deptypes(deptypes=(type,))
|
||||
|
||||
def virtual_on_edge(self, pkg, provider, virtual):
|
||||
dependencies = self._specs[pkg].edges_to_dependencies(name=provider)
|
||||
assert len(dependencies) == 1
|
||||
dependencies[0].update_virtuals((virtual,))
|
||||
|
||||
def reorder_flags(self):
|
||||
"""Order compiler flags on specs in predefined order.
|
||||
@@ -2581,6 +2586,8 @@ def sort_fn(function_tuple):
|
||||
return (-2, 0)
|
||||
elif name == "external_spec_selected":
|
||||
return (0, 0) # note out of order so this goes last
|
||||
elif name == "virtual_on_edge":
|
||||
return (1, 0)
|
||||
else:
|
||||
return (-1, 0)
|
||||
|
||||
|
@@ -300,6 +300,11 @@ attr("depends_on", Package, Provider, Type)
|
||||
provider(Provider, Virtual),
|
||||
not external(Package).
|
||||
|
||||
attr("virtual_on_edge", Package, Provider, Virtual)
|
||||
:- dependency_holds(Package, Virtual, Type),
|
||||
provider(Provider, Virtual),
|
||||
not external(Package).
|
||||
|
||||
% dependencies on virtuals also imply that the virtual is a virtual node
|
||||
attr("virtual_node", Virtual)
|
||||
:- dependency_holds(Package, Virtual, Type),
|
||||
|
@@ -50,7 +50,6 @@
|
||||
"""
|
||||
import collections
|
||||
import collections.abc
|
||||
import enum
|
||||
import io
|
||||
import itertools
|
||||
import os
|
||||
@@ -171,17 +170,7 @@
|
||||
)
|
||||
|
||||
#: specfile format version. Must increase monotonically
|
||||
SPECFILE_FORMAT_VERSION = 3
|
||||
|
||||
|
||||
# InstallStatus is used to map install statuses to symbols for display
|
||||
# Options are artificially disjoint for dispay purposes
|
||||
class InstallStatus(enum.Enum):
|
||||
installed = "@g{[+]} "
|
||||
upstream = "@g{[^]} "
|
||||
external = "@g{[e]} "
|
||||
absent = "@K{ - } "
|
||||
missing = "@r{[-]} "
|
||||
SPECFILE_FORMAT_VERSION = 4
|
||||
|
||||
|
||||
def colorize_spec(spec):
|
||||
@@ -725,47 +714,81 @@ class DependencySpec:
|
||||
parent: starting node of the edge
|
||||
spec: ending node of the edge.
|
||||
deptypes: list of strings, representing dependency relationships.
|
||||
virtuals: virtual packages provided from child to parent node.
|
||||
"""
|
||||
|
||||
__slots__ = "parent", "spec", "deptypes"
|
||||
__slots__ = "parent", "spec", "parameters"
|
||||
|
||||
def __init__(self, parent: "Spec", spec: "Spec", *, deptypes: dp.DependencyArgument):
|
||||
def __init__(
|
||||
self,
|
||||
parent: "Spec",
|
||||
spec: "Spec",
|
||||
*,
|
||||
deptypes: dp.DependencyArgument,
|
||||
virtuals: Tuple[str, ...],
|
||||
):
|
||||
self.parent = parent
|
||||
self.spec = spec
|
||||
self.deptypes = dp.canonical_deptype(deptypes)
|
||||
self.parameters = {
|
||||
"deptypes": dp.canonical_deptype(deptypes),
|
||||
"virtuals": tuple(sorted(set(virtuals))),
|
||||
}
|
||||
|
||||
def update_deptypes(self, deptypes: dp.DependencyArgument) -> bool:
|
||||
deptypes = set(deptypes)
|
||||
deptypes.update(self.deptypes)
|
||||
deptypes = tuple(sorted(deptypes))
|
||||
changed = self.deptypes != deptypes
|
||||
@property
|
||||
def deptypes(self) -> Tuple[str, ...]:
|
||||
return self.parameters["deptypes"]
|
||||
|
||||
self.deptypes = deptypes
|
||||
return changed
|
||||
@property
|
||||
def virtuals(self) -> Tuple[str, ...]:
|
||||
return self.parameters["virtuals"]
|
||||
|
||||
def _update_edge_multivalued_property(
|
||||
self, property_name: str, value: Tuple[str, ...]
|
||||
) -> bool:
|
||||
current = self.parameters[property_name]
|
||||
update = set(current) | set(value)
|
||||
update = tuple(sorted(update))
|
||||
changed = current != update
|
||||
|
||||
if not changed:
|
||||
return False
|
||||
|
||||
self.parameters[property_name] = update
|
||||
return True
|
||||
|
||||
def update_deptypes(self, deptypes: Tuple[str, ...]) -> bool:
|
||||
"""Update the current dependency types"""
|
||||
return self._update_edge_multivalued_property("deptypes", deptypes)
|
||||
|
||||
def update_virtuals(self, virtuals: Tuple[str, ...]) -> bool:
|
||||
"""Update the list of provided virtuals"""
|
||||
return self._update_edge_multivalued_property("virtuals", virtuals)
|
||||
|
||||
def copy(self) -> "DependencySpec":
|
||||
return DependencySpec(self.parent, self.spec, deptypes=self.deptypes)
|
||||
|
||||
def add_type(self, type: dp.DependencyArgument):
|
||||
self.deptypes = dp.canonical_deptype(self.deptypes + dp.canonical_deptype(type))
|
||||
"""Return a copy of this edge"""
|
||||
return DependencySpec(
|
||||
self.parent, self.spec, deptypes=self.deptypes, virtuals=self.virtuals
|
||||
)
|
||||
|
||||
def _cmp_iter(self):
|
||||
yield self.parent.name if self.parent else None
|
||||
yield self.spec.name if self.spec else None
|
||||
yield self.deptypes
|
||||
yield self.virtuals
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "%s %s--> %s" % (
|
||||
self.parent.name if self.parent else None,
|
||||
self.deptypes,
|
||||
self.spec.name if self.spec else None,
|
||||
)
|
||||
parent = self.parent.name if self.parent else None
|
||||
child = self.spec.name if self.spec else None
|
||||
return f"{parent} {self.deptypes}[virtuals={','.join(self.virtuals)}] --> {child}"
|
||||
|
||||
def canonical(self) -> Tuple[str, str, Tuple[str, ...]]:
|
||||
return self.parent.dag_hash(), self.spec.dag_hash(), self.deptypes
|
||||
def canonical(self) -> Tuple[str, str, Tuple[str, ...], Tuple[str, ...]]:
|
||||
return self.parent.dag_hash(), self.spec.dag_hash(), self.deptypes, self.virtuals
|
||||
|
||||
def flip(self) -> "DependencySpec":
|
||||
return DependencySpec(parent=self.spec, spec=self.parent, deptypes=self.deptypes)
|
||||
"""Flip the dependency, and drop virtual information"""
|
||||
return DependencySpec(
|
||||
parent=self.spec, spec=self.parent, deptypes=self.deptypes, virtuals=()
|
||||
)
|
||||
|
||||
|
||||
class CompilerFlag(str):
|
||||
@@ -1586,10 +1609,12 @@ def _set_compiler(self, compiler):
|
||||
)
|
||||
self.compiler = compiler
|
||||
|
||||
def _add_dependency(self, spec: "Spec", *, deptypes: dp.DependencyArgument):
|
||||
def _add_dependency(
|
||||
self, spec: "Spec", *, deptypes: dp.DependencyArgument, virtuals: Tuple[str, ...]
|
||||
):
|
||||
"""Called by the parser to add another spec as a dependency."""
|
||||
if spec.name not in self._dependencies or not spec.name:
|
||||
self.add_dependency_edge(spec, deptypes=deptypes)
|
||||
self.add_dependency_edge(spec, deptypes=deptypes, virtuals=virtuals)
|
||||
return
|
||||
|
||||
# Keep the intersection of constraints when a dependency is added
|
||||
@@ -1607,34 +1632,58 @@ def _add_dependency(self, spec: "Spec", *, deptypes: dp.DependencyArgument):
|
||||
"Cannot depend on incompatible specs '%s' and '%s'" % (dspec.spec, spec)
|
||||
)
|
||||
|
||||
def add_dependency_edge(self, dependency_spec: "Spec", *, deptypes: dp.DependencyArgument):
|
||||
def add_dependency_edge(
|
||||
self,
|
||||
dependency_spec: "Spec",
|
||||
*,
|
||||
deptypes: dp.DependencyArgument,
|
||||
virtuals: Tuple[str, ...],
|
||||
):
|
||||
"""Add a dependency edge to this spec.
|
||||
|
||||
Args:
|
||||
dependency_spec: spec of the dependency
|
||||
deptypes: dependency types for this edge
|
||||
virtuals: virtuals provided by this edge
|
||||
"""
|
||||
deptypes = dp.canonical_deptype(deptypes)
|
||||
|
||||
# Check if we need to update edges that are already present
|
||||
selected = self._dependencies.select(child=dependency_spec.name)
|
||||
for edge in selected:
|
||||
has_errors, details = False, []
|
||||
msg = f"cannot update the edge from {edge.parent.name} to {edge.spec.name}"
|
||||
if any(d in edge.deptypes for d in deptypes):
|
||||
msg = (
|
||||
'cannot add a dependency on "{0.spec}" of {1} type '
|
||||
'when the "{0.parent}" has the edge {0!s} already'
|
||||
has_errors = True
|
||||
details.append(
|
||||
(
|
||||
f"{edge.parent.name} has already an edge matching any"
|
||||
f" of these types {str(deptypes)}"
|
||||
)
|
||||
)
|
||||
raise spack.error.SpecError(msg.format(edge, deptypes))
|
||||
|
||||
if any(v in edge.virtuals for v in virtuals):
|
||||
has_errors = True
|
||||
details.append(
|
||||
(
|
||||
f"{edge.parent.name} has already an edge matching any"
|
||||
f" of these virtuals {str(virtuals)}"
|
||||
)
|
||||
)
|
||||
|
||||
if has_errors:
|
||||
raise spack.error.SpecError(msg, "\n".join(details))
|
||||
|
||||
for edge in selected:
|
||||
if id(dependency_spec) == id(edge.spec):
|
||||
# If we are here, it means the edge object was previously added to
|
||||
# both the parent and the child. When we update this object they'll
|
||||
# both see the deptype modification.
|
||||
edge.add_type(deptypes)
|
||||
edge.update_deptypes(deptypes=deptypes)
|
||||
edge.update_virtuals(virtuals=virtuals)
|
||||
return
|
||||
|
||||
edge = DependencySpec(self, dependency_spec, deptypes=deptypes)
|
||||
edge = DependencySpec(self, dependency_spec, deptypes=deptypes, virtuals=virtuals)
|
||||
self._dependencies.add(edge)
|
||||
dependency_spec._dependents.add(edge)
|
||||
|
||||
@@ -1907,12 +1956,12 @@ def lookup_hash(self):
|
||||
for node in self.traverse(root=False):
|
||||
if node.abstract_hash:
|
||||
new = node._lookup_hash()
|
||||
spec._add_dependency(new, deptypes=())
|
||||
spec._add_dependency(new, deptypes=(), virtuals=())
|
||||
|
||||
# reattach nodes that were not otherwise satisfied by new dependencies
|
||||
for node in self.traverse(root=False):
|
||||
if not any(n._satisfies(node) for n in spec.traverse()):
|
||||
spec._add_dependency(node.copy(), deptypes=())
|
||||
spec._add_dependency(node.copy(), deptypes=(), virtuals=())
|
||||
|
||||
return spec
|
||||
|
||||
@@ -2047,8 +2096,14 @@ def to_node_dict(self, hash=ht.dag_hash):
|
||||
name_tuple = ("name", name)
|
||||
for dspec in edges_for_name:
|
||||
hash_tuple = (hash.name, dspec.spec._cached_hash(hash))
|
||||
type_tuple = ("type", sorted(str(s) for s in dspec.deptypes))
|
||||
deps_list.append(syaml.syaml_dict([name_tuple, hash_tuple, type_tuple]))
|
||||
parameters_tuple = (
|
||||
"parameters",
|
||||
syaml.syaml_dict(
|
||||
(key, dspec.parameters[key]) for key in sorted(dspec.parameters)
|
||||
),
|
||||
)
|
||||
ordered_entries = [name_tuple, hash_tuple, parameters_tuple]
|
||||
deps_list.append(syaml.syaml_dict(ordered_entries))
|
||||
d["dependencies"] = deps_list
|
||||
|
||||
# Name is included in case this is replacing a virtual.
|
||||
@@ -2372,7 +2427,7 @@ def spec_and_dependency_types(s):
|
||||
dag_node, dependency_types = spec_and_dependency_types(s)
|
||||
|
||||
dependency_spec = spec_builder({dag_node: s_dependencies})
|
||||
spec._add_dependency(dependency_spec, deptypes=dependency_types)
|
||||
spec._add_dependency(dependency_spec, deptypes=dependency_types, virtuals=())
|
||||
|
||||
return spec
|
||||
|
||||
@@ -2390,8 +2445,10 @@ def from_dict(data):
|
||||
spec = SpecfileV1.load(data)
|
||||
elif int(data["spec"]["_meta"]["version"]) == 2:
|
||||
spec = SpecfileV2.load(data)
|
||||
else:
|
||||
elif int(data["spec"]["_meta"]["version"]) == 3:
|
||||
spec = SpecfileV3.load(data)
|
||||
else:
|
||||
spec = SpecfileV4.load(data)
|
||||
|
||||
# Any git version should
|
||||
for s in spec.traverse():
|
||||
@@ -2540,6 +2597,7 @@ def _concretize_helper(self, concretizer, presets=None, visited=None):
|
||||
def _replace_with(self, concrete):
|
||||
"""Replace this virtual spec with a concrete spec."""
|
||||
assert self.virtual
|
||||
virtuals = (self.name,)
|
||||
for dep_spec in itertools.chain.from_iterable(self._dependents.values()):
|
||||
dependent = dep_spec.parent
|
||||
deptypes = dep_spec.deptypes
|
||||
@@ -2550,7 +2608,11 @@ def _replace_with(self, concrete):
|
||||
|
||||
# add the replacement, unless it is already a dep of dependent.
|
||||
if concrete.name not in dependent._dependencies:
|
||||
dependent._add_dependency(concrete, deptypes=deptypes)
|
||||
dependent._add_dependency(concrete, deptypes=deptypes, virtuals=virtuals)
|
||||
else:
|
||||
dependent.edges_to_dependencies(name=concrete.name)[0].update_virtuals(
|
||||
virtuals=virtuals
|
||||
)
|
||||
|
||||
def _expand_virtual_packages(self, concretizer):
|
||||
"""Find virtual packages in this spec, replace them with providers,
|
||||
@@ -3191,7 +3253,9 @@ def _merge_dependency(self, dependency, visited, spec_deps, provider_index, test
|
||||
|
||||
# If it's a virtual dependency, try to find an existing
|
||||
# provider in the spec, and merge that.
|
||||
virtuals = ()
|
||||
if spack.repo.path.is_virtual_safe(dep.name):
|
||||
virtuals = (dep.name,)
|
||||
visited.add(dep.name)
|
||||
provider = self._find_provider(dep, provider_index)
|
||||
if provider:
|
||||
@@ -3247,7 +3311,7 @@ def _merge_dependency(self, dependency, visited, spec_deps, provider_index, test
|
||||
# Add merged spec to my deps and recurse
|
||||
spec_dependency = spec_deps[dep.name]
|
||||
if dep.name not in self._dependencies:
|
||||
self._add_dependency(spec_dependency, deptypes=dependency.type)
|
||||
self._add_dependency(spec_dependency, deptypes=dependency.type, virtuals=virtuals)
|
||||
|
||||
changed |= spec_dependency._normalize_helper(visited, spec_deps, provider_index, tests)
|
||||
return changed
|
||||
@@ -3584,15 +3648,20 @@ def _constrain_dependencies(self, other):
|
||||
changed |= edges_from_name[0].update_deptypes(
|
||||
other._dependencies[name][0].deptypes
|
||||
)
|
||||
changed |= edges_from_name[0].update_virtuals(
|
||||
other._dependencies[name][0].virtuals
|
||||
)
|
||||
|
||||
# Update with additional constraints from other spec
|
||||
# operate on direct dependencies only, because a concrete dep
|
||||
# represented by hash may have structure that needs to be preserved
|
||||
for name in other.direct_dep_difference(self):
|
||||
dep_spec_copy = other._get_dependency(name)
|
||||
dep_copy = dep_spec_copy.spec
|
||||
deptypes = dep_spec_copy.deptypes
|
||||
self._add_dependency(dep_copy.copy(), deptypes=deptypes)
|
||||
self._add_dependency(
|
||||
dep_spec_copy.spec.copy(),
|
||||
deptypes=dep_spec_copy.deptypes,
|
||||
virtuals=dep_spec_copy.virtuals,
|
||||
)
|
||||
changed = True
|
||||
|
||||
return changed
|
||||
@@ -3976,7 +4045,7 @@ def spid(spec):
|
||||
new_specs[spid(edge.spec)] = edge.spec.copy(deps=False)
|
||||
|
||||
new_specs[spid(edge.parent)].add_dependency_edge(
|
||||
new_specs[spid(edge.spec)], deptypes=edge.deptypes
|
||||
new_specs[spid(edge.spec)], deptypes=edge.deptypes, virtuals=edge.virtuals
|
||||
)
|
||||
|
||||
def copy(self, deps=True, **kwargs):
|
||||
@@ -4344,7 +4413,7 @@ def write_attribute(spec, attribute, color):
|
||||
|
||||
if callable(current):
|
||||
raise SpecFormatStringError("Attempted to format callable object")
|
||||
if not current:
|
||||
if current is None:
|
||||
# We're not printing anything
|
||||
return
|
||||
|
||||
@@ -4412,20 +4481,12 @@ def __str__(self):
|
||||
def install_status(self):
|
||||
"""Helper for tree to print DB install status."""
|
||||
if not self.concrete:
|
||||
return InstallStatus.absent
|
||||
|
||||
if self.external:
|
||||
return InstallStatus.external
|
||||
|
||||
upstream, record = spack.store.db.query_by_spec_hash(self.dag_hash())
|
||||
if not record:
|
||||
return InstallStatus.absent
|
||||
elif upstream and record.installed:
|
||||
return InstallStatus.upstream
|
||||
elif record.installed:
|
||||
return InstallStatus.installed
|
||||
else:
|
||||
return InstallStatus.missing
|
||||
return None
|
||||
try:
|
||||
record = spack.store.db.get_record(self)
|
||||
return record.installed
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def _installed_explicitly(self):
|
||||
"""Helper for tree to print DB install status."""
|
||||
@@ -4439,10 +4500,7 @@ def _installed_explicitly(self):
|
||||
|
||||
def tree(self, **kwargs):
|
||||
"""Prints out this spec and its dependencies, tree-formatted
|
||||
with indentation.
|
||||
|
||||
Status function may either output a boolean or an InstallStatus
|
||||
"""
|
||||
with indentation."""
|
||||
color = kwargs.pop("color", clr.get_color_when())
|
||||
depth = kwargs.pop("depth", False)
|
||||
hashes = kwargs.pop("hashes", False)
|
||||
@@ -4474,12 +4532,14 @@ def tree(self, **kwargs):
|
||||
|
||||
if status_fn:
|
||||
status = status_fn(node)
|
||||
if status in list(InstallStatus):
|
||||
out += clr.colorize(status.value, color=color)
|
||||
if node.installed_upstream:
|
||||
out += clr.colorize("@g{[^]} ", color=color)
|
||||
elif status is None:
|
||||
out += clr.colorize("@K{ - } ", color=color) # !installed
|
||||
elif status:
|
||||
out += clr.colorize("@g{[+]} ", color=color)
|
||||
out += clr.colorize("@g{[+]} ", color=color) # installed
|
||||
else:
|
||||
out += clr.colorize("@r{[-]} ", color=color)
|
||||
out += clr.colorize("@r{[-]} ", color=color) # missing
|
||||
|
||||
if hashes:
|
||||
out += clr.colorize("@K{%s} ", color=color) % node.dag_hash(hlen)
|
||||
@@ -4655,12 +4715,16 @@ def from_self(name, transitive):
|
||||
if name in self_nodes:
|
||||
for edge in self[name].edges_to_dependencies():
|
||||
dep_name = deps_to_replace.get(edge.spec, edge.spec).name
|
||||
nodes[name].add_dependency_edge(nodes[dep_name], deptypes=edge.deptypes)
|
||||
nodes[name].add_dependency_edge(
|
||||
nodes[dep_name], deptypes=edge.deptypes, virtuals=edge.virtuals
|
||||
)
|
||||
if any(dep not in self_nodes for dep in self[name]._dependencies):
|
||||
nodes[name].build_spec = self[name].build_spec
|
||||
else:
|
||||
for edge in other[name].edges_to_dependencies():
|
||||
nodes[name].add_dependency_edge(nodes[edge.spec.name], deptypes=edge.deptypes)
|
||||
nodes[name].add_dependency_edge(
|
||||
nodes[edge.spec.name], deptypes=edge.deptypes, virtuals=edge.virtuals
|
||||
)
|
||||
if any(dep not in other_nodes for dep in other[name]._dependencies):
|
||||
nodes[name].build_spec = other[name].build_spec
|
||||
|
||||
@@ -4750,11 +4814,40 @@ def merge_abstract_anonymous_specs(*abstract_specs: Spec):
|
||||
# Update with additional constraints from other spec
|
||||
for name in current_spec_constraint.direct_dep_difference(merged_spec):
|
||||
edge = next(iter(current_spec_constraint.edges_to_dependencies(name)))
|
||||
merged_spec._add_dependency(edge.spec.copy(), deptypes=edge.deptypes)
|
||||
merged_spec._add_dependency(
|
||||
edge.spec.copy(), deptypes=edge.deptypes, virtuals=edge.virtuals
|
||||
)
|
||||
|
||||
return merged_spec
|
||||
|
||||
|
||||
def reconstruct_virtuals_on_edges(spec):
|
||||
"""Reconstruct virtuals on edges. Used to read from old DB and reindex.
|
||||
|
||||
Args:
|
||||
spec: spec on which we want to reconstruct virtuals
|
||||
"""
|
||||
# Collect all possible virtuals
|
||||
possible_virtuals = set()
|
||||
for node in spec.traverse():
|
||||
try:
|
||||
possible_virtuals.update({x for x in node.package.dependencies if Spec(x).virtual})
|
||||
except Exception as e:
|
||||
warnings.warn(f"cannot reconstruct virtual dependencies on package {node.name}: {e}")
|
||||
continue
|
||||
|
||||
# Assume all incoming edges to provider are marked with virtuals=
|
||||
for vspec in possible_virtuals:
|
||||
try:
|
||||
provider = spec[vspec]
|
||||
except KeyError:
|
||||
# Virtual not in the DAG
|
||||
continue
|
||||
|
||||
for edge in provider.edges_from_dependents():
|
||||
edge.update_virtuals([vspec])
|
||||
|
||||
|
||||
class SpecfileReaderBase:
|
||||
@classmethod
|
||||
def from_node_dict(cls, node):
|
||||
@@ -4838,7 +4931,7 @@ def _load(cls, data):
|
||||
|
||||
# Pass 0: Determine hash type
|
||||
for node in nodes:
|
||||
for _, _, _, dhash_type in cls.dependencies_from_node_dict(node):
|
||||
for _, _, _, dhash_type, _ in cls.dependencies_from_node_dict(node):
|
||||
any_deps = True
|
||||
if dhash_type:
|
||||
hash_type = dhash_type
|
||||
@@ -4869,8 +4962,10 @@ def _load(cls, data):
|
||||
# Pass 2: Finish construction of all DAG edges (including build specs)
|
||||
for node_hash, node in hash_dict.items():
|
||||
node_spec = node["node_spec"]
|
||||
for _, dhash, dtypes, _ in cls.dependencies_from_node_dict(node):
|
||||
node_spec._add_dependency(hash_dict[dhash]["node_spec"], deptypes=dtypes)
|
||||
for _, dhash, dtypes, _, virtuals in cls.dependencies_from_node_dict(node):
|
||||
node_spec._add_dependency(
|
||||
hash_dict[dhash]["node_spec"], deptypes=dtypes, virtuals=virtuals
|
||||
)
|
||||
if "build_spec" in node.keys():
|
||||
_, bhash, _ = cls.build_spec_from_node_dict(node, hash_type=hash_type)
|
||||
node_spec._build_spec = hash_dict[bhash]["node_spec"]
|
||||
@@ -4904,9 +4999,10 @@ def load(cls, data):
|
||||
for node in nodes:
|
||||
# get dependency dict from the node.
|
||||
name, data = cls.name_and_data(node)
|
||||
for dname, _, dtypes, _ in cls.dependencies_from_node_dict(data):
|
||||
deps[name]._add_dependency(deps[dname], deptypes=dtypes)
|
||||
for dname, _, dtypes, _, virtuals in cls.dependencies_from_node_dict(data):
|
||||
deps[name]._add_dependency(deps[dname], deptypes=dtypes, virtuals=virtuals)
|
||||
|
||||
reconstruct_virtuals_on_edges(result)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
@@ -4935,18 +5031,20 @@ def read_specfile_dep_specs(cls, deps, hash_type=ht.dag_hash.name):
|
||||
if h.name in elt:
|
||||
dep_hash, deptypes = elt[h.name], elt["type"]
|
||||
hash_type = h.name
|
||||
virtuals = []
|
||||
break
|
||||
else: # We never determined a hash type...
|
||||
raise spack.error.SpecError("Couldn't parse dependency spec.")
|
||||
else:
|
||||
raise spack.error.SpecError("Couldn't parse dependency types in spec.")
|
||||
yield dep_name, dep_hash, list(deptypes), hash_type
|
||||
yield dep_name, dep_hash, list(deptypes), hash_type, list(virtuals)
|
||||
|
||||
|
||||
class SpecfileV2(SpecfileReaderBase):
|
||||
@classmethod
|
||||
def load(cls, data):
|
||||
result = cls._load(data)
|
||||
reconstruct_virtuals_on_edges(result)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
@@ -4980,7 +5078,7 @@ def read_specfile_dep_specs(cls, deps, hash_type=ht.dag_hash.name):
|
||||
raise spack.error.SpecError("Couldn't parse dependency spec.")
|
||||
else:
|
||||
raise spack.error.SpecError("Couldn't parse dependency types in spec.")
|
||||
result.append((dep_name, dep_hash, list(deptypes), hash_type))
|
||||
result.append((dep_name, dep_hash, list(deptypes), hash_type, list(virtuals)))
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
@@ -5000,6 +5098,20 @@ class SpecfileV3(SpecfileV2):
|
||||
pass
|
||||
|
||||
|
||||
class SpecfileV4(SpecfileV2):
|
||||
@classmethod
|
||||
def extract_info_from_dep(cls, elt, hash):
|
||||
dep_hash = elt[hash.name]
|
||||
deptypes = elt["parameters"]["deptypes"]
|
||||
hash_type = hash.name
|
||||
virtuals = elt["parameters"]["virtuals"]
|
||||
return dep_hash, deptypes, hash_type, virtuals
|
||||
|
||||
@classmethod
|
||||
def load(cls, data):
|
||||
return cls._load(data)
|
||||
|
||||
|
||||
class LazySpecCache(collections.defaultdict):
|
||||
"""Cache for Specs that uses a spec_like as key, and computes lazily
|
||||
the corresponding value ``Spec(spec_like``.
|
||||
|
@@ -100,15 +100,9 @@ def quote(text):
|
||||
return ['"{0}"'.format(line) for line in text]
|
||||
|
||||
|
||||
def curly_quote(text):
|
||||
"""Encloses each line of text in curly braces"""
|
||||
return ["{{{0}}}".format(line) for line in text]
|
||||
|
||||
|
||||
def _set_filters(env):
|
||||
"""Sets custom filters to the template engine environment"""
|
||||
env.filters["textwrap"] = textwrap.wrap
|
||||
env.filters["prepend_to_line"] = prepend_to_line
|
||||
env.filters["join"] = "\n".join
|
||||
env.filters["quote"] = quote
|
||||
env.filters["curly_quote"] = curly_quote
|
||||
|
@@ -201,12 +201,12 @@ def test_default_rpaths_create_install_default_layout(mirror_dir):
|
||||
install_cmd("--no-cache", sy_spec.name)
|
||||
|
||||
# Create a buildache
|
||||
buildcache_cmd("push", "-au", "-d", mirror_dir, cspec.name, sy_spec.name)
|
||||
buildcache_cmd("push", "-au", mirror_dir, cspec.name, sy_spec.name)
|
||||
# Test force overwrite create buildcache (-f option)
|
||||
buildcache_cmd("push", "-auf", "-d", mirror_dir, cspec.name)
|
||||
buildcache_cmd("push", "-auf", mirror_dir, cspec.name)
|
||||
|
||||
# Create mirror index
|
||||
buildcache_cmd("update-index", "-d", mirror_dir)
|
||||
buildcache_cmd("update-index", mirror_dir)
|
||||
# List the buildcaches in the mirror
|
||||
buildcache_cmd("list", "-alv")
|
||||
|
||||
@@ -214,13 +214,13 @@ def test_default_rpaths_create_install_default_layout(mirror_dir):
|
||||
uninstall_cmd("-y", "--dependents", gspec.name)
|
||||
|
||||
# Test installing from build caches
|
||||
buildcache_cmd("install", "-au", cspec.name, sy_spec.name)
|
||||
buildcache_cmd("install", "-u", cspec.name, sy_spec.name)
|
||||
|
||||
# This gives warning that spec is already installed
|
||||
buildcache_cmd("install", "-au", cspec.name)
|
||||
buildcache_cmd("install", "-u", cspec.name)
|
||||
|
||||
# Test overwrite install
|
||||
buildcache_cmd("install", "-afu", cspec.name)
|
||||
buildcache_cmd("install", "-fu", cspec.name)
|
||||
|
||||
buildcache_cmd("keys", "-f")
|
||||
buildcache_cmd("list")
|
||||
@@ -246,35 +246,10 @@ def test_default_rpaths_install_nondefault_layout(mirror_dir):
|
||||
|
||||
# Install some packages with dependent packages
|
||||
# test install in non-default install path scheme
|
||||
buildcache_cmd("install", "-au", cspec.name, sy_spec.name)
|
||||
buildcache_cmd("install", "-u", cspec.name, sy_spec.name)
|
||||
|
||||
# Test force install in non-default install path scheme
|
||||
buildcache_cmd("install", "-auf", cspec.name)
|
||||
|
||||
|
||||
@pytest.mark.requires_executables(*args)
|
||||
@pytest.mark.maybeslow
|
||||
@pytest.mark.nomockstage
|
||||
@pytest.mark.usefixtures("default_config", "cache_directory", "install_dir_default_layout")
|
||||
def test_relative_rpaths_create_default_layout(mirror_dir):
|
||||
"""
|
||||
Test the creation and installation of buildcaches with relative
|
||||
rpaths into the default directory layout scheme.
|
||||
"""
|
||||
|
||||
gspec, cspec = Spec("garply").concretized(), Spec("corge").concretized()
|
||||
|
||||
# Install 'corge' without using a cache
|
||||
install_cmd("--no-cache", cspec.name)
|
||||
|
||||
# Create build cache with relative rpaths
|
||||
buildcache_cmd("push", "-aur", "-d", mirror_dir, cspec.name)
|
||||
|
||||
# Create mirror index
|
||||
buildcache_cmd("update-index", "-d", mirror_dir)
|
||||
|
||||
# Uninstall the package and deps
|
||||
uninstall_cmd("-y", "--dependents", gspec.name)
|
||||
buildcache_cmd("install", "-uf", cspec.name)
|
||||
|
||||
|
||||
@pytest.mark.requires_executables(*args)
|
||||
@@ -291,19 +266,19 @@ def test_relative_rpaths_install_default_layout(mirror_dir):
|
||||
gspec, cspec = Spec("garply").concretized(), Spec("corge").concretized()
|
||||
|
||||
# Install buildcache created with relativized rpaths
|
||||
buildcache_cmd("install", "-auf", cspec.name)
|
||||
buildcache_cmd("install", "-uf", cspec.name)
|
||||
|
||||
# This gives warning that spec is already installed
|
||||
buildcache_cmd("install", "-auf", cspec.name)
|
||||
buildcache_cmd("install", "-uf", cspec.name)
|
||||
|
||||
# Uninstall the package and deps
|
||||
uninstall_cmd("-y", "--dependents", gspec.name)
|
||||
|
||||
# Install build cache
|
||||
buildcache_cmd("install", "-auf", cspec.name)
|
||||
buildcache_cmd("install", "-uf", cspec.name)
|
||||
|
||||
# Test overwrite install
|
||||
buildcache_cmd("install", "-auf", cspec.name)
|
||||
buildcache_cmd("install", "-uf", cspec.name)
|
||||
|
||||
|
||||
@pytest.mark.requires_executables(*args)
|
||||
@@ -320,7 +295,7 @@ def test_relative_rpaths_install_nondefault(mirror_dir):
|
||||
cspec = Spec("corge").concretized()
|
||||
|
||||
# Test install in non-default install path scheme and relative path
|
||||
buildcache_cmd("install", "-auf", cspec.name)
|
||||
buildcache_cmd("install", "-uf", cspec.name)
|
||||
|
||||
|
||||
def test_push_and_fetch_keys(mock_gnupghome):
|
||||
@@ -401,7 +376,7 @@ def test_spec_needs_rebuild(monkeypatch, tmpdir):
|
||||
install_cmd(s.name)
|
||||
|
||||
# Put installed package in the buildcache
|
||||
buildcache_cmd("push", "-u", "-a", "-d", mirror_dir.strpath, s.name)
|
||||
buildcache_cmd("push", "-u", "-a", mirror_dir.strpath, s.name)
|
||||
|
||||
rebuild = bindist.needs_rebuild(s, mirror_url)
|
||||
|
||||
@@ -430,8 +405,8 @@ def test_generate_index_missing(monkeypatch, tmpdir, mutable_config):
|
||||
install_cmd("--no-cache", s.name)
|
||||
|
||||
# Create a buildcache and update index
|
||||
buildcache_cmd("push", "-uad", mirror_dir.strpath, s.name)
|
||||
buildcache_cmd("update-index", "-d", mirror_dir.strpath)
|
||||
buildcache_cmd("push", "-ua", mirror_dir.strpath, s.name)
|
||||
buildcache_cmd("update-index", mirror_dir.strpath)
|
||||
|
||||
# Check package and dependency in buildcache
|
||||
cache_list = buildcache_cmd("list", "--allarch")
|
||||
@@ -443,7 +418,7 @@ def test_generate_index_missing(monkeypatch, tmpdir, mutable_config):
|
||||
os.remove(*libelf_files)
|
||||
|
||||
# Update index
|
||||
buildcache_cmd("update-index", "-d", mirror_dir.strpath)
|
||||
buildcache_cmd("update-index", mirror_dir.strpath)
|
||||
|
||||
with spack.config.override("config:binary_index_ttl", 0):
|
||||
# Check dependency not in buildcache
|
||||
@@ -519,10 +494,10 @@ def test_update_sbang(tmpdir, test_mirror):
|
||||
install_cmd("--no-cache", old_spec.name)
|
||||
|
||||
# Create a buildcache with the installed spec.
|
||||
buildcache_cmd("push", "-u", "-a", "-d", mirror_dir, old_spec_hash_str)
|
||||
buildcache_cmd("push", "-u", "-a", mirror_dir, old_spec_hash_str)
|
||||
|
||||
# Need to force an update of the buildcache index
|
||||
buildcache_cmd("update-index", "-d", mirror_dir)
|
||||
buildcache_cmd("update-index", mirror_dir)
|
||||
|
||||
# Uninstall the original package.
|
||||
uninstall_cmd("-y", old_spec_hash_str)
|
||||
@@ -538,7 +513,7 @@ def test_update_sbang(tmpdir, test_mirror):
|
||||
assert new_spec.dag_hash() == old_spec.dag_hash()
|
||||
|
||||
# Install package from buildcache
|
||||
buildcache_cmd("install", "-a", "-u", "-f", new_spec.name)
|
||||
buildcache_cmd("install", "-u", "-f", new_spec.name)
|
||||
|
||||
# Continue blowing away caches
|
||||
bindist.clear_spec_cache()
|
||||
|
@@ -3,8 +3,6 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import spack.cmd.create
|
||||
@@ -12,8 +10,6 @@
|
||||
import spack.util.executable
|
||||
import spack.util.url as url_util
|
||||
|
||||
pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
scope="function",
|
||||
|
@@ -291,7 +291,7 @@ def make_build_job(name, deps, stage, use_artifact_buildcache, optimize, use_dep
|
||||
def make_rebuild_index_job(use_artifact_buildcache, optimize, use_dependencies):
|
||||
result = {
|
||||
"stage": "stage-rebuild-index",
|
||||
"script": "spack buildcache update-index --mirror-url s3://mirror",
|
||||
"script": "spack buildcache update-index s3://mirror",
|
||||
"tags": ["tag-0", "tag-1"],
|
||||
"image": {"name": "spack/centos7", "entrypoint": [""]},
|
||||
"after_script": ['rm -rf "./spack"'],
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import pickle
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -39,7 +40,10 @@ def test_dump(tmpdir):
|
||||
with tmpdir.as_cwd():
|
||||
build_env("--dump", _out_file, "zlib")
|
||||
with open(_out_file) as f:
|
||||
assert any(line.startswith("PATH=") for line in f.readlines())
|
||||
if sys.platform == "win32":
|
||||
assert any(line.startswith('set "PATH=') for line in f.readlines())
|
||||
else:
|
||||
assert any(line.startswith("PATH=") for line in f.readlines())
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("config", "mock_packages", "working_env")
|
||||
|
@@ -85,7 +85,7 @@ def tests_buildcache_create(install_mockery, mock_fetch, monkeypatch, tmpdir):
|
||||
pkg = "trivial-install-test-package"
|
||||
install(pkg)
|
||||
|
||||
buildcache("push", "-d", str(tmpdir), "--unsigned", pkg)
|
||||
buildcache("push", "--unsigned", str(tmpdir), pkg)
|
||||
|
||||
spec = Spec(pkg).concretized()
|
||||
tarball_path = spack.binary_distribution.tarball_path_name(spec, ".spack")
|
||||
@@ -105,7 +105,7 @@ def tests_buildcache_create_env(
|
||||
add(pkg)
|
||||
install()
|
||||
|
||||
buildcache("push", "-d", str(tmpdir), "--unsigned")
|
||||
buildcache("push", "--unsigned", str(tmpdir))
|
||||
|
||||
spec = Spec(pkg).concretized()
|
||||
tarball_path = spack.binary_distribution.tarball_path_name(spec, ".spack")
|
||||
@@ -118,7 +118,7 @@ def test_buildcache_create_fails_on_noargs(tmpdir):
|
||||
"""Ensure that buildcache create fails when given no args or
|
||||
environment."""
|
||||
with pytest.raises(spack.main.SpackCommandError):
|
||||
buildcache("push", "-d", str(tmpdir), "--unsigned")
|
||||
buildcache("push", "--unsigned", str(tmpdir))
|
||||
|
||||
|
||||
def test_buildcache_create_fail_on_perm_denied(install_mockery, mock_fetch, monkeypatch, tmpdir):
|
||||
@@ -127,7 +127,7 @@ def test_buildcache_create_fail_on_perm_denied(install_mockery, mock_fetch, monk
|
||||
|
||||
tmpdir.chmod(0)
|
||||
with pytest.raises(OSError) as error:
|
||||
buildcache("push", "-d", str(tmpdir), "--unsigned", "trivial-install-test-package")
|
||||
buildcache("push", "--unsigned", str(tmpdir), "trivial-install-test-package")
|
||||
assert error.value.errno == errno.EACCES
|
||||
tmpdir.chmod(0o700)
|
||||
|
||||
@@ -159,11 +159,11 @@ def test_update_key_index(
|
||||
# Put installed package in the buildcache, which, because we're signing
|
||||
# it, should result in the public key getting pushed to the buildcache
|
||||
# as well.
|
||||
buildcache("push", "-a", "-d", mirror_dir.strpath, s.name)
|
||||
buildcache("push", "-a", mirror_dir.strpath, s.name)
|
||||
|
||||
# Now make sure that when we pass the "--keys" argument to update-index
|
||||
# it causes the index to get update.
|
||||
buildcache("update-index", "--keys", "-d", mirror_dir.strpath)
|
||||
buildcache("update-index", "--keys", mirror_dir.strpath)
|
||||
|
||||
key_dir_list = os.listdir(os.path.join(mirror_dir.strpath, "build_cache", "_pgp"))
|
||||
|
||||
@@ -213,27 +213,25 @@ def verify_mirror_contents():
|
||||
# Install a package and put it in the buildcache
|
||||
s = Spec(out_env_pkg).concretized()
|
||||
install(s.name)
|
||||
buildcache("push", "-u", "-f", "-a", "--mirror-url", src_mirror_url, s.name)
|
||||
buildcache("push", "-u", "-f", "-a", src_mirror_url, s.name)
|
||||
|
||||
env("create", "test")
|
||||
with ev.read("test"):
|
||||
add(in_env_pkg)
|
||||
install()
|
||||
buildcache("push", "-u", "-f", "-a", "--mirror-url", src_mirror_url, in_env_pkg)
|
||||
buildcache("push", "-u", "-f", "-a", src_mirror_url, in_env_pkg)
|
||||
|
||||
# Now run the spack buildcache sync command with all the various options
|
||||
# for specifying mirrors
|
||||
|
||||
# Use urls to specify mirrors
|
||||
buildcache(
|
||||
"sync", "--src-mirror-url", src_mirror_url, "--dest-mirror-url", dest_mirror_url
|
||||
)
|
||||
buildcache("sync", src_mirror_url, dest_mirror_url)
|
||||
|
||||
verify_mirror_contents()
|
||||
shutil.rmtree(dest_mirror_dir)
|
||||
|
||||
# Use local directory paths to specify fs locations
|
||||
buildcache("sync", "--src-directory", src_mirror_dir, "--dest-directory", dest_mirror_dir)
|
||||
buildcache("sync", src_mirror_dir, dest_mirror_dir)
|
||||
|
||||
verify_mirror_contents()
|
||||
shutil.rmtree(dest_mirror_dir)
|
||||
@@ -242,7 +240,7 @@ def verify_mirror_contents():
|
||||
mirror("add", "src", src_mirror_url)
|
||||
mirror("add", "dest", dest_mirror_url)
|
||||
|
||||
buildcache("sync", "--src-mirror-name", "src", "--dest-mirror-name", "dest")
|
||||
buildcache("sync", "src", "dest")
|
||||
|
||||
verify_mirror_contents()
|
||||
|
||||
@@ -260,7 +258,7 @@ def test_buildcache_create_install(
|
||||
pkg = "trivial-install-test-package"
|
||||
install(pkg)
|
||||
|
||||
buildcache("push", "-d", str(tmpdir), "--unsigned", pkg)
|
||||
buildcache("push", "--unsigned", str(tmpdir), pkg)
|
||||
|
||||
spec = Spec(pkg).concretized()
|
||||
tarball_path = spack.binary_distribution.tarball_path_name(spec, ".spack")
|
||||
@@ -324,12 +322,12 @@ def fake_push(node, push_url, options):
|
||||
|
||||
monkeypatch.setattr(spack.binary_distribution, "push_or_raise", fake_push)
|
||||
|
||||
buildcache_create_args = ["create", "-d", str(tmpdir), "--unsigned"]
|
||||
buildcache_create_args = ["create", "--unsigned"]
|
||||
|
||||
if things_to_install != "":
|
||||
buildcache_create_args.extend(["--only", things_to_install])
|
||||
|
||||
buildcache_create_args.extend([slash_hash])
|
||||
buildcache_create_args.extend([str(tmpdir), slash_hash])
|
||||
|
||||
buildcache(*buildcache_create_args)
|
||||
|
||||
|
@@ -1055,7 +1055,7 @@ def test_ci_nothing_to_rebuild(
|
||||
)
|
||||
|
||||
install_cmd("archive-files")
|
||||
buildcache_cmd("push", "-a", "-f", "-u", "--mirror-url", mirror_url, "archive-files")
|
||||
buildcache_cmd("push", "-a", "-f", "-u", mirror_url, "archive-files")
|
||||
|
||||
filename = str(tmpdir.join("spack.yaml"))
|
||||
with open(filename, "w") as f:
|
||||
@@ -1155,8 +1155,8 @@ def test_ci_generate_mirror_override(
|
||||
second_ci_yaml = str(tmpdir.join(".gitlab-ci-2.yml"))
|
||||
with ev.read("test"):
|
||||
install_cmd()
|
||||
buildcache_cmd("push", "-u", "--mirror-url", mirror_url, "patchelf")
|
||||
buildcache_cmd("update-index", "--mirror-url", mirror_url, output=str)
|
||||
buildcache_cmd("push", "-u", mirror_url, "patchelf")
|
||||
buildcache_cmd("update-index", mirror_url, output=str)
|
||||
|
||||
# This generate should not trigger a rebuild of patchelf, since it's in
|
||||
# the main mirror referenced in the environment.
|
||||
@@ -1297,7 +1297,7 @@ def test_push_mirror_contents(
|
||||
mirror_cmd("rm", "test-ci")
|
||||
|
||||
# Test generating buildcache index while we have bin mirror
|
||||
buildcache_cmd("update-index", "--mirror-url", mirror_url)
|
||||
buildcache_cmd("update-index", mirror_url)
|
||||
index_path = os.path.join(buildcache_path, "index.json")
|
||||
with open(index_path) as idx_fd:
|
||||
index_object = json.load(idx_fd)
|
||||
@@ -1613,7 +1613,7 @@ def test_ci_rebuild_index(
|
||||
ypfd.write(spec_json)
|
||||
|
||||
install_cmd("--add", "--keep-stage", "-f", json_path)
|
||||
buildcache_cmd("push", "-u", "-a", "-f", "--mirror-url", mirror_url, "callpath")
|
||||
buildcache_cmd("push", "-u", "-a", "-f", mirror_url, "callpath")
|
||||
ci_cmd("rebuild-index")
|
||||
|
||||
buildcache_path = os.path.join(mirror_dir.strpath, "build_cache")
|
||||
@@ -1647,7 +1647,7 @@ def test_ci_generate_bootstrap_prune_dag(
|
||||
install_cmd("gcc@=12.2.0%gcc@10.2.1")
|
||||
|
||||
# Put installed compiler in the buildcache
|
||||
buildcache_cmd("push", "-u", "-a", "-f", "-d", mirror_dir.strpath, "gcc@12.2.0%gcc@10.2.1")
|
||||
buildcache_cmd("push", "-u", "-a", "-f", mirror_dir.strpath, "gcc@12.2.0%gcc@10.2.1")
|
||||
|
||||
# Now uninstall the compiler
|
||||
uninstall_cmd("-y", "gcc@12.2.0%gcc@10.2.1")
|
||||
@@ -1662,7 +1662,7 @@ def test_ci_generate_bootstrap_prune_dag(
|
||||
install_cmd("--no-check-signature", "b%gcc@=12.2.0")
|
||||
|
||||
# Put spec built with installed compiler in the buildcache
|
||||
buildcache_cmd("push", "-u", "-a", "-f", "-d", mirror_dir.strpath, "b%gcc@12.2.0")
|
||||
buildcache_cmd("push", "-u", "-a", "-f", mirror_dir.strpath, "b%gcc@12.2.0")
|
||||
|
||||
# Now uninstall the spec
|
||||
uninstall_cmd("-y", "b%gcc@12.2.0")
|
||||
|
@@ -396,16 +396,17 @@ def reset_string():
|
||||
with envdir.as_cwd():
|
||||
with open("spack.yaml", "w") as f:
|
||||
f.write(
|
||||
f"""\
|
||||
"""\
|
||||
spack:
|
||||
specs:
|
||||
- {test_spec}@0.0.0
|
||||
- %s@0.0.0
|
||||
|
||||
develop:
|
||||
dev-build-test-install:
|
||||
spec: dev-build-test-install@0.0.0
|
||||
path: {build_dir}
|
||||
path: %s
|
||||
"""
|
||||
% (test_spec, build_dir)
|
||||
)
|
||||
|
||||
env("create", "test", "./spack.yaml")
|
||||
|
@@ -32,7 +32,7 @@ def check_develop(self, env, spec, path=None):
|
||||
assert dev_specs_entry["spec"] == str(spec)
|
||||
|
||||
# check yaml representation
|
||||
yaml = ev.config_dict(env.manifest)
|
||||
yaml = env.manifest[ev.TOP_LEVEL_KEY]
|
||||
assert spec.name in yaml["develop"]
|
||||
yaml_entry = yaml["develop"][spec.name]
|
||||
assert yaml_entry["spec"] == str(spec)
|
||||
|
@@ -2402,6 +2402,21 @@ def test_env_activate_default_view_root_unconditional(mutable_mock_env_path):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.regression("38510")
|
||||
def test_concretize_separately_abstract_hash(install_mockery, mock_fetch):
|
||||
"""Check that a root can have no name if it has a hash."""
|
||||
s = Spec("trivial-install-test-package").concretized()
|
||||
install(str(s))
|
||||
|
||||
e = ev.create("test")
|
||||
e.unify = False
|
||||
|
||||
e.add(f"/{s.dag_hash()}")
|
||||
e.concretize()
|
||||
|
||||
assert list(e.concretized_specs()) == [(Spec(f"/{s.dag_hash()}"), s)]
|
||||
|
||||
|
||||
def test_concretize_user_specs_together():
|
||||
e = ev.create("coconcretization")
|
||||
e.unify = True
|
||||
@@ -2688,7 +2703,7 @@ def test_modules_relative_to_views(environment_from_manifest, install_mockery, m
|
||||
|
||||
spec = e.specs_by_hash[e.concretized_order[0]]
|
||||
view_prefix = e.default_view.get_projection_for_spec(spec)
|
||||
modules_glob = "%s/modules/**/*" % e.path
|
||||
modules_glob = "%s/modules/**/*/*" % e.path
|
||||
modules = glob.glob(modules_glob)
|
||||
assert len(modules) == 1
|
||||
module = modules[0]
|
||||
@@ -2724,12 +2739,12 @@ def test_multiple_modules_post_env_hook(environment_from_manifest, install_mocke
|
||||
|
||||
spec = e.specs_by_hash[e.concretized_order[0]]
|
||||
view_prefix = e.default_view.get_projection_for_spec(spec)
|
||||
modules_glob = "%s/modules/**/*" % e.path
|
||||
modules_glob = "%s/modules/**/*/*" % e.path
|
||||
modules = glob.glob(modules_glob)
|
||||
assert len(modules) == 1
|
||||
module = modules[0]
|
||||
|
||||
full_modules_glob = "%s/full_modules/**/*" % e.path
|
||||
full_modules_glob = "%s/full_modules/**/*/*" % e.path
|
||||
full_modules = glob.glob(full_modules_glob)
|
||||
assert len(full_modules) == 1
|
||||
full_module = full_modules[0]
|
||||
|
@@ -396,30 +396,3 @@ def test_use_tags_for_detection(command_args, mock_executable, mutable_config, m
|
||||
assert "The following specs have been" in output
|
||||
assert "cmake" in output
|
||||
assert "openssl" not in output
|
||||
|
||||
|
||||
@pytest.mark.regression("38733")
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="the test uses bash scripts")
|
||||
def test_failures_in_scanning_do_not_result_in_an_error(
|
||||
mock_executable, monkeypatch, mutable_config
|
||||
):
|
||||
"""Tests that scanning paths with wrong permissions, won't cause `external find` to error."""
|
||||
cmake_exe1 = mock_executable(
|
||||
"cmake", output="echo cmake version 3.19.1", subdir=("first", "bin")
|
||||
)
|
||||
cmake_exe2 = mock_executable(
|
||||
"cmake", output="echo cmake version 3.23.3", subdir=("second", "bin")
|
||||
)
|
||||
|
||||
# Remove access from the first directory executable
|
||||
cmake_exe1.parent.chmod(0o600)
|
||||
|
||||
value = os.pathsep.join([str(cmake_exe1.parent), str(cmake_exe2.parent)])
|
||||
monkeypatch.setenv("PATH", value)
|
||||
|
||||
output = external("find", "cmake")
|
||||
assert external.returncode == 0
|
||||
assert "The following specs have been" in output
|
||||
assert "cmake" in output
|
||||
assert "3.23.3" in output
|
||||
assert "3.19.1" not in output
|
||||
|
@@ -3,16 +3,12 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from spack.main import SpackCommand, SpackCommandError
|
||||
|
||||
graph = SpackCommand("graph")
|
||||
|
||||
pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
|
||||
|
||||
|
||||
@pytest.mark.db
|
||||
@pytest.mark.usefixtures("mock_packages", "database")
|
||||
|
@@ -4,7 +4,6 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -13,8 +12,6 @@
|
||||
|
||||
info = SpackCommand("info")
|
||||
|
||||
pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="Not yet implemented on Windows")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def parser():
|
||||
|
@@ -966,7 +966,7 @@ def test_compiler_bootstrap_from_binary_mirror(
|
||||
install("gcc@=10.2.0")
|
||||
|
||||
# Put installed compiler in the buildcache
|
||||
buildcache("push", "-u", "-a", "-f", "-d", mirror_dir.strpath, "gcc@10.2.0")
|
||||
buildcache("push", "-u", "-a", "-f", mirror_dir.strpath, "gcc@10.2.0")
|
||||
|
||||
# Now uninstall the compiler
|
||||
uninstall("-y", "gcc@10.2.0")
|
||||
@@ -1138,7 +1138,7 @@ def install_use_buildcache(opt):
|
||||
|
||||
# Populate the buildcache
|
||||
install(package_name)
|
||||
buildcache("push", "-u", "-a", "-f", "-d", mirror_dir.strpath, package_name, dependency_name)
|
||||
buildcache("push", "-u", "-a", "-f", mirror_dir.strpath, package_name, dependency_name)
|
||||
|
||||
# Uninstall the all of the packages for clean slate
|
||||
uninstall("-y", "-a")
|
||||
|
@@ -3,8 +3,6 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import spack.store
|
||||
@@ -15,8 +13,6 @@
|
||||
install = SpackCommand("install")
|
||||
uninstall = SpackCommand("uninstall")
|
||||
|
||||
pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
|
||||
|
||||
|
||||
@pytest.mark.db
|
||||
def test_mark_mode_required(mutable_database):
|
||||
|
@@ -235,7 +235,7 @@ def test_mirror_destroy(
|
||||
|
||||
# Put a binary package in a buildcache
|
||||
install("--no-cache", spec_name)
|
||||
buildcache("push", "-u", "-a", "-f", "-d", mirror_dir.strpath, spec_name)
|
||||
buildcache("push", "-u", "-a", "-f", mirror_dir.strpath, spec_name)
|
||||
|
||||
contents = os.listdir(mirror_dir.strpath)
|
||||
assert "build_cache" in contents
|
||||
@@ -245,7 +245,7 @@ def test_mirror_destroy(
|
||||
|
||||
assert not os.path.exists(mirror_dir.strpath)
|
||||
|
||||
buildcache("push", "-u", "-a", "-f", "-d", mirror_dir.strpath, spec_name)
|
||||
buildcache("push", "-u", "-a", "-f", mirror_dir.strpath, spec_name)
|
||||
|
||||
contents = os.listdir(mirror_dir.strpath)
|
||||
assert "build_cache" in contents
|
||||
|
@@ -157,7 +157,7 @@ def _parse_types(string):
|
||||
|
||||
|
||||
def test_spec_deptypes_nodes():
|
||||
output = spec("--types", "--cover", "nodes", "dt-diamond")
|
||||
output = spec("--types", "--cover", "nodes", "--no-install-status", "dt-diamond")
|
||||
types = _parse_types(output)
|
||||
|
||||
assert types["dt-diamond"] == [" "]
|
||||
@@ -167,7 +167,7 @@ def test_spec_deptypes_nodes():
|
||||
|
||||
|
||||
def test_spec_deptypes_edges():
|
||||
output = spec("--types", "--cover", "edges", "dt-diamond")
|
||||
output = spec("--types", "--cover", "edges", "--no-install-status", "dt-diamond")
|
||||
types = _parse_types(output)
|
||||
|
||||
assert types["dt-diamond"] == [" "]
|
||||
|
@@ -2170,3 +2170,14 @@ def test_concretization_with_compilers_supporting_target_any(self):
|
||||
with spack.config.override("compilers", compiler_configuration):
|
||||
s = spack.spec.Spec("a").concretized()
|
||||
assert s.satisfies("%gcc@12.1.0")
|
||||
|
||||
@pytest.mark.parametrize("spec_str", ["mpileaks", "mpileaks ^mpich"])
|
||||
def test_virtuals_are_annotated_on_edges(self, spec_str, default_mock_concretization):
|
||||
"""Tests that information on virtuals is annotated on DAG edges"""
|
||||
spec = default_mock_concretization(spec_str)
|
||||
mpi_provider = spec["mpi"].name
|
||||
|
||||
edges = spec.edges_to_dependencies(name=mpi_provider)
|
||||
assert len(edges) == 1 and edges[0].virtuals == ("mpi",)
|
||||
edges = spec.edges_to_dependencies(name="callpath")
|
||||
assert len(edges) == 1 and edges[0].virtuals == ()
|
||||
|
@@ -1,17 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
_module_raw() { return 1; };
|
||||
module() { return 1; };
|
||||
ml() { return 1; };
|
||||
export -f _module_raw;
|
||||
export -f module;
|
||||
export -f ml;
|
||||
|
||||
export MODULES_AUTO_HANDLING=1
|
||||
export __MODULES_LMCONFLICT=bar&foo
|
||||
export NEW_VAR=new
|
BIN
lib/spack/spack/test/data/specfiles/hdf5.v020.json.gz
Normal file
BIN
lib/spack/spack/test/data/specfiles/hdf5.v020.json.gz
Normal file
Binary file not shown.
@@ -31,194 +31,164 @@ class Amdfftw(FftwBase):
|
||||
Example : spack install amdfftw precision=float
|
||||
"""
|
||||
|
||||
_name = 'amdfftw'
|
||||
_name = "amdfftw"
|
||||
homepage = "https://developer.amd.com/amd-aocl/fftw/"
|
||||
url = "https://github.com/amd/amd-fftw/archive/3.0.tar.gz"
|
||||
git = "https://github.com/amd/amd-fftw.git"
|
||||
|
||||
maintainers = ['amd-toolchain-support']
|
||||
maintainers("amd-toolchain-support")
|
||||
|
||||
version('3.1', sha256='3e777f3acef13fa1910db097e818b1d0d03a6a36ef41186247c6ab1ab0afc132')
|
||||
version('3.0.1', sha256='87030c6bbb9c710f0a64f4f306ba6aa91dc4b182bb804c9022b35aef274d1a4c')
|
||||
version('3.0', sha256='a69deaf45478a59a69f77c4f7e9872967f1cfe996592dd12beb6318f18ea0bcd')
|
||||
version('2.2', sha256='de9d777236fb290c335860b458131678f75aa0799c641490c644c843f0e246f8')
|
||||
version("3.1", sha256="3e777f3acef13fa1910db097e818b1d0d03a6a36ef41186247c6ab1ab0afc132")
|
||||
version("3.0.1", sha256="87030c6bbb9c710f0a64f4f306ba6aa91dc4b182bb804c9022b35aef274d1a4c")
|
||||
version("3.0", sha256="a69deaf45478a59a69f77c4f7e9872967f1cfe996592dd12beb6318f18ea0bcd")
|
||||
version("2.2", sha256="de9d777236fb290c335860b458131678f75aa0799c641490c644c843f0e246f8")
|
||||
|
||||
variant('shared', default=True,
|
||||
description='Builds a shared version of the library')
|
||||
variant('openmp', default=True,
|
||||
description='Enable OpenMP support')
|
||||
variant('threads', default=False,
|
||||
description='Enable SMP threads support')
|
||||
variant('debug', default=False,
|
||||
description='Builds a debug version of the library')
|
||||
variant("shared", default=True, description="Builds a shared version of the library")
|
||||
variant("openmp", default=True, description="Enable OpenMP support")
|
||||
variant("threads", default=False, description="Enable SMP threads support")
|
||||
variant("debug", default=False, description="Builds a debug version of the library")
|
||||
variant(
|
||||
'amd-fast-planner',
|
||||
"amd-fast-planner",
|
||||
default=False,
|
||||
description='Option to reduce the planning time without much'
|
||||
'tradeoff in the performance. It is supported for'
|
||||
'Float and double precisions only.')
|
||||
description="Option to reduce the planning time without much"
|
||||
"tradeoff in the performance. It is supported for"
|
||||
"Float and double precisions only.",
|
||||
)
|
||||
variant("amd-top-n-planner", default=False, description="Build with amd-top-n-planner support")
|
||||
variant(
|
||||
'amd-top-n-planner',
|
||||
default=False,
|
||||
description='Build with amd-top-n-planner support')
|
||||
variant(
|
||||
'amd-mpi-vader-limit',
|
||||
default=False,
|
||||
description='Build with amd-mpi-vader-limit support')
|
||||
variant(
|
||||
'static',
|
||||
default=False,
|
||||
description='Build with static suppport')
|
||||
variant(
|
||||
'amd-trans',
|
||||
default=False,
|
||||
description='Build with amd-trans suppport')
|
||||
variant(
|
||||
'amd-app-opt',
|
||||
default=False,
|
||||
description='Build with amd-app-opt suppport')
|
||||
"amd-mpi-vader-limit", default=False, description="Build with amd-mpi-vader-limit support"
|
||||
)
|
||||
variant("static", default=False, description="Build with static suppport")
|
||||
variant("amd-trans", default=False, description="Build with amd-trans suppport")
|
||||
variant("amd-app-opt", default=False, description="Build with amd-app-opt suppport")
|
||||
|
||||
depends_on('texinfo')
|
||||
depends_on("texinfo")
|
||||
|
||||
provides('fftw-api@3', when='@2:')
|
||||
provides("fftw-api@3", when="@2:")
|
||||
|
||||
conflicts(
|
||||
'precision=quad',
|
||||
when='@2.2 %aocc',
|
||||
msg='Quad precision is not supported by AOCC clang version 2.2')
|
||||
"precision=quad",
|
||||
when="@2.2 %aocc",
|
||||
msg="Quad precision is not supported by AOCC clang version 2.2",
|
||||
)
|
||||
conflicts(
|
||||
'+debug',
|
||||
when='@2.2 %aocc',
|
||||
msg='debug mode is not supported by AOCC clang version 2.2')
|
||||
"+debug", when="@2.2 %aocc", msg="debug mode is not supported by AOCC clang version 2.2"
|
||||
)
|
||||
conflicts("%gcc@:7.2", when="@2.2:", msg="GCC version above 7.2 is required for AMDFFTW")
|
||||
conflicts(
|
||||
'%gcc@:7.2',
|
||||
when='@2.2:',
|
||||
msg='GCC version above 7.2 is required for AMDFFTW')
|
||||
"+amd-fast-planner ", when="+mpi", msg="mpi thread is not supported with amd-fast-planner"
|
||||
)
|
||||
conflicts(
|
||||
'+amd-fast-planner ',
|
||||
when='+mpi',
|
||||
msg='mpi thread is not supported with amd-fast-planner')
|
||||
"+amd-fast-planner", when="@2.2", msg="amd-fast-planner is supported from 3.0 onwards"
|
||||
)
|
||||
conflicts(
|
||||
'+amd-fast-planner',
|
||||
when='@2.2',
|
||||
msg='amd-fast-planner is supported from 3.0 onwards')
|
||||
"+amd-fast-planner",
|
||||
when="precision=quad",
|
||||
msg="Quad precision is not supported with amd-fast-planner",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-fast-planner',
|
||||
when='precision=quad',
|
||||
msg='Quad precision is not supported with amd-fast-planner')
|
||||
"+amd-fast-planner",
|
||||
when="precision=long_double",
|
||||
msg="long_double precision is not supported with amd-fast-planner",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-fast-planner',
|
||||
when='precision=long_double',
|
||||
msg='long_double precision is not supported with amd-fast-planner')
|
||||
"+amd-top-n-planner",
|
||||
when="@:3.0.0",
|
||||
msg="amd-top-n-planner is supported from 3.0.1 onwards",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-top-n-planner',
|
||||
when='@:3.0.0',
|
||||
msg='amd-top-n-planner is supported from 3.0.1 onwards')
|
||||
"+amd-top-n-planner",
|
||||
when="precision=long_double",
|
||||
msg="long_double precision is not supported with amd-top-n-planner",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-top-n-planner',
|
||||
when='precision=long_double',
|
||||
msg='long_double precision is not supported with amd-top-n-planner')
|
||||
"+amd-top-n-planner",
|
||||
when="precision=quad",
|
||||
msg="Quad precision is not supported with amd-top-n-planner",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-top-n-planner',
|
||||
when='precision=quad',
|
||||
msg='Quad precision is not supported with amd-top-n-planner')
|
||||
"+amd-top-n-planner",
|
||||
when="+amd-fast-planner",
|
||||
msg="amd-top-n-planner cannot be used with amd-fast-planner",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-top-n-planner',
|
||||
when='+amd-fast-planner',
|
||||
msg='amd-top-n-planner cannot be used with amd-fast-planner')
|
||||
"+amd-top-n-planner", when="+threads", msg="amd-top-n-planner works only for single thread"
|
||||
)
|
||||
conflicts(
|
||||
'+amd-top-n-planner',
|
||||
when='+threads',
|
||||
msg='amd-top-n-planner works only for single thread')
|
||||
"+amd-top-n-planner", when="+mpi", msg="mpi thread is not supported with amd-top-n-planner"
|
||||
)
|
||||
conflicts(
|
||||
'+amd-top-n-planner',
|
||||
when='+mpi',
|
||||
msg='mpi thread is not supported with amd-top-n-planner')
|
||||
"+amd-top-n-planner",
|
||||
when="+openmp",
|
||||
msg="openmp thread is not supported with amd-top-n-planner",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-top-n-planner',
|
||||
when='+openmp',
|
||||
msg='openmp thread is not supported with amd-top-n-planner')
|
||||
"+amd-mpi-vader-limit",
|
||||
when="@:3.0.0",
|
||||
msg="amd-mpi-vader-limit is supported from 3.0.1 onwards",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-mpi-vader-limit',
|
||||
when='@:3.0.0',
|
||||
msg='amd-mpi-vader-limit is supported from 3.0.1 onwards')
|
||||
"+amd-mpi-vader-limit",
|
||||
when="precision=quad",
|
||||
msg="Quad precision is not supported with amd-mpi-vader-limit",
|
||||
)
|
||||
conflicts("+amd-trans", when="+threads", msg="amd-trans works only for single thread")
|
||||
conflicts("+amd-trans", when="+mpi", msg="mpi thread is not supported with amd-trans")
|
||||
conflicts("+amd-trans", when="+openmp", msg="openmp thread is not supported with amd-trans")
|
||||
conflicts(
|
||||
'+amd-mpi-vader-limit',
|
||||
when='precision=quad',
|
||||
msg='Quad precision is not supported with amd-mpi-vader-limit')
|
||||
"+amd-trans",
|
||||
when="precision=long_double",
|
||||
msg="long_double precision is not supported with amd-trans",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-trans',
|
||||
when='+threads',
|
||||
msg='amd-trans works only for single thread')
|
||||
"+amd-trans", when="precision=quad", msg="Quad precision is not supported with amd-trans"
|
||||
)
|
||||
conflicts("+amd-app-opt", when="@:3.0.1", msg="amd-app-opt is supported from 3.1 onwards")
|
||||
conflicts("+amd-app-opt", when="+mpi", msg="mpi thread is not supported with amd-app-opt")
|
||||
conflicts(
|
||||
'+amd-trans',
|
||||
when='+mpi',
|
||||
msg='mpi thread is not supported with amd-trans')
|
||||
"+amd-app-opt",
|
||||
when="precision=long_double",
|
||||
msg="long_double precision is not supported with amd-app-opt",
|
||||
)
|
||||
conflicts(
|
||||
'+amd-trans',
|
||||
when='+openmp',
|
||||
msg='openmp thread is not supported with amd-trans')
|
||||
conflicts(
|
||||
'+amd-trans',
|
||||
when='precision=long_double',
|
||||
msg='long_double precision is not supported with amd-trans')
|
||||
conflicts(
|
||||
'+amd-trans',
|
||||
when='precision=quad',
|
||||
msg='Quad precision is not supported with amd-trans')
|
||||
conflicts(
|
||||
'+amd-app-opt',
|
||||
when='@:3.0.1',
|
||||
msg='amd-app-opt is supported from 3.1 onwards')
|
||||
conflicts(
|
||||
'+amd-app-opt',
|
||||
when='+mpi',
|
||||
msg='mpi thread is not supported with amd-app-opt')
|
||||
conflicts(
|
||||
'+amd-app-opt',
|
||||
when='precision=long_double',
|
||||
msg='long_double precision is not supported with amd-app-opt')
|
||||
conflicts(
|
||||
'+amd-app-opt',
|
||||
when='precision=quad',
|
||||
msg='Quad precision is not supported with amd-app-opt')
|
||||
"+amd-app-opt",
|
||||
when="precision=quad",
|
||||
msg="Quad precision is not supported with amd-app-opt",
|
||||
)
|
||||
|
||||
def configure(self, spec, prefix):
|
||||
"""Configure function"""
|
||||
# Base options
|
||||
options = [
|
||||
'--prefix={0}'.format(prefix),
|
||||
'--enable-amd-opt'
|
||||
]
|
||||
options = ["--prefix={0}".format(prefix), "--enable-amd-opt"]
|
||||
|
||||
# Check if compiler is AOCC
|
||||
if '%aocc' in spec:
|
||||
options.append('CC={0}'.format(os.path.basename(spack_cc)))
|
||||
options.append('FC={0}'.format(os.path.basename(spack_fc)))
|
||||
options.append('F77={0}'.format(os.path.basename(spack_fc)))
|
||||
if "%aocc" in spec:
|
||||
options.append("CC={0}".format(os.path.basename(spack_cc)))
|
||||
options.append("FC={0}".format(os.path.basename(spack_fc)))
|
||||
options.append("F77={0}".format(os.path.basename(spack_fc)))
|
||||
|
||||
if '+debug' in spec:
|
||||
options.append('--enable-debug')
|
||||
if "+debug" in spec:
|
||||
options.append("--enable-debug")
|
||||
|
||||
if '+mpi' in spec:
|
||||
options.append('--enable-mpi')
|
||||
options.append('--enable-amd-mpifft')
|
||||
if "+mpi" in spec:
|
||||
options.append("--enable-mpi")
|
||||
options.append("--enable-amd-mpifft")
|
||||
else:
|
||||
options.append('--disable-mpi')
|
||||
options.append('--disable-amd-mpifft')
|
||||
options.append("--disable-mpi")
|
||||
options.append("--disable-amd-mpifft")
|
||||
|
||||
options.extend(self.enable_or_disable('shared'))
|
||||
options.extend(self.enable_or_disable('openmp'))
|
||||
options.extend(self.enable_or_disable('threads'))
|
||||
options.extend(self.enable_or_disable('amd-fast-planner'))
|
||||
options.extend(self.enable_or_disable('amd-top-n-planner'))
|
||||
options.extend(self.enable_or_disable('amd-mpi-vader-limit'))
|
||||
options.extend(self.enable_or_disable('static'))
|
||||
options.extend(self.enable_or_disable('amd-trans'))
|
||||
options.extend(self.enable_or_disable('amd-app-opt'))
|
||||
options.extend(self.enable_or_disable("shared"))
|
||||
options.extend(self.enable_or_disable("openmp"))
|
||||
options.extend(self.enable_or_disable("threads"))
|
||||
options.extend(self.enable_or_disable("amd-fast-planner"))
|
||||
options.extend(self.enable_or_disable("amd-top-n-planner"))
|
||||
options.extend(self.enable_or_disable("amd-mpi-vader-limit"))
|
||||
options.extend(self.enable_or_disable("static"))
|
||||
options.extend(self.enable_or_disable("amd-trans"))
|
||||
options.extend(self.enable_or_disable("amd-app-opt"))
|
||||
|
||||
if not self.compiler.f77 or not self.compiler.fc:
|
||||
options.append('--disable-fortran')
|
||||
options.append("--disable-fortran")
|
||||
|
||||
# Cross compilation is supported in amd-fftw by making use of target
|
||||
# variable to set AMD_ARCH configure option.
|
||||
@@ -226,17 +196,16 @@ class Amdfftw(FftwBase):
|
||||
# use target variable to set appropriate -march option in AMD_ARCH.
|
||||
arch = spec.architecture
|
||||
options.append(
|
||||
'AMD_ARCH={0}'.format(
|
||||
arch.target.optimization_flags(
|
||||
spec.compiler).split('=')[-1]))
|
||||
"AMD_ARCH={0}".format(arch.target.optimization_flags(spec.compiler).split("=")[-1])
|
||||
)
|
||||
|
||||
# Specific SIMD support.
|
||||
# float and double precisions are supported
|
||||
simd_features = ['sse2', 'avx', 'avx2']
|
||||
simd_features = ["sse2", "avx", "avx2"]
|
||||
|
||||
simd_options = []
|
||||
for feature in simd_features:
|
||||
msg = '--enable-{0}' if feature in spec.target else '--disable-{0}'
|
||||
msg = "--enable-{0}" if feature in spec.target else "--disable-{0}"
|
||||
simd_options.append(msg.format(feature))
|
||||
|
||||
# When enabling configure option "--enable-amd-opt", do not use the
|
||||
@@ -246,20 +215,19 @@ class Amdfftw(FftwBase):
|
||||
# Double is the default precision, for all the others we need
|
||||
# to enable the corresponding option.
|
||||
enable_precision = {
|
||||
'float': ['--enable-float'],
|
||||
'double': None,
|
||||
'long_double': ['--enable-long-double'],
|
||||
'quad': ['--enable-quad-precision']
|
||||
"float": ["--enable-float"],
|
||||
"double": None,
|
||||
"long_double": ["--enable-long-double"],
|
||||
"quad": ["--enable-quad-precision"],
|
||||
}
|
||||
|
||||
# Different precisions must be configured and compiled one at a time
|
||||
configure = Executable('../configure')
|
||||
configure = Executable("../configure")
|
||||
for precision in self.selected_precisions:
|
||||
|
||||
opts = (enable_precision[precision] or []) + options[:]
|
||||
|
||||
# SIMD optimizations are available only for float and double
|
||||
if precision in ('float', 'double'):
|
||||
if precision in ("float", "double"):
|
||||
opts += simd_options
|
||||
|
||||
with working_dir(precision, create=True):
|
||||
|
@@ -16,21 +16,21 @@ from spack.package import *
|
||||
|
||||
class Llvm(CMakePackage, CudaPackage):
|
||||
"""The LLVM Project is a collection of modular and reusable compiler and
|
||||
toolchain technologies. Despite its name, LLVM has little to do
|
||||
with traditional virtual machines, though it does provide helpful
|
||||
libraries that can be used to build them. The name "LLVM" itself
|
||||
is not an acronym; it is the full name of the project.
|
||||
toolchain technologies. Despite its name, LLVM has little to do
|
||||
with traditional virtual machines, though it does provide helpful
|
||||
libraries that can be used to build them. The name "LLVM" itself
|
||||
is not an acronym; it is the full name of the project.
|
||||
"""
|
||||
|
||||
homepage = "https://llvm.org/"
|
||||
url = "https://github.com/llvm/llvm-project/archive/llvmorg-7.1.0.tar.gz"
|
||||
list_url = "https://releases.llvm.org/download.html"
|
||||
git = "https://github.com/llvm/llvm-project"
|
||||
maintainers = ['trws', 'haampie']
|
||||
maintainers("trws", "haampie")
|
||||
|
||||
tags = ['e4s']
|
||||
tags = ["e4s"]
|
||||
|
||||
generator = 'Ninja'
|
||||
generator = "Ninja"
|
||||
|
||||
family = "compiler" # Used by lmod
|
||||
|
||||
@@ -80,13 +80,12 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
# to save space, build with `build_type=Release`.
|
||||
|
||||
variant(
|
||||
"clang",
|
||||
default=True,
|
||||
description="Build the LLVM C/C++/Objective-C compiler frontend",
|
||||
"clang", default=True, description="Build the LLVM C/C++/Objective-C compiler frontend"
|
||||
)
|
||||
variant(
|
||||
"flang",
|
||||
default=False, when='@11: +clang',
|
||||
default=False,
|
||||
when="@11: +clang",
|
||||
description="Build the LLVM Fortran compiler frontend "
|
||||
"(experimental - parser only, needs GCC)",
|
||||
)
|
||||
@@ -95,27 +94,23 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
default=False,
|
||||
description="Include debugging code in OpenMP runtime libraries",
|
||||
)
|
||||
variant("lldb", default=True, when='+clang', description="Build the LLVM debugger")
|
||||
variant("lldb", default=True, when="+clang", description="Build the LLVM debugger")
|
||||
variant("lld", default=True, description="Build the LLVM linker")
|
||||
variant("mlir", default=False, when='@10:', description="Build with MLIR support")
|
||||
variant("mlir", default=False, when="@10:", description="Build with MLIR support")
|
||||
variant(
|
||||
"internal_unwind",
|
||||
default=True, when='+clang',
|
||||
description="Build the libcxxabi libunwind",
|
||||
"internal_unwind", default=True, when="+clang", description="Build the libcxxabi libunwind"
|
||||
)
|
||||
variant(
|
||||
"polly",
|
||||
default=True,
|
||||
description="Build the LLVM polyhedral optimization plugin, "
|
||||
"only builds for 3.7.0+",
|
||||
description="Build the LLVM polyhedral optimization plugin, " "only builds for 3.7.0+",
|
||||
)
|
||||
variant(
|
||||
"libcxx",
|
||||
default=True, when='+clang',
|
||||
description="Build the LLVM C++ standard library",
|
||||
"libcxx", default=True, when="+clang", description="Build the LLVM C++ standard library"
|
||||
)
|
||||
variant(
|
||||
"compiler-rt", when='+clang',
|
||||
"compiler-rt",
|
||||
when="+clang",
|
||||
default=True,
|
||||
description="Build LLVM compiler runtime, including sanitizers",
|
||||
)
|
||||
@@ -124,11 +119,7 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
default=(sys.platform != "darwin"),
|
||||
description="Add support for LTO with the gold linker plugin",
|
||||
)
|
||||
variant(
|
||||
"split_dwarf",
|
||||
default=False,
|
||||
description="Build with split dwarf information",
|
||||
)
|
||||
variant("split_dwarf", default=False, description="Build with split dwarf information")
|
||||
variant(
|
||||
"llvm_dylib",
|
||||
default=True,
|
||||
@@ -136,18 +127,40 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
)
|
||||
variant(
|
||||
"link_llvm_dylib",
|
||||
default=False, when='+llvm_dylib',
|
||||
default=False,
|
||||
when="+llvm_dylib",
|
||||
description="Link LLVM tools against the LLVM shared library",
|
||||
)
|
||||
variant(
|
||||
"targets",
|
||||
default="none",
|
||||
description=("What targets to build. Spack's target family is always added "
|
||||
"(e.g. X86 is automatically enabled when targeting znver2)."),
|
||||
values=("all", "none", "aarch64", "amdgpu", "arm", "avr", "bpf", "cppbackend",
|
||||
"hexagon", "lanai", "mips", "msp430", "nvptx", "powerpc", "riscv",
|
||||
"sparc", "systemz", "webassembly", "x86", "xcore"),
|
||||
multi=True
|
||||
description=(
|
||||
"What targets to build. Spack's target family is always added "
|
||||
"(e.g. X86 is automatically enabled when targeting znver2)."
|
||||
),
|
||||
values=(
|
||||
"all",
|
||||
"none",
|
||||
"aarch64",
|
||||
"amdgpu",
|
||||
"arm",
|
||||
"avr",
|
||||
"bpf",
|
||||
"cppbackend",
|
||||
"hexagon",
|
||||
"lanai",
|
||||
"mips",
|
||||
"msp430",
|
||||
"nvptx",
|
||||
"powerpc",
|
||||
"riscv",
|
||||
"sparc",
|
||||
"systemz",
|
||||
"webassembly",
|
||||
"x86",
|
||||
"xcore",
|
||||
),
|
||||
multi=True,
|
||||
)
|
||||
variant(
|
||||
"build_type",
|
||||
@@ -157,51 +170,52 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
)
|
||||
variant(
|
||||
"omp_tsan",
|
||||
default=False, when='@6:',
|
||||
default=False,
|
||||
when="@6:",
|
||||
description="Build with OpenMP capable thread sanitizer",
|
||||
)
|
||||
variant(
|
||||
"omp_as_runtime",
|
||||
default=True,
|
||||
when='+clang @12:',
|
||||
when="+clang @12:",
|
||||
description="Build OpenMP runtime via ENABLE_RUNTIME by just-built Clang",
|
||||
)
|
||||
variant('code_signing', default=False,
|
||||
when='+lldb platform=darwin',
|
||||
description="Enable code-signing on macOS")
|
||||
variant("python", default=False, description="Install python bindings")
|
||||
variant('version_suffix', default='none', description="Add a symbol suffix")
|
||||
variant(
|
||||
'shlib_symbol_version',
|
||||
default='none',
|
||||
"code_signing",
|
||||
default=False,
|
||||
when="+lldb platform=darwin",
|
||||
description="Enable code-signing on macOS",
|
||||
)
|
||||
variant("python", default=False, description="Install python bindings")
|
||||
variant("version_suffix", default="none", description="Add a symbol suffix")
|
||||
variant(
|
||||
"shlib_symbol_version",
|
||||
default="none",
|
||||
description="Add shared library symbol version",
|
||||
when='@13:'
|
||||
when="@13:",
|
||||
)
|
||||
variant(
|
||||
'z3',
|
||||
default=False,
|
||||
when='+clang @8:',
|
||||
description='Use Z3 for the clang static analyzer'
|
||||
"z3", default=False, when="+clang @8:", description="Use Z3 for the clang static analyzer"
|
||||
)
|
||||
|
||||
provides('libllvm@14', when='@14.0.0:14')
|
||||
provides('libllvm@13', when='@13.0.0:13')
|
||||
provides('libllvm@12', when='@12.0.0:12')
|
||||
provides('libllvm@11', when='@11.0.0:11')
|
||||
provides('libllvm@10', when='@10.0.0:10')
|
||||
provides('libllvm@9', when='@9.0.0:9')
|
||||
provides('libllvm@8', when='@8.0.0:8')
|
||||
provides('libllvm@7', when='@7.0.0:7')
|
||||
provides('libllvm@6', when='@6.0.0:6')
|
||||
provides('libllvm@5', when='@5.0.0:5')
|
||||
provides('libllvm@4', when='@4.0.0:4')
|
||||
provides('libllvm@3', when='@3.0.0:3')
|
||||
provides("libllvm@14", when="@14.0.0:14")
|
||||
provides("libllvm@13", when="@13.0.0:13")
|
||||
provides("libllvm@12", when="@12.0.0:12")
|
||||
provides("libllvm@11", when="@11.0.0:11")
|
||||
provides("libllvm@10", when="@10.0.0:10")
|
||||
provides("libllvm@9", when="@9.0.0:9")
|
||||
provides("libllvm@8", when="@8.0.0:8")
|
||||
provides("libllvm@7", when="@7.0.0:7")
|
||||
provides("libllvm@6", when="@6.0.0:6")
|
||||
provides("libllvm@5", when="@5.0.0:5")
|
||||
provides("libllvm@4", when="@4.0.0:4")
|
||||
provides("libllvm@3", when="@3.0.0:3")
|
||||
|
||||
extends("python", when="+python")
|
||||
|
||||
# Build dependency
|
||||
depends_on("cmake@3.4.3:", type="build")
|
||||
depends_on('cmake@3.13.4:', type='build', when='@12:')
|
||||
depends_on("cmake@3.13.4:", type="build", when="@12:")
|
||||
depends_on("ninja", type="build")
|
||||
depends_on("python@2.7:2.8", when="@:4 ~python", type="build")
|
||||
depends_on("python", when="@5: ~python", type="build")
|
||||
@@ -242,7 +256,7 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
# clang/lib: a lambda parameter cannot shadow an explicitly captured entity
|
||||
conflicts("%clang@8:", when="@:4")
|
||||
# Internal compiler error on gcc 8.4 on aarch64 https://bugzilla.redhat.com/show_bug.cgi?id=1958295
|
||||
conflicts('%gcc@8.4:8.4.9', when='@12: target=aarch64:')
|
||||
conflicts("%gcc@8.4:8.4.9", when="@12: target=aarch64:")
|
||||
|
||||
# When these versions are concretized, but not explicitly with +libcxx, these
|
||||
# conflicts will enable clingo to set ~libcxx, making the build successful:
|
||||
@@ -252,17 +266,17 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
# GCC 11 - latest stable release per GCC release page
|
||||
# Clang: 11, 12 - latest two stable releases per LLVM release page
|
||||
# AppleClang 12 - latest stable release per Xcode release page
|
||||
conflicts("%gcc@:10", when="@13:+libcxx")
|
||||
conflicts("%clang@:10", when="@13:+libcxx")
|
||||
conflicts("%gcc@:10", when="@13:+libcxx")
|
||||
conflicts("%clang@:10", when="@13:+libcxx")
|
||||
conflicts("%apple-clang@:11", when="@13:+libcxx")
|
||||
|
||||
# libcxx-4 and compiler-rt-4 fail to build with "newer" clang and gcc versions:
|
||||
conflicts('%gcc@7:', when='@:4+libcxx')
|
||||
conflicts('%clang@6:', when='@:4+libcxx')
|
||||
conflicts('%apple-clang@6:', when='@:4+libcxx')
|
||||
conflicts('%gcc@7:', when='@:4+compiler-rt')
|
||||
conflicts('%clang@6:', when='@:4+compiler-rt')
|
||||
conflicts('%apple-clang@6:', when='@:4+compiler-rt')
|
||||
conflicts("%gcc@7:", when="@:4+libcxx")
|
||||
conflicts("%clang@6:", when="@:4+libcxx")
|
||||
conflicts("%apple-clang@6:", when="@:4+libcxx")
|
||||
conflicts("%gcc@7:", when="@:4+compiler-rt")
|
||||
conflicts("%clang@6:", when="@:4+compiler-rt")
|
||||
conflicts("%apple-clang@6:", when="@:4+compiler-rt")
|
||||
|
||||
# cuda_arch value must be specified
|
||||
conflicts("cuda_arch=none", when="+cuda", msg="A value for cuda_arch must be specified.")
|
||||
@@ -270,27 +284,27 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
# LLVM bug https://bugs.llvm.org/show_bug.cgi?id=48234
|
||||
# CMake bug: https://gitlab.kitware.com/cmake/cmake/-/issues/21469
|
||||
# Fixed in upstream versions of both
|
||||
conflicts('^cmake@3.19.0', when='@6:11.0.0')
|
||||
conflicts("^cmake@3.19.0", when="@6:11.0.0")
|
||||
|
||||
# Github issue #4986
|
||||
patch("llvm_gcc7.patch", when="@4.0.0:4.0.1+lldb %gcc@7.0:")
|
||||
|
||||
# sys/ustat.h has been removed in favour of statfs from glibc-2.28. Use fixed sizes:
|
||||
patch('llvm5-sanitizer-ustat.patch', when="@4:6.0.0+compiler-rt")
|
||||
patch("llvm5-sanitizer-ustat.patch", when="@4:6.0.0+compiler-rt")
|
||||
|
||||
# Fix lld templates: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=230463
|
||||
patch('llvm4-lld-ELF-Symbols.patch', when="@4+lld%clang@6:")
|
||||
patch('llvm5-lld-ELF-Symbols.patch', when="@5+lld%clang@7:")
|
||||
patch("llvm4-lld-ELF-Symbols.patch", when="@4+lld%clang@6:")
|
||||
patch("llvm5-lld-ELF-Symbols.patch", when="@5+lld%clang@7:")
|
||||
|
||||
# Fix missing std:size_t in 'llvm@4:5' when built with '%clang@7:'
|
||||
patch('xray_buffer_queue-cstddef.patch', when="@4:5+compiler-rt%clang@7:")
|
||||
patch("xray_buffer_queue-cstddef.patch", when="@4:5+compiler-rt%clang@7:")
|
||||
|
||||
# https://github.com/llvm/llvm-project/commit/947f9692440836dcb8d88b74b69dd379d85974ce
|
||||
patch('sanitizer-ipc_perm_mode.patch', when="@5:7+compiler-rt%clang@11:")
|
||||
patch('sanitizer-ipc_perm_mode.patch', when="@5:9+compiler-rt%gcc@9:")
|
||||
patch("sanitizer-ipc_perm_mode.patch", when="@5:7+compiler-rt%clang@11:")
|
||||
patch("sanitizer-ipc_perm_mode.patch", when="@5:9+compiler-rt%gcc@9:")
|
||||
|
||||
# github.com/spack/spack/issues/24270: MicrosoftDemangle for %gcc@10: and %clang@13:
|
||||
patch('missing-includes.patch', when='@8')
|
||||
patch("missing-includes.patch", when="@8")
|
||||
|
||||
# Backport from llvm master + additional fix
|
||||
# see https://bugs.llvm.org/show_bug.cgi?id=39696
|
||||
@@ -315,33 +329,33 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
patch("llvm_python_path.patch", when="@:11")
|
||||
|
||||
# Workaround for issue https://github.com/spack/spack/issues/18197
|
||||
patch('llvm7_intel.patch', when='@7 %intel@18.0.2,19.0.0:19.1.99')
|
||||
patch("llvm7_intel.patch", when="@7 %intel@18.0.2,19.0.0:19.1.99")
|
||||
|
||||
# Remove cyclades support to build against newer kernel headers
|
||||
# https://reviews.llvm.org/D102059
|
||||
patch('no_cyclades.patch', when='@10:12.0.0')
|
||||
patch('no_cyclades9.patch', when='@6:9')
|
||||
patch("no_cyclades.patch", when="@10:12.0.0")
|
||||
patch("no_cyclades9.patch", when="@6:9")
|
||||
|
||||
patch('llvm-gcc11.patch', when='@9:11%gcc@11:')
|
||||
patch("llvm-gcc11.patch", when="@9:11%gcc@11:")
|
||||
|
||||
# add -lpthread to build OpenMP libraries with Fujitsu compiler
|
||||
patch('llvm12-thread.patch', when='@12 %fj')
|
||||
patch('llvm13-thread.patch', when='@13 %fj')
|
||||
patch("llvm12-thread.patch", when="@12 %fj")
|
||||
patch("llvm13-thread.patch", when="@13 %fj")
|
||||
|
||||
# avoid build failed with Fujitsu compiler
|
||||
patch('llvm13-fujitsu.patch', when='@13 %fj')
|
||||
patch("llvm13-fujitsu.patch", when="@13 %fj")
|
||||
|
||||
# patch for missing hwloc.h include for libompd
|
||||
patch('llvm14-hwloc-ompd.patch', when='@14')
|
||||
patch("llvm14-hwloc-ompd.patch", when="@14")
|
||||
|
||||
# make libflags a list in openmp subproject when ~omp_as_runtime
|
||||
patch('libomp-libflags-as-list.patch', when='@3.7:')
|
||||
patch("libomp-libflags-as-list.patch", when="@3.7:")
|
||||
|
||||
# The functions and attributes below implement external package
|
||||
# detection for LLVM. See:
|
||||
#
|
||||
# https://spack.readthedocs.io/en/latest/packaging_guide.html#making-a-package-discoverable-with-spack-external-find
|
||||
executables = ['clang', 'flang', 'ld.lld', 'lldb']
|
||||
executables = ["clang", "flang", "ld.lld", "lldb"]
|
||||
|
||||
@classmethod
|
||||
def filter_detected_exes(cls, prefix, exes_in_prefix):
|
||||
@@ -351,7 +365,7 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
# on some port and would hang Spack during detection.
|
||||
# clang-cl and clang-cpp are dev tools that we don't
|
||||
# need to test
|
||||
if any(x in exe for x in ('vscode', 'cpp', '-cl', '-gpu')):
|
||||
if any(x in exe for x in ("vscode", "cpp", "-cl", "-gpu")):
|
||||
continue
|
||||
result.append(exe)
|
||||
return result
|
||||
@@ -360,20 +374,20 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
def determine_version(cls, exe):
|
||||
version_regex = re.compile(
|
||||
# Normal clang compiler versions are left as-is
|
||||
r'clang version ([^ )\n]+)-svn[~.\w\d-]*|'
|
||||
r"clang version ([^ )\n]+)-svn[~.\w\d-]*|"
|
||||
# Don't include hyphenated patch numbers in the version
|
||||
# (see https://github.com/spack/spack/pull/14365 for details)
|
||||
r'clang version ([^ )\n]+?)-[~.\w\d-]*|'
|
||||
r'clang version ([^ )\n]+)|'
|
||||
r"clang version ([^ )\n]+?)-[~.\w\d-]*|"
|
||||
r"clang version ([^ )\n]+)|"
|
||||
# LLDB
|
||||
r'lldb version ([^ )\n]+)|'
|
||||
r"lldb version ([^ )\n]+)|"
|
||||
# LLD
|
||||
r'LLD ([^ )\n]+) \(compatible with GNU linkers\)'
|
||||
r"LLD ([^ )\n]+) \(compatible with GNU linkers\)"
|
||||
)
|
||||
try:
|
||||
compiler = Executable(exe)
|
||||
output = compiler('--version', output=str, error=str)
|
||||
if 'Apple' in output:
|
||||
output = compiler("--version", output=str, error=str)
|
||||
if "Apple" in output:
|
||||
return None
|
||||
match = version_regex.search(output)
|
||||
if match:
|
||||
@@ -387,38 +401,39 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
|
||||
@classmethod
|
||||
def determine_variants(cls, exes, version_str):
|
||||
variants, compilers = ['+clang'], {}
|
||||
variants, compilers = ["+clang"], {}
|
||||
lld_found, lldb_found = False, False
|
||||
for exe in exes:
|
||||
if 'clang++' in exe:
|
||||
compilers['cxx'] = exe
|
||||
elif 'clang' in exe:
|
||||
compilers['c'] = exe
|
||||
elif 'flang' in exe:
|
||||
variants.append('+flang')
|
||||
compilers['fc'] = exe
|
||||
compilers['f77'] = exe
|
||||
elif 'ld.lld' in exe:
|
||||
if "clang++" in exe:
|
||||
compilers["cxx"] = exe
|
||||
elif "clang" in exe:
|
||||
compilers["c"] = exe
|
||||
elif "flang" in exe:
|
||||
variants.append("+flang")
|
||||
compilers["fc"] = exe
|
||||
compilers["f77"] = exe
|
||||
elif "ld.lld" in exe:
|
||||
lld_found = True
|
||||
compilers['ld'] = exe
|
||||
elif 'lldb' in exe:
|
||||
compilers["ld"] = exe
|
||||
elif "lldb" in exe:
|
||||
lldb_found = True
|
||||
compilers['lldb'] = exe
|
||||
compilers["lldb"] = exe
|
||||
|
||||
variants.append('+lld' if lld_found else '~lld')
|
||||
variants.append('+lldb' if lldb_found else '~lldb')
|
||||
variants.append("+lld" if lld_found else "~lld")
|
||||
variants.append("+lldb" if lldb_found else "~lldb")
|
||||
|
||||
return ''.join(variants), {'compilers': compilers}
|
||||
return "".join(variants), {"compilers": compilers}
|
||||
|
||||
@classmethod
|
||||
def validate_detected_spec(cls, spec, extra_attributes):
|
||||
# For LLVM 'compilers' is a mandatory attribute
|
||||
msg = ('the extra attribute "compilers" must be set for '
|
||||
'the detected spec "{0}"'.format(spec))
|
||||
assert 'compilers' in extra_attributes, msg
|
||||
compilers = extra_attributes['compilers']
|
||||
for key in ('c', 'cxx'):
|
||||
msg = '{0} compiler not found for {1}'
|
||||
msg = 'the extra attribute "compilers" must be set for ' 'the detected spec "{0}"'.format(
|
||||
spec
|
||||
)
|
||||
assert "compilers" in extra_attributes, msg
|
||||
compilers = extra_attributes["compilers"]
|
||||
for key in ("c", "cxx"):
|
||||
msg = "{0} compiler not found for {1}"
|
||||
assert key in compilers, msg.format(key, spec)
|
||||
|
||||
@property
|
||||
@@ -426,10 +441,10 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
msg = "cannot retrieve C compiler [spec is not concrete]"
|
||||
assert self.spec.concrete, msg
|
||||
if self.spec.external:
|
||||
return self.spec.extra_attributes['compilers'].get('c', None)
|
||||
return self.spec.extra_attributes["compilers"].get("c", None)
|
||||
result = None
|
||||
if '+clang' in self.spec:
|
||||
result = os.path.join(self.spec.prefix.bin, 'clang')
|
||||
if "+clang" in self.spec:
|
||||
result = os.path.join(self.spec.prefix.bin, "clang")
|
||||
return result
|
||||
|
||||
@property
|
||||
@@ -437,10 +452,10 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
msg = "cannot retrieve C++ compiler [spec is not concrete]"
|
||||
assert self.spec.concrete, msg
|
||||
if self.spec.external:
|
||||
return self.spec.extra_attributes['compilers'].get('cxx', None)
|
||||
return self.spec.extra_attributes["compilers"].get("cxx", None)
|
||||
result = None
|
||||
if '+clang' in self.spec:
|
||||
result = os.path.join(self.spec.prefix.bin, 'clang++')
|
||||
if "+clang" in self.spec:
|
||||
result = os.path.join(self.spec.prefix.bin, "clang++")
|
||||
return result
|
||||
|
||||
@property
|
||||
@@ -448,10 +463,10 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
msg = "cannot retrieve Fortran compiler [spec is not concrete]"
|
||||
assert self.spec.concrete, msg
|
||||
if self.spec.external:
|
||||
return self.spec.extra_attributes['compilers'].get('fc', None)
|
||||
return self.spec.extra_attributes["compilers"].get("fc", None)
|
||||
result = None
|
||||
if '+flang' in self.spec:
|
||||
result = os.path.join(self.spec.prefix.bin, 'flang')
|
||||
if "+flang" in self.spec:
|
||||
result = os.path.join(self.spec.prefix.bin, "flang")
|
||||
return result
|
||||
|
||||
@property
|
||||
@@ -459,27 +474,25 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
msg = "cannot retrieve Fortran 77 compiler [spec is not concrete]"
|
||||
assert self.spec.concrete, msg
|
||||
if self.spec.external:
|
||||
return self.spec.extra_attributes['compilers'].get('f77', None)
|
||||
return self.spec.extra_attributes["compilers"].get("f77", None)
|
||||
result = None
|
||||
if '+flang' in self.spec:
|
||||
result = os.path.join(self.spec.prefix.bin, 'flang')
|
||||
if "+flang" in self.spec:
|
||||
result = os.path.join(self.spec.prefix.bin, "flang")
|
||||
return result
|
||||
|
||||
@property
|
||||
def libs(self):
|
||||
return LibraryList(self.llvm_config("--libfiles", "all",
|
||||
result="list"))
|
||||
return LibraryList(self.llvm_config("--libfiles", "all", result="list"))
|
||||
|
||||
@run_before('cmake')
|
||||
@run_before("cmake")
|
||||
def codesign_check(self):
|
||||
if self.spec.satisfies("+code_signing"):
|
||||
codesign = which('codesign')
|
||||
mkdir('tmp')
|
||||
llvm_check_file = join_path('tmp', 'llvm_check')
|
||||
copy('/usr/bin/false', llvm_check_file)
|
||||
codesign = which("codesign")
|
||||
mkdir("tmp")
|
||||
llvm_check_file = join_path("tmp", "llvm_check")
|
||||
copy("/usr/bin/false", llvm_check_file)
|
||||
try:
|
||||
codesign('-f', '-s', 'lldb_codesign', '--dryrun',
|
||||
llvm_check_file)
|
||||
codesign("-f", "-s", "lldb_codesign", "--dryrun", llvm_check_file)
|
||||
|
||||
except ProcessError:
|
||||
# Newer LLVM versions have a simple script that sets up
|
||||
@@ -489,32 +502,32 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
setup()
|
||||
except Exception:
|
||||
raise RuntimeError(
|
||||
'spack was unable to either find or set up'
|
||||
'code-signing on your system. Please refer to'
|
||||
'https://lldb.llvm.org/resources/build.html#'
|
||||
'code-signing-on-macos for details on how to'
|
||||
'create this identity.'
|
||||
"spack was unable to either find or set up"
|
||||
"code-signing on your system. Please refer to"
|
||||
"https://lldb.llvm.org/resources/build.html#"
|
||||
"code-signing-on-macos for details on how to"
|
||||
"create this identity."
|
||||
)
|
||||
|
||||
def flag_handler(self, name, flags):
|
||||
if name == 'cxxflags':
|
||||
if name == "cxxflags":
|
||||
flags.append(self.compiler.cxx11_flag)
|
||||
return(None, flags, None)
|
||||
elif name == 'ldflags' and self.spec.satisfies('%intel'):
|
||||
flags.append('-shared-intel')
|
||||
return(None, flags, None)
|
||||
return(flags, None, None)
|
||||
return (None, flags, None)
|
||||
elif name == "ldflags" and self.spec.satisfies("%intel"):
|
||||
flags.append("-shared-intel")
|
||||
return (None, flags, None)
|
||||
return (flags, None, None)
|
||||
|
||||
def setup_build_environment(self, env):
|
||||
"""When using %clang, add only its ld.lld-$ver and/or ld.lld to our PATH"""
|
||||
if self.compiler.name in ['clang', 'apple-clang']:
|
||||
for lld in 'ld.lld-{0}'.format(self.compiler.version.version[0]), 'ld.lld':
|
||||
if self.compiler.name in ["clang", "apple-clang"]:
|
||||
for lld in "ld.lld-{0}".format(self.compiler.version.version[0]), "ld.lld":
|
||||
bin = os.path.join(os.path.dirname(self.compiler.cc), lld)
|
||||
sym = os.path.join(self.stage.path, 'ld.lld')
|
||||
sym = os.path.join(self.stage.path, "ld.lld")
|
||||
if os.path.exists(bin) and not os.path.exists(sym):
|
||||
mkdirp(self.stage.path)
|
||||
os.symlink(bin, sym)
|
||||
env.prepend_path('PATH', self.stage.path)
|
||||
env.prepend_path("PATH", self.stage.path)
|
||||
|
||||
def setup_run_environment(self, env):
|
||||
if "+clang" in self.spec:
|
||||
@@ -531,7 +544,7 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
define = CMakePackage.define
|
||||
from_variant = self.define_from_variant
|
||||
|
||||
python = spec['python']
|
||||
python = spec["python"]
|
||||
cmake_args = [
|
||||
define("LLVM_REQUIRES_RTTI", True),
|
||||
define("LLVM_ENABLE_RTTI", True),
|
||||
@@ -544,14 +557,13 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
define("LIBOMP_HWLOC_INSTALL_DIR", spec["hwloc"].prefix),
|
||||
]
|
||||
|
||||
version_suffix = spec.variants['version_suffix'].value
|
||||
if version_suffix != 'none':
|
||||
cmake_args.append(define('LLVM_VERSION_SUFFIX', version_suffix))
|
||||
version_suffix = spec.variants["version_suffix"].value
|
||||
if version_suffix != "none":
|
||||
cmake_args.append(define("LLVM_VERSION_SUFFIX", version_suffix))
|
||||
|
||||
shlib_symbol_version = spec.variants.get('shlib_symbol_version', None)
|
||||
if shlib_symbol_version is not None and shlib_symbol_version.value != 'none':
|
||||
cmake_args.append(define('LLVM_SHLIB_SYMBOL_VERSION',
|
||||
shlib_symbol_version.value))
|
||||
shlib_symbol_version = spec.variants.get("shlib_symbol_version", None)
|
||||
if shlib_symbol_version is not None and shlib_symbol_version.value != "none":
|
||||
cmake_args.append(define("LLVM_SHLIB_SYMBOL_VERSION", shlib_symbol_version.value))
|
||||
|
||||
if python.version >= Version("3"):
|
||||
cmake_args.append(define("Python3_EXECUTABLE", python.command.path))
|
||||
@@ -562,47 +574,56 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
runtimes = []
|
||||
|
||||
if "+cuda" in spec:
|
||||
cmake_args.extend([
|
||||
define("CUDA_TOOLKIT_ROOT_DIR", spec["cuda"].prefix),
|
||||
define("LIBOMPTARGET_NVPTX_COMPUTE_CAPABILITIES",
|
||||
",".join(spec.variants["cuda_arch"].value)),
|
||||
define("CLANG_OPENMP_NVPTX_DEFAULT_ARCH",
|
||||
"sm_{0}".format(spec.variants["cuda_arch"].value[-1])),
|
||||
])
|
||||
cmake_args.extend(
|
||||
[
|
||||
define("CUDA_TOOLKIT_ROOT_DIR", spec["cuda"].prefix),
|
||||
define(
|
||||
"LIBOMPTARGET_NVPTX_COMPUTE_CAPABILITIES",
|
||||
",".join(spec.variants["cuda_arch"].value),
|
||||
),
|
||||
define(
|
||||
"CLANG_OPENMP_NVPTX_DEFAULT_ARCH",
|
||||
"sm_{0}".format(spec.variants["cuda_arch"].value[-1]),
|
||||
),
|
||||
]
|
||||
)
|
||||
if "+omp_as_runtime" in spec:
|
||||
cmake_args.extend([
|
||||
define("LIBOMPTARGET_NVPTX_ENABLE_BCLIB", True),
|
||||
# work around bad libelf detection in libomptarget
|
||||
define("LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR",
|
||||
spec["libelf"].prefix.include),
|
||||
])
|
||||
cmake_args.extend(
|
||||
[
|
||||
define("LIBOMPTARGET_NVPTX_ENABLE_BCLIB", True),
|
||||
# work around bad libelf detection in libomptarget
|
||||
define(
|
||||
"LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR", spec["libelf"].prefix.include
|
||||
),
|
||||
]
|
||||
)
|
||||
else:
|
||||
# still build libomptarget but disable cuda
|
||||
cmake_args.extend([
|
||||
define("CUDA_TOOLKIT_ROOT_DIR", "IGNORE"),
|
||||
define("CUDA_SDK_ROOT_DIR", "IGNORE"),
|
||||
define("CUDA_NVCC_EXECUTABLE", "IGNORE"),
|
||||
define("LIBOMPTARGET_DEP_CUDA_DRIVER_LIBRARIES", "IGNORE"),
|
||||
])
|
||||
cmake_args.extend(
|
||||
[
|
||||
define("CUDA_TOOLKIT_ROOT_DIR", "IGNORE"),
|
||||
define("CUDA_SDK_ROOT_DIR", "IGNORE"),
|
||||
define("CUDA_NVCC_EXECUTABLE", "IGNORE"),
|
||||
define("LIBOMPTARGET_DEP_CUDA_DRIVER_LIBRARIES", "IGNORE"),
|
||||
]
|
||||
)
|
||||
|
||||
cmake_args.append(from_variant("LIBOMPTARGET_ENABLE_DEBUG", "omp_debug"))
|
||||
|
||||
if "+lldb" in spec:
|
||||
projects.append("lldb")
|
||||
cmake_args.append(define('LLDB_ENABLE_LIBEDIT', True))
|
||||
cmake_args.append(define('LLDB_ENABLE_NCURSES', True))
|
||||
cmake_args.append(define('LLDB_ENABLE_LIBXML2', False))
|
||||
if spec.version >= Version('10'):
|
||||
cmake_args.append(from_variant("LLDB_ENABLE_PYTHON", 'python'))
|
||||
cmake_args.append(define("LLDB_ENABLE_LIBEDIT", True))
|
||||
cmake_args.append(define("LLDB_ENABLE_NCURSES", True))
|
||||
cmake_args.append(define("LLDB_ENABLE_LIBXML2", False))
|
||||
if spec.version >= Version("10"):
|
||||
cmake_args.append(from_variant("LLDB_ENABLE_PYTHON", "python"))
|
||||
else:
|
||||
cmake_args.append(define("LLDB_DISABLE_PYTHON", '~python' in spec))
|
||||
cmake_args.append(define("LLDB_DISABLE_PYTHON", "~python" in spec))
|
||||
if spec.satisfies("@5.0.0: +python"):
|
||||
cmake_args.append(define("LLDB_USE_SYSTEM_SIX", True))
|
||||
|
||||
if "+gold" in spec:
|
||||
cmake_args.append(
|
||||
define("LLVM_BINUTILS_INCDIR", spec["binutils"].prefix.include)
|
||||
)
|
||||
cmake_args.append(define("LLVM_BINUTILS_INCDIR", spec["binutils"].prefix.include))
|
||||
|
||||
if "+clang" in spec:
|
||||
projects.append("clang")
|
||||
@@ -612,10 +633,10 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
else:
|
||||
projects.append("openmp")
|
||||
|
||||
if '@8' in spec:
|
||||
cmake_args.append(from_variant('CLANG_ANALYZER_ENABLE_Z3_SOLVER', 'z3'))
|
||||
elif '@9:' in spec:
|
||||
cmake_args.append(from_variant('LLVM_ENABLE_Z3_SOLVER', 'z3'))
|
||||
if "@8" in spec:
|
||||
cmake_args.append(from_variant("CLANG_ANALYZER_ENABLE_Z3_SOLVER", "z3"))
|
||||
elif "@9:" in spec:
|
||||
cmake_args.append(from_variant("LLVM_ENABLE_Z3_SOLVER", "z3"))
|
||||
|
||||
if "+flang" in spec:
|
||||
projects.append("flang")
|
||||
@@ -634,26 +655,26 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
projects.append("polly")
|
||||
cmake_args.append(define("LINK_POLLY_INTO_TOOLS", True))
|
||||
|
||||
cmake_args.extend([
|
||||
define("BUILD_SHARED_LIBS", False),
|
||||
from_variant("LLVM_BUILD_LLVM_DYLIB", "llvm_dylib"),
|
||||
from_variant("LLVM_LINK_LLVM_DYLIB", "link_llvm_dylib"),
|
||||
from_variant("LLVM_USE_SPLIT_DWARF", "split_dwarf"),
|
||||
# By default on Linux, libc++.so is a ldscript. CMake fails to add
|
||||
# CMAKE_INSTALL_RPATH to it, which fails. Statically link libc++abi.a
|
||||
# into libc++.so, linking with -lc++ or -stdlib=libc++ is enough.
|
||||
define('LIBCXX_ENABLE_STATIC_ABI_LIBRARY', True)
|
||||
])
|
||||
cmake_args.extend(
|
||||
[
|
||||
define("BUILD_SHARED_LIBS", False),
|
||||
from_variant("LLVM_BUILD_LLVM_DYLIB", "llvm_dylib"),
|
||||
from_variant("LLVM_LINK_LLVM_DYLIB", "link_llvm_dylib"),
|
||||
from_variant("LLVM_USE_SPLIT_DWARF", "split_dwarf"),
|
||||
# By default on Linux, libc++.so is a ldscript. CMake fails to add
|
||||
# CMAKE_INSTALL_RPATH to it, which fails. Statically link libc++abi.a
|
||||
# into libc++.so, linking with -lc++ or -stdlib=libc++ is enough.
|
||||
define("LIBCXX_ENABLE_STATIC_ABI_LIBRARY", True),
|
||||
]
|
||||
)
|
||||
|
||||
cmake_args.append(define(
|
||||
"LLVM_TARGETS_TO_BUILD",
|
||||
get_llvm_targets_to_build(spec)))
|
||||
cmake_args.append(define("LLVM_TARGETS_TO_BUILD", get_llvm_targets_to_build(spec)))
|
||||
|
||||
cmake_args.append(from_variant("LIBOMP_TSAN_SUPPORT", "omp_tsan"))
|
||||
|
||||
if self.compiler.name == "gcc":
|
||||
compiler = Executable(self.compiler.cc)
|
||||
gcc_output = compiler('-print-search-dirs', output=str, error=str)
|
||||
gcc_output = compiler("-print-search-dirs", output=str, error=str)
|
||||
|
||||
for line in gcc_output.splitlines():
|
||||
if line.startswith("install:"):
|
||||
@@ -665,7 +686,7 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
cmake_args.append(define("GCC_INSTALL_PREFIX", gcc_prefix))
|
||||
|
||||
if self.spec.satisfies("~code_signing platform=darwin"):
|
||||
cmake_args.append(define('LLDB_USE_SYSTEM_DEBUGSERVER', True))
|
||||
cmake_args.append(define("LLDB_USE_SYSTEM_DEBUGSERVER", True))
|
||||
|
||||
# Semicolon seperated list of projects to enable
|
||||
cmake_args.append(define("LLVM_ENABLE_PROJECTS", projects))
|
||||
@@ -689,20 +710,24 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
# rebuild libomptarget to get bytecode runtime library files
|
||||
with working_dir(ompdir, create=True):
|
||||
cmake_args = [
|
||||
'-G', 'Ninja',
|
||||
define('CMAKE_BUILD_TYPE', spec.variants['build_type'].value),
|
||||
"-G",
|
||||
"Ninja",
|
||||
define("CMAKE_BUILD_TYPE", spec.variants["build_type"].value),
|
||||
define("CMAKE_C_COMPILER", spec.prefix.bin + "/clang"),
|
||||
define("CMAKE_CXX_COMPILER", spec.prefix.bin + "/clang++"),
|
||||
define("CMAKE_INSTALL_PREFIX", spec.prefix),
|
||||
define('CMAKE_PREFIX_PATH', prefix_paths)
|
||||
define("CMAKE_PREFIX_PATH", prefix_paths),
|
||||
]
|
||||
cmake_args.extend(self.cmake_args())
|
||||
cmake_args.extend([
|
||||
define("LIBOMPTARGET_NVPTX_ENABLE_BCLIB", True),
|
||||
define("LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR",
|
||||
spec["libelf"].prefix.include),
|
||||
self.stage.source_path + "/openmp",
|
||||
])
|
||||
cmake_args.extend(
|
||||
[
|
||||
define("LIBOMPTARGET_NVPTX_ENABLE_BCLIB", True),
|
||||
define(
|
||||
"LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR", spec["libelf"].prefix.include
|
||||
),
|
||||
self.stage.source_path + "/openmp",
|
||||
]
|
||||
)
|
||||
|
||||
cmake(*cmake_args)
|
||||
ninja()
|
||||
@@ -717,22 +742,22 @@ class Llvm(CMakePackage, CudaPackage):
|
||||
install_tree("bin", join_path(self.prefix, "libexec", "llvm"))
|
||||
|
||||
def llvm_config(self, *args, **kwargs):
|
||||
lc = Executable(self.prefix.bin.join('llvm-config'))
|
||||
if not kwargs.get('output'):
|
||||
kwargs['output'] = str
|
||||
lc = Executable(self.prefix.bin.join("llvm-config"))
|
||||
if not kwargs.get("output"):
|
||||
kwargs["output"] = str
|
||||
ret = lc(*args, **kwargs)
|
||||
if kwargs.get('result') == "list":
|
||||
if kwargs.get("result") == "list":
|
||||
return ret.split()
|
||||
else:
|
||||
return ret
|
||||
|
||||
|
||||
def get_llvm_targets_to_build(spec):
|
||||
targets = spec.variants['targets'].value
|
||||
targets = spec.variants["targets"].value
|
||||
|
||||
# Build everything?
|
||||
if 'all' in targets:
|
||||
return 'all'
|
||||
if "all" in targets:
|
||||
return "all"
|
||||
|
||||
# Convert targets variant values to CMake LLVM_TARGETS_TO_BUILD array.
|
||||
spack_to_cmake = {
|
||||
@@ -753,10 +778,10 @@ def get_llvm_targets_to_build(spec):
|
||||
"systemz": "SystemZ",
|
||||
"webassembly": "WebAssembly",
|
||||
"x86": "X86",
|
||||
"xcore": "XCore"
|
||||
"xcore": "XCore",
|
||||
}
|
||||
|
||||
if 'none' in targets:
|
||||
if "none" in targets:
|
||||
llvm_targets = set()
|
||||
else:
|
||||
llvm_targets = set(spack_to_cmake[target] for target in targets)
|
||||
|
@@ -22,127 +22,140 @@ class PyTorch(PythonPackage, CudaPackage):
|
||||
with strong GPU acceleration."""
|
||||
|
||||
homepage = "https://pytorch.org/"
|
||||
git = "https://github.com/pytorch/pytorch.git"
|
||||
git = "https://github.com/pytorch/pytorch.git"
|
||||
|
||||
maintainers = ['adamjstewart']
|
||||
maintainers("adamjstewart")
|
||||
|
||||
# Exact set of modules is version- and variant-specific, just attempt to import the
|
||||
# core libraries to ensure that the package was successfully installed.
|
||||
import_modules = ['torch', 'torch.autograd', 'torch.nn', 'torch.utils']
|
||||
import_modules = ["torch", "torch.autograd", "torch.nn", "torch.utils"]
|
||||
|
||||
version('master', branch='master', submodules=True)
|
||||
version('1.10.1', tag='v1.10.1', submodules=True)
|
||||
version('1.10.0', tag='v1.10.0', submodules=True)
|
||||
version('1.9.1', tag='v1.9.1', submodules=True)
|
||||
version('1.9.0', tag='v1.9.0', submodules=True)
|
||||
version('1.8.2', tag='v1.8.2', submodules=True)
|
||||
version('1.8.1', tag='v1.8.1', submodules=True)
|
||||
version('1.8.0', tag='v1.8.0', submodules=True)
|
||||
version('1.7.1', tag='v1.7.1', submodules=True)
|
||||
version('1.7.0', tag='v1.7.0', submodules=True)
|
||||
version('1.6.0', tag='v1.6.0', submodules=True)
|
||||
version('1.5.1', tag='v1.5.1', submodules=True)
|
||||
version('1.5.0', tag='v1.5.0', submodules=True)
|
||||
version('1.4.1', tag='v1.4.1', submodules=True)
|
||||
version('1.4.0', tag='v1.4.0', submodules=True, deprecated=True,
|
||||
submodules_delete=['third_party/fbgemm'])
|
||||
version('1.3.1', tag='v1.3.1', submodules=True)
|
||||
version('1.3.0', tag='v1.3.0', submodules=True)
|
||||
version('1.2.0', tag='v1.2.0', submodules=True)
|
||||
version('1.1.0', tag='v1.1.0', submodules=True)
|
||||
version('1.0.1', tag='v1.0.1', submodules=True)
|
||||
version('1.0.0', tag='v1.0.0', submodules=True)
|
||||
version('0.4.1', tag='v0.4.1', submodules=True, deprecated=True,
|
||||
submodules_delete=['third_party/nervanagpu'])
|
||||
version('0.4.0', tag='v0.4.0', submodules=True, deprecated=True)
|
||||
version('0.3.1', tag='v0.3.1', submodules=True, deprecated=True)
|
||||
version("master", branch="master", submodules=True)
|
||||
version("1.10.1", tag="v1.10.1", submodules=True)
|
||||
version("1.10.0", tag="v1.10.0", submodules=True)
|
||||
version("1.9.1", tag="v1.9.1", submodules=True)
|
||||
version("1.9.0", tag="v1.9.0", submodules=True)
|
||||
version("1.8.2", tag="v1.8.2", submodules=True)
|
||||
version("1.8.1", tag="v1.8.1", submodules=True)
|
||||
version("1.8.0", tag="v1.8.0", submodules=True)
|
||||
version("1.7.1", tag="v1.7.1", submodules=True)
|
||||
version("1.7.0", tag="v1.7.0", submodules=True)
|
||||
version("1.6.0", tag="v1.6.0", submodules=True)
|
||||
version("1.5.1", tag="v1.5.1", submodules=True)
|
||||
version("1.5.0", tag="v1.5.0", submodules=True)
|
||||
version("1.4.1", tag="v1.4.1", submodules=True)
|
||||
version(
|
||||
"1.4.0",
|
||||
tag="v1.4.0",
|
||||
submodules=True,
|
||||
deprecated=True,
|
||||
submodules_delete=["third_party/fbgemm"],
|
||||
)
|
||||
version("1.3.1", tag="v1.3.1", submodules=True)
|
||||
version("1.3.0", tag="v1.3.0", submodules=True)
|
||||
version("1.2.0", tag="v1.2.0", submodules=True)
|
||||
version("1.1.0", tag="v1.1.0", submodules=True)
|
||||
version("1.0.1", tag="v1.0.1", submodules=True)
|
||||
version("1.0.0", tag="v1.0.0", submodules=True)
|
||||
version(
|
||||
"0.4.1",
|
||||
tag="v0.4.1",
|
||||
submodules=True,
|
||||
deprecated=True,
|
||||
submodules_delete=["third_party/nervanagpu"],
|
||||
)
|
||||
version("0.4.0", tag="v0.4.0", submodules=True, deprecated=True)
|
||||
version("0.3.1", tag="v0.3.1", submodules=True, deprecated=True)
|
||||
|
||||
is_darwin = sys.platform == 'darwin'
|
||||
is_darwin = sys.platform == "darwin"
|
||||
|
||||
# All options are defined in CMakeLists.txt.
|
||||
# Some are listed in setup.py, but not all.
|
||||
variant('caffe2', default=True, description='Build Caffe2')
|
||||
variant('test', default=False, description='Build C++ test binaries')
|
||||
variant('cuda', default=not is_darwin, description='Use CUDA')
|
||||
variant('rocm', default=False, description='Use ROCm')
|
||||
variant('cudnn', default=not is_darwin, description='Use cuDNN')
|
||||
variant('fbgemm', default=True, description='Use FBGEMM (quantized 8-bit server operators)')
|
||||
variant('kineto', default=True, description='Use Kineto profiling library')
|
||||
variant('magma', default=not is_darwin, description='Use MAGMA')
|
||||
variant('metal', default=is_darwin, description='Use Metal for Caffe2 iOS build')
|
||||
variant('nccl', default=not is_darwin, description='Use NCCL')
|
||||
variant('nnpack', default=True, description='Use NNPACK')
|
||||
variant('numa', default=not is_darwin, description='Use NUMA')
|
||||
variant('numpy', default=True, description='Use NumPy')
|
||||
variant('openmp', default=True, description='Use OpenMP for parallel code')
|
||||
variant('qnnpack', default=True, description='Use QNNPACK (quantized 8-bit operators)')
|
||||
variant('valgrind', default=not is_darwin, description='Use Valgrind')
|
||||
variant('xnnpack', default=True, description='Use XNNPACK')
|
||||
variant('mkldnn', default=True, description='Use MKLDNN')
|
||||
variant('distributed', default=not is_darwin, description='Use distributed')
|
||||
variant('mpi', default=not is_darwin, description='Use MPI for Caffe2')
|
||||
variant('gloo', default=not is_darwin, description='Use Gloo')
|
||||
variant('tensorpipe', default=not is_darwin, description='Use TensorPipe')
|
||||
variant('onnx_ml', default=True, description='Enable traditional ONNX ML API')
|
||||
variant('breakpad', default=True, description='Enable breakpad crash dump library')
|
||||
variant("caffe2", default=True, description="Build Caffe2")
|
||||
variant("test", default=False, description="Build C++ test binaries")
|
||||
variant("cuda", default=not is_darwin, description="Use CUDA")
|
||||
variant("rocm", default=False, description="Use ROCm")
|
||||
variant("cudnn", default=not is_darwin, description="Use cuDNN")
|
||||
variant("fbgemm", default=True, description="Use FBGEMM (quantized 8-bit server operators)")
|
||||
variant("kineto", default=True, description="Use Kineto profiling library")
|
||||
variant("magma", default=not is_darwin, description="Use MAGMA")
|
||||
variant("metal", default=is_darwin, description="Use Metal for Caffe2 iOS build")
|
||||
variant("nccl", default=not is_darwin, description="Use NCCL")
|
||||
variant("nnpack", default=True, description="Use NNPACK")
|
||||
variant("numa", default=not is_darwin, description="Use NUMA")
|
||||
variant("numpy", default=True, description="Use NumPy")
|
||||
variant("openmp", default=True, description="Use OpenMP for parallel code")
|
||||
variant("qnnpack", default=True, description="Use QNNPACK (quantized 8-bit operators)")
|
||||
variant("valgrind", default=not is_darwin, description="Use Valgrind")
|
||||
variant("xnnpack", default=True, description="Use XNNPACK")
|
||||
variant("mkldnn", default=True, description="Use MKLDNN")
|
||||
variant("distributed", default=not is_darwin, description="Use distributed")
|
||||
variant("mpi", default=not is_darwin, description="Use MPI for Caffe2")
|
||||
variant("gloo", default=not is_darwin, description="Use Gloo")
|
||||
variant("tensorpipe", default=not is_darwin, description="Use TensorPipe")
|
||||
variant("onnx_ml", default=True, description="Enable traditional ONNX ML API")
|
||||
variant("breakpad", default=True, description="Enable breakpad crash dump library")
|
||||
|
||||
conflicts('+cuda', when='+rocm')
|
||||
conflicts('+cudnn', when='~cuda')
|
||||
conflicts('+magma', when='~cuda')
|
||||
conflicts('+nccl', when='~cuda~rocm')
|
||||
conflicts('+nccl', when='platform=darwin')
|
||||
conflicts('+numa', when='platform=darwin', msg='Only available on Linux')
|
||||
conflicts('+valgrind', when='platform=darwin', msg='Only available on Linux')
|
||||
conflicts('+mpi', when='~distributed')
|
||||
conflicts('+gloo', when='~distributed')
|
||||
conflicts('+tensorpipe', when='~distributed')
|
||||
conflicts('+kineto', when='@:1.7')
|
||||
conflicts('+valgrind', when='@:1.7')
|
||||
conflicts('~caffe2', when='@0.4.0:1.6') # no way to disable caffe2?
|
||||
conflicts('+caffe2', when='@:0.3.1') # caffe2 did not yet exist?
|
||||
conflicts('+tensorpipe', when='@:1.5')
|
||||
conflicts('+xnnpack', when='@:1.4')
|
||||
conflicts('~onnx_ml', when='@:1.4') # no way to disable ONNX?
|
||||
conflicts('+rocm', when='@:0.4')
|
||||
conflicts('+cudnn', when='@:0.4')
|
||||
conflicts('+fbgemm', when='@:0.4,1.4.0')
|
||||
conflicts('+qnnpack', when='@:0.4')
|
||||
conflicts('+mkldnn', when='@:0.4')
|
||||
conflicts('+breakpad', when='@:1.9') # Option appeared in 1.10.0
|
||||
conflicts('+breakpad', when='target=ppc64:', msg='Unsupported')
|
||||
conflicts('+breakpad', when='target=ppc64le:', msg='Unsupported')
|
||||
conflicts("+cuda", when="+rocm")
|
||||
conflicts("+cudnn", when="~cuda")
|
||||
conflicts("+magma", when="~cuda")
|
||||
conflicts("+nccl", when="~cuda~rocm")
|
||||
conflicts("+nccl", when="platform=darwin")
|
||||
conflicts("+numa", when="platform=darwin", msg="Only available on Linux")
|
||||
conflicts("+valgrind", when="platform=darwin", msg="Only available on Linux")
|
||||
conflicts("+mpi", when="~distributed")
|
||||
conflicts("+gloo", when="~distributed")
|
||||
conflicts("+tensorpipe", when="~distributed")
|
||||
conflicts("+kineto", when="@:1.7")
|
||||
conflicts("+valgrind", when="@:1.7")
|
||||
conflicts("~caffe2", when="@0.4.0:1.6") # no way to disable caffe2?
|
||||
conflicts("+caffe2", when="@:0.3.1") # caffe2 did not yet exist?
|
||||
conflicts("+tensorpipe", when="@:1.5")
|
||||
conflicts("+xnnpack", when="@:1.4")
|
||||
conflicts("~onnx_ml", when="@:1.4") # no way to disable ONNX?
|
||||
conflicts("+rocm", when="@:0.4")
|
||||
conflicts("+cudnn", when="@:0.4")
|
||||
conflicts("+fbgemm", when="@:0.4,1.4.0")
|
||||
conflicts("+qnnpack", when="@:0.4")
|
||||
conflicts("+mkldnn", when="@:0.4")
|
||||
conflicts("+breakpad", when="@:1.9") # Option appeared in 1.10.0
|
||||
conflicts("+breakpad", when="target=ppc64:", msg="Unsupported")
|
||||
conflicts("+breakpad", when="target=ppc64le:", msg="Unsupported")
|
||||
|
||||
conflicts('cuda_arch=none', when='+cuda',
|
||||
msg='Must specify CUDA compute capabilities of your GPU, see '
|
||||
'https://developer.nvidia.com/cuda-gpus')
|
||||
conflicts(
|
||||
"cuda_arch=none",
|
||||
when="+cuda",
|
||||
msg="Must specify CUDA compute capabilities of your GPU, see "
|
||||
"https://developer.nvidia.com/cuda-gpus",
|
||||
)
|
||||
|
||||
# Required dependencies
|
||||
depends_on('cmake@3.5:', type='build')
|
||||
depends_on("cmake@3.5:", type="build")
|
||||
# Use Ninja generator to speed up build times, automatically used if found
|
||||
depends_on('ninja@1.5:', when='@1.1.0:', type='build')
|
||||
depends_on("ninja@1.5:", when="@1.1.0:", type="build")
|
||||
# See python_min_version in setup.py
|
||||
depends_on('python@3.6.2:', when='@1.7.1:', type=('build', 'link', 'run'))
|
||||
depends_on('python@3.6.1:', when='@1.6.0:1.7.0', type=('build', 'link', 'run'))
|
||||
depends_on('python@3.5:', when='@1.5.0:1.5', type=('build', 'link', 'run'))
|
||||
depends_on('python@2.7:2.8,3.5:', when='@1.4.0:1.4', type=('build', 'link', 'run'))
|
||||
depends_on('python@2.7:2.8,3.5:3.7', when='@:1.3', type=('build', 'link', 'run'))
|
||||
depends_on('py-setuptools', type=('build', 'run'))
|
||||
depends_on('py-future', when='@1.5:', type=('build', 'run'))
|
||||
depends_on('py-future', when='@1.1: ^python@:2', type=('build', 'run'))
|
||||
depends_on('py-pyyaml', type=('build', 'run'))
|
||||
depends_on('py-typing', when='@0.4: ^python@:3.4', type=('build', 'run'))
|
||||
depends_on('py-typing-extensions', when='@1.7:', type=('build', 'run'))
|
||||
depends_on('py-pybind11@2.6.2', when='@1.8.0:', type=('build', 'link', 'run'))
|
||||
depends_on('py-pybind11@2.3.0', when='@1.1.0:1.7', type=('build', 'link', 'run'))
|
||||
depends_on('py-pybind11@2.2.4', when='@1.0.0:1.0', type=('build', 'link', 'run'))
|
||||
depends_on('py-pybind11@2.2.2', when='@0.4.0:0.4', type=('build', 'link', 'run'))
|
||||
depends_on('py-dataclasses', when='@1.7: ^python@3.6.0:3.6', type=('build', 'run'))
|
||||
depends_on('py-tqdm', type='run')
|
||||
depends_on('py-protobuf', when='@0.4:', type=('build', 'run'))
|
||||
depends_on('protobuf', when='@0.4:')
|
||||
depends_on('blas')
|
||||
depends_on('lapack')
|
||||
depends_on('eigen', when='@0.4:')
|
||||
depends_on("python@3.6.2:", when="@1.7.1:", type=("build", "link", "run"))
|
||||
depends_on("python@3.6.1:", when="@1.6.0:1.7.0", type=("build", "link", "run"))
|
||||
depends_on("python@3.5:", when="@1.5.0:1.5", type=("build", "link", "run"))
|
||||
depends_on("python@2.7:2.8,3.5:", when="@1.4.0:1.4", type=("build", "link", "run"))
|
||||
depends_on("python@2.7:2.8,3.5:3.7", when="@:1.3", type=("build", "link", "run"))
|
||||
depends_on("py-setuptools", type=("build", "run"))
|
||||
depends_on("py-future", when="@1.5:", type=("build", "run"))
|
||||
depends_on("py-future", when="@1.1: ^python@:2", type=("build", "run"))
|
||||
depends_on("py-pyyaml", type=("build", "run"))
|
||||
depends_on("py-typing", when="@0.4: ^python@:3.4", type=("build", "run"))
|
||||
depends_on("py-typing-extensions", when="@1.7:", type=("build", "run"))
|
||||
depends_on("py-pybind11@2.6.2", when="@1.8.0:", type=("build", "link", "run"))
|
||||
depends_on("py-pybind11@2.3.0", when="@1.1.0:1.7", type=("build", "link", "run"))
|
||||
depends_on("py-pybind11@2.2.4", when="@1.0.0:1.0", type=("build", "link", "run"))
|
||||
depends_on("py-pybind11@2.2.2", when="@0.4.0:0.4", type=("build", "link", "run"))
|
||||
depends_on("py-dataclasses", when="@1.7: ^python@3.6.0:3.6", type=("build", "run"))
|
||||
depends_on("py-tqdm", type="run")
|
||||
depends_on("py-protobuf", when="@0.4:", type=("build", "run"))
|
||||
depends_on("protobuf", when="@0.4:")
|
||||
depends_on("blas")
|
||||
depends_on("lapack")
|
||||
depends_on("eigen", when="@0.4:")
|
||||
# https://github.com/pytorch/pytorch/issues/60329
|
||||
# depends_on('cpuinfo@2020-12-17', when='@1.8.0:')
|
||||
# depends_on('cpuinfo@2020-06-11', when='@1.6.0:1.7')
|
||||
@@ -152,30 +165,30 @@ class PyTorch(PythonPackage, CudaPackage):
|
||||
# depends_on('sleef@3.4.0_2019-07-30', when='@1.6.0:1.7')
|
||||
# https://github.com/Maratyszcza/FP16/issues/18
|
||||
# depends_on('fp16@2020-05-14', when='@1.6.0:')
|
||||
depends_on('pthreadpool@2021-04-13', when='@1.9.0:')
|
||||
depends_on('pthreadpool@2020-10-05', when='@1.8.0:1.8')
|
||||
depends_on('pthreadpool@2020-06-15', when='@1.6.0:1.7')
|
||||
depends_on('psimd@2020-05-17', when='@1.6.0:')
|
||||
depends_on('fxdiv@2020-04-17', when='@1.6.0:')
|
||||
depends_on('benchmark', when='@1.6:+test')
|
||||
depends_on("pthreadpool@2021-04-13", when="@1.9.0:")
|
||||
depends_on("pthreadpool@2020-10-05", when="@1.8.0:1.8")
|
||||
depends_on("pthreadpool@2020-06-15", when="@1.6.0:1.7")
|
||||
depends_on("psimd@2020-05-17", when="@1.6.0:")
|
||||
depends_on("fxdiv@2020-04-17", when="@1.6.0:")
|
||||
depends_on("benchmark", when="@1.6:+test")
|
||||
|
||||
# Optional dependencies
|
||||
depends_on('cuda@7.5:', when='+cuda', type=('build', 'link', 'run'))
|
||||
depends_on('cuda@9:', when='@1.1:+cuda', type=('build', 'link', 'run'))
|
||||
depends_on('cuda@9.2:', when='@1.6:+cuda', type=('build', 'link', 'run'))
|
||||
depends_on('cudnn@6.0:7', when='@:1.0+cudnn')
|
||||
depends_on('cudnn@7.0:7', when='@1.1.0:1.5+cudnn')
|
||||
depends_on('cudnn@7.0:', when='@1.6.0:+cudnn')
|
||||
depends_on('magma', when='+magma')
|
||||
depends_on('nccl', when='+nccl')
|
||||
depends_on('numactl', when='+numa')
|
||||
depends_on('py-numpy', when='+numpy', type=('build', 'run'))
|
||||
depends_on('llvm-openmp', when='%apple-clang +openmp')
|
||||
depends_on('valgrind', when='+valgrind')
|
||||
depends_on("cuda@7.5:", when="+cuda", type=("build", "link", "run"))
|
||||
depends_on("cuda@9:", when="@1.1:+cuda", type=("build", "link", "run"))
|
||||
depends_on("cuda@9.2:", when="@1.6:+cuda", type=("build", "link", "run"))
|
||||
depends_on("cudnn@6.0:7", when="@:1.0+cudnn")
|
||||
depends_on("cudnn@7.0:7", when="@1.1.0:1.5+cudnn")
|
||||
depends_on("cudnn@7.0:", when="@1.6.0:+cudnn")
|
||||
depends_on("magma", when="+magma")
|
||||
depends_on("nccl", when="+nccl")
|
||||
depends_on("numactl", when="+numa")
|
||||
depends_on("py-numpy", when="+numpy", type=("build", "run"))
|
||||
depends_on("llvm-openmp", when="%apple-clang +openmp")
|
||||
depends_on("valgrind", when="+valgrind")
|
||||
# https://github.com/pytorch/pytorch/issues/60332
|
||||
# depends_on('xnnpack@2021-02-22', when='@1.8.0:+xnnpack')
|
||||
# depends_on('xnnpack@2020-03-23', when='@1.6.0:1.7+xnnpack')
|
||||
depends_on('mpi', when='+mpi')
|
||||
depends_on("mpi", when="+mpi")
|
||||
# https://github.com/pytorch/pytorch/issues/60270
|
||||
# depends_on('gloo@2021-05-04', when='@1.9.0:+gloo')
|
||||
# depends_on('gloo@2020-09-18', when='@1.7.0:1.8+gloo')
|
||||
@@ -183,31 +196,35 @@ class PyTorch(PythonPackage, CudaPackage):
|
||||
# https://github.com/pytorch/pytorch/issues/60331
|
||||
# depends_on('onnx@1.8.0_2020-11-03', when='@1.8.0:+onnx_ml')
|
||||
# depends_on('onnx@1.7.0_2020-05-31', when='@1.6.0:1.7+onnx_ml')
|
||||
depends_on('mkl', when='+mkldnn')
|
||||
depends_on("mkl", when="+mkldnn")
|
||||
|
||||
# Test dependencies
|
||||
depends_on('py-hypothesis', type='test')
|
||||
depends_on('py-six', type='test')
|
||||
depends_on('py-psutil', type='test')
|
||||
depends_on("py-hypothesis", type="test")
|
||||
depends_on("py-six", type="test")
|
||||
depends_on("py-psutil", type="test")
|
||||
|
||||
# Fix BLAS being overridden by MKL
|
||||
# https://github.com/pytorch/pytorch/issues/60328
|
||||
patch('https://patch-diff.githubusercontent.com/raw/pytorch/pytorch/pull/59220.patch',
|
||||
sha256='e37afffe45cf7594c22050109942370e49983ad772d12ebccf508377dc9dcfc9',
|
||||
when='@1.2.0:')
|
||||
patch(
|
||||
"https://patch-diff.githubusercontent.com/raw/pytorch/pytorch/pull/59220.patch",
|
||||
sha256="e37afffe45cf7594c22050109942370e49983ad772d12ebccf508377dc9dcfc9",
|
||||
when="@1.2.0:",
|
||||
)
|
||||
|
||||
# Fixes build on older systems with glibc <2.12
|
||||
patch('https://patch-diff.githubusercontent.com/raw/pytorch/pytorch/pull/55063.patch',
|
||||
sha256='e17eaa42f5d7c18bf0d7c37d7b0910127a01ad53fdce3e226a92893356a70395',
|
||||
when='@1.1.0:1.8.1')
|
||||
patch(
|
||||
"https://patch-diff.githubusercontent.com/raw/pytorch/pytorch/pull/55063.patch",
|
||||
sha256="e17eaa42f5d7c18bf0d7c37d7b0910127a01ad53fdce3e226a92893356a70395",
|
||||
when="@1.1.0:1.8.1",
|
||||
)
|
||||
|
||||
# Fixes CMake configuration error when XNNPACK is disabled
|
||||
# https://github.com/pytorch/pytorch/pull/35607
|
||||
# https://github.com/pytorch/pytorch/pull/37865
|
||||
patch('xnnpack.patch', when='@1.5.0:1.5')
|
||||
patch("xnnpack.patch", when="@1.5.0:1.5")
|
||||
|
||||
# Fixes build error when ROCm is enabled for pytorch-1.5 release
|
||||
patch('rocm.patch', when='@1.5.0:1.5+rocm')
|
||||
patch("rocm.patch", when="@1.5.0:1.5+rocm")
|
||||
|
||||
# Fixes fatal error: sleef.h: No such file or directory
|
||||
# https://github.com/pytorch/pytorch/pull/35359
|
||||
@@ -216,47 +233,56 @@ class PyTorch(PythonPackage, CudaPackage):
|
||||
|
||||
# Fixes compilation with Clang 9.0.0 and Apple Clang 11.0.3
|
||||
# https://github.com/pytorch/pytorch/pull/37086
|
||||
patch('https://github.com/pytorch/pytorch/commit/e921cd222a8fbeabf5a3e74e83e0d8dfb01aa8b5.patch',
|
||||
sha256='17561b16cd2db22f10c0fe1fdcb428aecb0ac3964ba022a41343a6bb8cba7049',
|
||||
when='@1.1:1.5')
|
||||
patch(
|
||||
"https://github.com/pytorch/pytorch/commit/e921cd222a8fbeabf5a3e74e83e0d8dfb01aa8b5.patch",
|
||||
sha256="17561b16cd2db22f10c0fe1fdcb428aecb0ac3964ba022a41343a6bb8cba7049",
|
||||
when="@1.1:1.5",
|
||||
)
|
||||
|
||||
# Removes duplicate definition of getCusparseErrorString
|
||||
# https://github.com/pytorch/pytorch/issues/32083
|
||||
patch('cusparseGetErrorString.patch', when='@0.4.1:1.0^cuda@10.1.243:')
|
||||
patch("cusparseGetErrorString.patch", when="@0.4.1:1.0^cuda@10.1.243:")
|
||||
|
||||
# Fixes 'FindOpenMP.cmake'
|
||||
# to detect openmp settings used by Fujitsu compiler.
|
||||
patch('detect_omp_of_fujitsu_compiler.patch', when='%fj')
|
||||
patch("detect_omp_of_fujitsu_compiler.patch", when="%fj")
|
||||
|
||||
# Fix compilation of +distributed~tensorpipe
|
||||
# https://github.com/pytorch/pytorch/issues/68002
|
||||
patch('https://github.com/pytorch/pytorch/commit/c075f0f633fa0136e68f0a455b5b74d7b500865c.patch',
|
||||
sha256='e69e41b5c171bfb00d1b5d4ee55dd5e4c8975483230274af4ab461acd37e40b8', when='@1.10.0+distributed~tensorpipe')
|
||||
patch(
|
||||
"https://github.com/pytorch/pytorch/commit/c075f0f633fa0136e68f0a455b5b74d7b500865c.patch",
|
||||
sha256="e69e41b5c171bfb00d1b5d4ee55dd5e4c8975483230274af4ab461acd37e40b8",
|
||||
when="@1.10.0+distributed~tensorpipe",
|
||||
)
|
||||
|
||||
# Both build and install run cmake/make/make install
|
||||
# Only run once to speed up build times
|
||||
phases = ['install']
|
||||
phases = ["install"]
|
||||
|
||||
@property
|
||||
def libs(self):
|
||||
root = join_path(self.prefix, self.spec['python'].package.site_packages_dir,
|
||||
'torch', 'lib')
|
||||
return find_libraries('libtorch', root)
|
||||
root = join_path(
|
||||
self.prefix, self.spec["python"].package.site_packages_dir, "torch", "lib"
|
||||
)
|
||||
return find_libraries("libtorch", root)
|
||||
|
||||
@property
|
||||
def headers(self):
|
||||
root = join_path(self.prefix, self.spec['python'].package.site_packages_dir,
|
||||
'torch', 'include')
|
||||
root = join_path(
|
||||
self.prefix, self.spec["python"].package.site_packages_dir, "torch", "include"
|
||||
)
|
||||
headers = find_all_headers(root)
|
||||
headers.directories = [root]
|
||||
return headers
|
||||
|
||||
@when('@1.5.0:')
|
||||
@when("@1.5.0:")
|
||||
def patch(self):
|
||||
# https://github.com/pytorch/pytorch/issues/52208
|
||||
filter_file('torch_global_deps PROPERTIES LINKER_LANGUAGE C',
|
||||
'torch_global_deps PROPERTIES LINKER_LANGUAGE CXX',
|
||||
'caffe2/CMakeLists.txt')
|
||||
filter_file(
|
||||
"torch_global_deps PROPERTIES LINKER_LANGUAGE C",
|
||||
"torch_global_deps PROPERTIES LINKER_LANGUAGE CXX",
|
||||
"caffe2/CMakeLists.txt",
|
||||
)
|
||||
|
||||
def setup_build_environment(self, env):
|
||||
"""Set environment variables used to control the build.
|
||||
@@ -269,7 +295,8 @@ class PyTorch(PythonPackage, CudaPackage):
|
||||
most flags defined in ``CMakeLists.txt`` can be specified as
|
||||
environment variables.
|
||||
"""
|
||||
def enable_or_disable(variant, keyword='USE', var=None, newer=False):
|
||||
|
||||
def enable_or_disable(variant, keyword="USE", var=None, newer=False):
|
||||
"""Set environment variable to enable or disable support for a
|
||||
particular variant.
|
||||
|
||||
@@ -284,137 +311,135 @@ class PyTorch(PythonPackage, CudaPackage):
|
||||
|
||||
# Version 1.1.0 switched from NO_* to USE_* or BUILD_*
|
||||
# But some newer variants have always used USE_* or BUILD_*
|
||||
if self.spec.satisfies('@1.1:') or newer:
|
||||
if '+' + variant in self.spec:
|
||||
env.set(keyword + '_' + var, 'ON')
|
||||
if self.spec.satisfies("@1.1:") or newer:
|
||||
if "+" + variant in self.spec:
|
||||
env.set(keyword + "_" + var, "ON")
|
||||
else:
|
||||
env.set(keyword + '_' + var, 'OFF')
|
||||
env.set(keyword + "_" + var, "OFF")
|
||||
else:
|
||||
if '+' + variant in self.spec:
|
||||
env.unset('NO_' + var)
|
||||
if "+" + variant in self.spec:
|
||||
env.unset("NO_" + var)
|
||||
else:
|
||||
env.set('NO_' + var, 'ON')
|
||||
env.set("NO_" + var, "ON")
|
||||
|
||||
# Build in parallel to speed up build times
|
||||
env.set('MAX_JOBS', make_jobs)
|
||||
env.set("MAX_JOBS", make_jobs)
|
||||
|
||||
# Spack logs have trouble handling colored output
|
||||
env.set('COLORIZE_OUTPUT', 'OFF')
|
||||
env.set("COLORIZE_OUTPUT", "OFF")
|
||||
|
||||
if self.spec.satisfies('@0.4:'):
|
||||
enable_or_disable('test', keyword='BUILD')
|
||||
if self.spec.satisfies("@0.4:"):
|
||||
enable_or_disable("test", keyword="BUILD")
|
||||
|
||||
if self.spec.satisfies('@1.7:'):
|
||||
enable_or_disable('caffe2', keyword='BUILD')
|
||||
if self.spec.satisfies("@1.7:"):
|
||||
enable_or_disable("caffe2", keyword="BUILD")
|
||||
|
||||
enable_or_disable('cuda')
|
||||
if '+cuda' in self.spec:
|
||||
enable_or_disable("cuda")
|
||||
if "+cuda" in self.spec:
|
||||
# cmake/public/cuda.cmake
|
||||
# cmake/Modules_CUDA_fix/upstream/FindCUDA.cmake
|
||||
env.unset('CUDA_ROOT')
|
||||
torch_cuda_arch = ';'.join('{0:.1f}'.format(float(i) / 10.0) for i
|
||||
in
|
||||
self.spec.variants['cuda_arch'].value)
|
||||
env.set('TORCH_CUDA_ARCH_LIST', torch_cuda_arch)
|
||||
env.unset("CUDA_ROOT")
|
||||
torch_cuda_arch = ";".join(
|
||||
"{0:.1f}".format(float(i) / 10.0) for i in self.spec.variants["cuda_arch"].value
|
||||
)
|
||||
env.set("TORCH_CUDA_ARCH_LIST", torch_cuda_arch)
|
||||
|
||||
enable_or_disable('rocm')
|
||||
enable_or_disable("rocm")
|
||||
|
||||
enable_or_disable('cudnn')
|
||||
if '+cudnn' in self.spec:
|
||||
enable_or_disable("cudnn")
|
||||
if "+cudnn" in self.spec:
|
||||
# cmake/Modules_CUDA_fix/FindCUDNN.cmake
|
||||
env.set('CUDNN_INCLUDE_DIR', self.spec['cudnn'].prefix.include)
|
||||
env.set('CUDNN_LIBRARY', self.spec['cudnn'].libs[0])
|
||||
env.set("CUDNN_INCLUDE_DIR", self.spec["cudnn"].prefix.include)
|
||||
env.set("CUDNN_LIBRARY", self.spec["cudnn"].libs[0])
|
||||
|
||||
enable_or_disable('fbgemm')
|
||||
if self.spec.satisfies('@1.8:'):
|
||||
enable_or_disable('kineto')
|
||||
enable_or_disable('magma')
|
||||
enable_or_disable('metal')
|
||||
if self.spec.satisfies('@1.10:'):
|
||||
enable_or_disable('breakpad')
|
||||
enable_or_disable("fbgemm")
|
||||
if self.spec.satisfies("@1.8:"):
|
||||
enable_or_disable("kineto")
|
||||
enable_or_disable("magma")
|
||||
enable_or_disable("metal")
|
||||
if self.spec.satisfies("@1.10:"):
|
||||
enable_or_disable("breakpad")
|
||||
|
||||
enable_or_disable('nccl')
|
||||
if '+nccl' in self.spec:
|
||||
env.set('NCCL_LIB_DIR', self.spec['nccl'].libs.directories[0])
|
||||
env.set('NCCL_INCLUDE_DIR', self.spec['nccl'].prefix.include)
|
||||
enable_or_disable("nccl")
|
||||
if "+nccl" in self.spec:
|
||||
env.set("NCCL_LIB_DIR", self.spec["nccl"].libs.directories[0])
|
||||
env.set("NCCL_INCLUDE_DIR", self.spec["nccl"].prefix.include)
|
||||
|
||||
# cmake/External/nnpack.cmake
|
||||
enable_or_disable('nnpack')
|
||||
enable_or_disable("nnpack")
|
||||
|
||||
enable_or_disable('numa')
|
||||
if '+numa' in self.spec:
|
||||
enable_or_disable("numa")
|
||||
if "+numa" in self.spec:
|
||||
# cmake/Modules/FindNuma.cmake
|
||||
env.set('NUMA_ROOT_DIR', self.spec['numactl'].prefix)
|
||||
env.set("NUMA_ROOT_DIR", self.spec["numactl"].prefix)
|
||||
|
||||
# cmake/Modules/FindNumPy.cmake
|
||||
enable_or_disable('numpy')
|
||||
enable_or_disable("numpy")
|
||||
# cmake/Modules/FindOpenMP.cmake
|
||||
enable_or_disable('openmp', newer=True)
|
||||
enable_or_disable('qnnpack')
|
||||
if self.spec.satisfies('@1.3:'):
|
||||
enable_or_disable('qnnpack', var='PYTORCH_QNNPACK')
|
||||
if self.spec.satisfies('@1.8:'):
|
||||
enable_or_disable('valgrind')
|
||||
if self.spec.satisfies('@1.5:'):
|
||||
enable_or_disable('xnnpack')
|
||||
enable_or_disable('mkldnn')
|
||||
enable_or_disable('distributed')
|
||||
enable_or_disable('mpi')
|
||||
enable_or_disable("openmp", newer=True)
|
||||
enable_or_disable("qnnpack")
|
||||
if self.spec.satisfies("@1.3:"):
|
||||
enable_or_disable("qnnpack", var="PYTORCH_QNNPACK")
|
||||
if self.spec.satisfies("@1.8:"):
|
||||
enable_or_disable("valgrind")
|
||||
if self.spec.satisfies("@1.5:"):
|
||||
enable_or_disable("xnnpack")
|
||||
enable_or_disable("mkldnn")
|
||||
enable_or_disable("distributed")
|
||||
enable_or_disable("mpi")
|
||||
# cmake/Modules/FindGloo.cmake
|
||||
enable_or_disable('gloo', newer=True)
|
||||
if self.spec.satisfies('@1.6:'):
|
||||
enable_or_disable('tensorpipe')
|
||||
enable_or_disable("gloo", newer=True)
|
||||
if self.spec.satisfies("@1.6:"):
|
||||
enable_or_disable("tensorpipe")
|
||||
|
||||
if '+onnx_ml' in self.spec:
|
||||
env.set('ONNX_ML', 'ON')
|
||||
if "+onnx_ml" in self.spec:
|
||||
env.set("ONNX_ML", "ON")
|
||||
else:
|
||||
env.set('ONNX_ML', 'OFF')
|
||||
env.set("ONNX_ML", "OFF")
|
||||
|
||||
if not self.spec.satisfies('@master'):
|
||||
env.set('PYTORCH_BUILD_VERSION', self.version)
|
||||
env.set('PYTORCH_BUILD_NUMBER', 0)
|
||||
if not self.spec.satisfies("@master"):
|
||||
env.set("PYTORCH_BUILD_VERSION", self.version)
|
||||
env.set("PYTORCH_BUILD_NUMBER", 0)
|
||||
|
||||
# BLAS to be used by Caffe2
|
||||
# Options defined in cmake/Dependencies.cmake and cmake/Modules/FindBLAS.cmake
|
||||
if self.spec['blas'].name == 'atlas':
|
||||
env.set('BLAS', 'ATLAS')
|
||||
env.set('WITH_BLAS', 'atlas')
|
||||
elif self.spec['blas'].name in ['blis', 'amdblis']:
|
||||
env.set('BLAS', 'BLIS')
|
||||
env.set('WITH_BLAS', 'blis')
|
||||
elif self.spec['blas'].name == 'eigen':
|
||||
env.set('BLAS', 'Eigen')
|
||||
elif self.spec['lapack'].name in ['libflame', 'amdlibflame']:
|
||||
env.set('BLAS', 'FLAME')
|
||||
env.set('WITH_BLAS', 'FLAME')
|
||||
elif self.spec['blas'].name in [
|
||||
'intel-mkl', 'intel-parallel-studio', 'intel-oneapi-mkl']:
|
||||
env.set('BLAS', 'MKL')
|
||||
env.set('WITH_BLAS', 'mkl')
|
||||
elif self.spec['blas'].name == 'openblas':
|
||||
env.set('BLAS', 'OpenBLAS')
|
||||
env.set('WITH_BLAS', 'open')
|
||||
elif self.spec['blas'].name == 'veclibfort':
|
||||
env.set('BLAS', 'vecLib')
|
||||
env.set('WITH_BLAS', 'veclib')
|
||||
if self.spec["blas"].name == "atlas":
|
||||
env.set("BLAS", "ATLAS")
|
||||
env.set("WITH_BLAS", "atlas")
|
||||
elif self.spec["blas"].name in ["blis", "amdblis"]:
|
||||
env.set("BLAS", "BLIS")
|
||||
env.set("WITH_BLAS", "blis")
|
||||
elif self.spec["blas"].name == "eigen":
|
||||
env.set("BLAS", "Eigen")
|
||||
elif self.spec["lapack"].name in ["libflame", "amdlibflame"]:
|
||||
env.set("BLAS", "FLAME")
|
||||
env.set("WITH_BLAS", "FLAME")
|
||||
elif self.spec["blas"].name in ["intel-mkl", "intel-parallel-studio", "intel-oneapi-mkl"]:
|
||||
env.set("BLAS", "MKL")
|
||||
env.set("WITH_BLAS", "mkl")
|
||||
elif self.spec["blas"].name == "openblas":
|
||||
env.set("BLAS", "OpenBLAS")
|
||||
env.set("WITH_BLAS", "open")
|
||||
elif self.spec["blas"].name == "veclibfort":
|
||||
env.set("BLAS", "vecLib")
|
||||
env.set("WITH_BLAS", "veclib")
|
||||
else:
|
||||
env.set('BLAS', 'Generic')
|
||||
env.set('WITH_BLAS', 'generic')
|
||||
env.set("BLAS", "Generic")
|
||||
env.set("WITH_BLAS", "generic")
|
||||
|
||||
# Don't use vendored third-party libraries when possible
|
||||
env.set('BUILD_CUSTOM_PROTOBUF', 'OFF')
|
||||
env.set('USE_SYSTEM_NCCL', 'ON')
|
||||
env.set('USE_SYSTEM_EIGEN_INSTALL', 'ON')
|
||||
if self.spec.satisfies('@0.4:'):
|
||||
env.set('pybind11_DIR', self.spec['py-pybind11'].prefix)
|
||||
env.set('pybind11_INCLUDE_DIR',
|
||||
self.spec['py-pybind11'].prefix.include)
|
||||
if self.spec.satisfies('@1.10:'):
|
||||
env.set('USE_SYSTEM_PYBIND11', 'ON')
|
||||
env.set("BUILD_CUSTOM_PROTOBUF", "OFF")
|
||||
env.set("USE_SYSTEM_NCCL", "ON")
|
||||
env.set("USE_SYSTEM_EIGEN_INSTALL", "ON")
|
||||
if self.spec.satisfies("@0.4:"):
|
||||
env.set("pybind11_DIR", self.spec["py-pybind11"].prefix)
|
||||
env.set("pybind11_INCLUDE_DIR", self.spec["py-pybind11"].prefix.include)
|
||||
if self.spec.satisfies("@1.10:"):
|
||||
env.set("USE_SYSTEM_PYBIND11", "ON")
|
||||
# https://github.com/pytorch/pytorch/issues/60334
|
||||
# if self.spec.satisfies('@1.8:'):
|
||||
# env.set('USE_SYSTEM_SLEEF', 'ON')
|
||||
if self.spec.satisfies('@1.6:'):
|
||||
if self.spec.satisfies("@1.6:"):
|
||||
# env.set('USE_SYSTEM_LIBS', 'ON')
|
||||
# https://github.com/pytorch/pytorch/issues/60329
|
||||
# env.set('USE_SYSTEM_CPUINFO', 'ON')
|
||||
@@ -422,27 +447,26 @@ class PyTorch(PythonPackage, CudaPackage):
|
||||
# env.set('USE_SYSTEM_GLOO', 'ON')
|
||||
# https://github.com/Maratyszcza/FP16/issues/18
|
||||
# env.set('USE_SYSTEM_FP16', 'ON')
|
||||
env.set('USE_SYSTEM_PTHREADPOOL', 'ON')
|
||||
env.set('USE_SYSTEM_PSIMD', 'ON')
|
||||
env.set('USE_SYSTEM_FXDIV', 'ON')
|
||||
env.set('USE_SYSTEM_BENCHMARK', 'ON')
|
||||
env.set("USE_SYSTEM_PTHREADPOOL", "ON")
|
||||
env.set("USE_SYSTEM_PSIMD", "ON")
|
||||
env.set("USE_SYSTEM_FXDIV", "ON")
|
||||
env.set("USE_SYSTEM_BENCHMARK", "ON")
|
||||
# https://github.com/pytorch/pytorch/issues/60331
|
||||
# env.set('USE_SYSTEM_ONNX', 'ON')
|
||||
# https://github.com/pytorch/pytorch/issues/60332
|
||||
# env.set('USE_SYSTEM_XNNPACK', 'ON')
|
||||
|
||||
@run_before('install')
|
||||
@run_before("install")
|
||||
def build_amd(self):
|
||||
if '+rocm' in self.spec:
|
||||
python(os.path.join('tools', 'amd_build', 'build_amd.py'))
|
||||
if "+rocm" in self.spec:
|
||||
python(os.path.join("tools", "amd_build", "build_amd.py"))
|
||||
|
||||
@run_after('install')
|
||||
@run_after("install")
|
||||
@on_package_attributes(run_tests=True)
|
||||
def install_test(self):
|
||||
with working_dir('test'):
|
||||
python('run_test.py')
|
||||
with working_dir("test"):
|
||||
python("run_test.py")
|
||||
|
||||
# Tests need to be re-added since `phases` was overridden
|
||||
run_after('install')(
|
||||
PythonPackage._run_default_install_time_test_callbacks)
|
||||
run_after('install')(PythonPackage.sanity_check_prefix)
|
||||
run_after("install")(PythonPackage._run_default_install_time_test_callbacks)
|
||||
run_after("install")(PythonPackage.sanity_check_prefix)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -400,7 +400,7 @@ def test_sanitize_literals(env, exclude, include):
|
||||
({"SHLVL": "1"}, ["SH.*"], [], [], ["SHLVL"]),
|
||||
# Check we can include using a regex
|
||||
({"SHLVL": "1"}, ["SH.*"], ["SH.*"], ["SHLVL"], []),
|
||||
# Check regex to exclude Environment Modules related vars
|
||||
# Check regex to exclude Modules v4 related vars
|
||||
(
|
||||
{"MODULES_LMALTNAME": "1", "MODULES_LMCONFLICT": "2"},
|
||||
["MODULES_(.*)"],
|
||||
@@ -415,13 +415,6 @@ def test_sanitize_literals(env, exclude, include):
|
||||
[],
|
||||
["A_modquar", "b_modquar", "C_modshare"],
|
||||
),
|
||||
(
|
||||
{"__MODULES_LMTAG": "1", "__MODULES_LMPREREQ": "2"},
|
||||
["__MODULES_(.*)"],
|
||||
[],
|
||||
[],
|
||||
["__MODULES_LMTAG", "__MODULES_LMPREREQ"],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_sanitize_regex(env, exclude, include, expected, deleted):
|
||||
@@ -496,19 +489,3 @@ def test_exclude_lmod_variables():
|
||||
# Check that variables related to lmod are not in there
|
||||
modifications = env.group_by_name()
|
||||
assert not any(x.startswith("LMOD_") for x in modifications)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
@pytest.mark.regression("13504")
|
||||
def test_exclude_modules_variables():
|
||||
# Construct the list of environment modifications
|
||||
file = os.path.join(datadir, "sourceme_modules.sh")
|
||||
env = EnvironmentModifications.from_sourcing_file(file)
|
||||
|
||||
# Check that variables related to modules are not in there
|
||||
modifications = env.group_by_name()
|
||||
assert not any(x.startswith("MODULES_") for x in modifications)
|
||||
assert not any(x.startswith("__MODULES_") for x in modifications)
|
||||
assert not any(x.startswith("BASH_FUNC_ml") for x in modifications)
|
||||
assert not any(x.startswith("BASH_FUNC_module") for x in modifications)
|
||||
assert not any(x.startswith("BASH_FUNC__module_raw") for x in modifications)
|
||||
|
@@ -1386,30 +1386,6 @@ def test_single_external_implicit_install(install_mockery, explicit_args, is_exp
|
||||
assert spack.store.db.get_record(pkg).explicit == is_explicit
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform == "win32",
|
||||
reason="Windows breaks overwrite install due to prefix normalization inconsistencies",
|
||||
)
|
||||
def test_overwrite_install_does_install_build_deps(install_mockery, mock_fetch):
|
||||
"""When overwrite installing something from sources, build deps should be installed."""
|
||||
s = spack.spec.Spec("dtrun3").concretized()
|
||||
create_installer([(s, {})]).install()
|
||||
|
||||
# Verify there is a pure build dep
|
||||
edge = s.edges_to_dependencies(name="dtbuild3").pop()
|
||||
assert edge.deptypes == ("build",)
|
||||
build_dep = edge.spec
|
||||
|
||||
# Uninstall the build dep
|
||||
build_dep.package.do_uninstall()
|
||||
|
||||
# Overwrite install the root dtrun3
|
||||
create_installer([(s, {"overwrite": [s.dag_hash()]})]).install()
|
||||
|
||||
# Verify that the build dep was also installed.
|
||||
assert build_dep.installed
|
||||
|
||||
|
||||
@pytest.mark.parametrize("run_tests", [True, False])
|
||||
def test_print_install_test_log_skipped(install_mockery, mock_packages, capfd, run_tests):
|
||||
"""Confirm printing of install log skipped if not run/no failures."""
|
||||
|
@@ -198,15 +198,6 @@ def test_manpath_setup(self, modulefile_content, module_configuration):
|
||||
assert len([x for x in content if 'setenv("MANPATH", "/path/to/man")' in x]) == 1
|
||||
assert len([x for x in content if 'append_path("MANPATH", "", ":")' in x]) == 0
|
||||
|
||||
@pytest.mark.regression("29578")
|
||||
def test_setenv_raw_value(self, modulefile_content, module_configuration):
|
||||
"""Tests that we can set environment variable value without formatting it."""
|
||||
|
||||
module_configuration("autoload_direct")
|
||||
content = modulefile_content("module-setenv-raw")
|
||||
|
||||
assert len([x for x in content if 'setenv("FOO", "{{name}}, {name}, {{}}, {}")' in x]) == 1
|
||||
|
||||
def test_help_message(self, modulefile_content, module_configuration):
|
||||
"""Tests the generation of module help message."""
|
||||
|
||||
@@ -232,18 +223,6 @@ def test_help_message(self, modulefile_content, module_configuration):
|
||||
)
|
||||
assert help_msg in "".join(content)
|
||||
|
||||
content = modulefile_content("module-long-help target=core2")
|
||||
|
||||
help_msg = (
|
||||
"help([[Name : module-long-help]])"
|
||||
"help([[Version: 1.0]])"
|
||||
"help([[Target : core2]])"
|
||||
"help()"
|
||||
"help([[Package to test long description message generated in modulefile."
|
||||
"Message too long is wrapped over multiple lines.]])"
|
||||
)
|
||||
assert help_msg in "".join(content)
|
||||
|
||||
def test_exclude(self, modulefile_content, module_configuration):
|
||||
"""Tests excluding the generation of selected modules."""
|
||||
module_configuration("exclude")
|
||||
|
@@ -29,7 +29,7 @@ def test_simple_case(self, modulefile_content, module_configuration):
|
||||
module_configuration("autoload_direct")
|
||||
content = modulefile_content(mpich_spec_string)
|
||||
|
||||
assert "module-whatis {mpich @3.0.4}" in content
|
||||
assert 'module-whatis "mpich @3.0.4"' in content
|
||||
|
||||
def test_autoload_direct(self, modulefile_content, module_configuration):
|
||||
"""Tests the automatic loading of direct dependencies."""
|
||||
@@ -112,16 +112,16 @@ def test_alter_environment(self, modulefile_content, module_configuration):
|
||||
content = modulefile_content("mpileaks platform=test target=x86_64")
|
||||
|
||||
assert len([x for x in content if x.startswith("prepend-path CMAKE_PREFIX_PATH")]) == 0
|
||||
assert len([x for x in content if "setenv FOO {foo}" in x]) == 1
|
||||
assert len([x for x in content if "setenv OMPI_MCA_mpi_leave_pinned {1}" in x]) == 1
|
||||
assert len([x for x in content if "setenv OMPI_MCA_MPI_LEAVE_PINNED {1}" in x]) == 0
|
||||
assert len([x for x in content if 'setenv FOO "foo"' in x]) == 1
|
||||
assert len([x for x in content if 'setenv OMPI_MCA_mpi_leave_pinned "1"' in x]) == 1
|
||||
assert len([x for x in content if 'setenv OMPI_MCA_MPI_LEAVE_PINNED "1"' in x]) == 0
|
||||
assert len([x for x in content if "unsetenv BAR" in x]) == 1
|
||||
assert len([x for x in content if "setenv MPILEAKS_ROOT" in x]) == 1
|
||||
|
||||
content = modulefile_content("libdwarf platform=test target=core2")
|
||||
|
||||
assert len([x for x in content if x.startswith("prepend-path CMAKE_PREFIX_PATH")]) == 0
|
||||
assert len([x for x in content if "setenv FOO {foo}" in x]) == 0
|
||||
assert len([x for x in content if 'setenv FOO "foo"' in x]) == 0
|
||||
assert len([x for x in content if "unsetenv BAR" in x]) == 0
|
||||
assert len([x for x in content if "depends-on foo/bar" in x]) == 1
|
||||
assert len([x for x in content if "module load foo/bar" in x]) == 1
|
||||
@@ -133,14 +133,14 @@ def test_prepend_path_separator(self, modulefile_content, module_configuration):
|
||||
module_configuration("module_path_separator")
|
||||
content = modulefile_content("module-path-separator")
|
||||
|
||||
assert len([x for x in content if "append-path --delim {:} COLON {foo}" in x]) == 1
|
||||
assert len([x for x in content if "prepend-path --delim {:} COLON {foo}" in x]) == 1
|
||||
assert len([x for x in content if "remove-path --delim {:} COLON {foo}" in x]) == 1
|
||||
assert len([x for x in content if "append-path --delim {;} SEMICOLON {bar}" in x]) == 1
|
||||
assert len([x for x in content if "prepend-path --delim {;} SEMICOLON {bar}" in x]) == 1
|
||||
assert len([x for x in content if "remove-path --delim {;} SEMICOLON {bar}" in x]) == 1
|
||||
assert len([x for x in content if "append-path --delim { } SPACE {qux}" in x]) == 1
|
||||
assert len([x for x in content if "remove-path --delim { } SPACE {qux}" in x]) == 1
|
||||
assert len([x for x in content if 'append-path --delim ":" COLON "foo"' in x]) == 1
|
||||
assert len([x for x in content if 'prepend-path --delim ":" COLON "foo"' in x]) == 1
|
||||
assert len([x for x in content if 'remove-path --delim ":" COLON "foo"' in x]) == 1
|
||||
assert len([x for x in content if 'append-path --delim ";" SEMICOLON "bar"' in x]) == 1
|
||||
assert len([x for x in content if 'prepend-path --delim ";" SEMICOLON "bar"' in x]) == 1
|
||||
assert len([x for x in content if 'remove-path --delim ";" SEMICOLON "bar"' in x]) == 1
|
||||
assert len([x for x in content if 'append-path --delim " " SPACE "qux"' in x]) == 1
|
||||
assert len([x for x in content if 'remove-path --delim " " SPACE "qux"' in x]) == 1
|
||||
|
||||
@pytest.mark.regression("11355")
|
||||
def test_manpath_setup(self, modulefile_content, module_configuration):
|
||||
@@ -150,12 +150,12 @@ def test_manpath_setup(self, modulefile_content, module_configuration):
|
||||
|
||||
# no manpath set by module
|
||||
content = modulefile_content("mpileaks")
|
||||
assert len([x for x in content if "append-path --delim {:} MANPATH {}" in x]) == 0
|
||||
assert len([x for x in content if 'append-path --delim ":" MANPATH ""' in x]) == 0
|
||||
|
||||
# manpath set by module with prepend-path
|
||||
content = modulefile_content("module-manpath-prepend")
|
||||
assert (
|
||||
len([x for x in content if "prepend-path --delim {:} MANPATH {/path/to/man}" in x])
|
||||
len([x for x in content if 'prepend-path --delim ":" MANPATH "/path/to/man"' in x])
|
||||
== 1
|
||||
)
|
||||
assert (
|
||||
@@ -163,33 +163,24 @@ def test_manpath_setup(self, modulefile_content, module_configuration):
|
||||
[
|
||||
x
|
||||
for x in content
|
||||
if "prepend-path --delim {:} MANPATH {/path/to/share/man}" in x
|
||||
if 'prepend-path --delim ":" MANPATH "/path/to/share/man"' in x
|
||||
]
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert len([x for x in content if "append-path --delim {:} MANPATH {}" in x]) == 1
|
||||
assert len([x for x in content if 'append-path --delim ":" MANPATH ""' in x]) == 1
|
||||
|
||||
# manpath set by module with append-path
|
||||
content = modulefile_content("module-manpath-append")
|
||||
assert (
|
||||
len([x for x in content if "append-path --delim {:} MANPATH {/path/to/man}" in x]) == 1
|
||||
len([x for x in content if 'append-path --delim ":" MANPATH "/path/to/man"' in x]) == 1
|
||||
)
|
||||
assert len([x for x in content if "append-path --delim {:} MANPATH {}" in x]) == 1
|
||||
assert len([x for x in content if 'append-path --delim ":" MANPATH ""' in x]) == 1
|
||||
|
||||
# manpath set by module with setenv
|
||||
content = modulefile_content("module-manpath-setenv")
|
||||
assert len([x for x in content if "setenv MANPATH {/path/to/man}" in x]) == 1
|
||||
assert len([x for x in content if "append-path --delim {:} MANPATH {}" in x]) == 0
|
||||
|
||||
@pytest.mark.regression("29578")
|
||||
def test_setenv_raw_value(self, modulefile_content, module_configuration):
|
||||
"""Tests that we can set environment variable value without formatting it."""
|
||||
|
||||
module_configuration("autoload_direct")
|
||||
content = modulefile_content("module-setenv-raw")
|
||||
|
||||
assert len([x for x in content if "setenv FOO {{{name}}, {name}, {{}}, {}}" in x]) == 1
|
||||
assert len([x for x in content if 'setenv MANPATH "/path/to/man"' in x]) == 1
|
||||
assert len([x for x in content if 'append-path --delim ":" MANPATH ""' in x]) == 0
|
||||
|
||||
def test_help_message(self, modulefile_content, module_configuration):
|
||||
"""Tests the generation of module help message."""
|
||||
@@ -199,11 +190,11 @@ def test_help_message(self, modulefile_content, module_configuration):
|
||||
|
||||
help_msg = (
|
||||
"proc ModulesHelp { } {"
|
||||
" puts stderr {Name : mpileaks}"
|
||||
" puts stderr {Version: 2.3}"
|
||||
" puts stderr {Target : core2}"
|
||||
" puts stderr {}"
|
||||
" puts stderr {Mpileaks is a mock package that passes audits}"
|
||||
' puts stderr "Name : mpileaks"'
|
||||
' puts stderr "Version: 2.3"'
|
||||
' puts stderr "Target : core2"'
|
||||
' puts stderr ""'
|
||||
' puts stderr "Mpileaks is a mock package that passes audits"'
|
||||
"}"
|
||||
)
|
||||
assert help_msg in "".join(content)
|
||||
@@ -212,23 +203,9 @@ def test_help_message(self, modulefile_content, module_configuration):
|
||||
|
||||
help_msg = (
|
||||
"proc ModulesHelp { } {"
|
||||
" puts stderr {Name : libdwarf}"
|
||||
" puts stderr {Version: 20130729}"
|
||||
" puts stderr {Target : core2}"
|
||||
"}"
|
||||
)
|
||||
assert help_msg in "".join(content)
|
||||
|
||||
content = modulefile_content("module-long-help target=core2")
|
||||
|
||||
help_msg = (
|
||||
"proc ModulesHelp { } {"
|
||||
" puts stderr {Name : module-long-help}"
|
||||
" puts stderr {Version: 1.0}"
|
||||
" puts stderr {Target : core2}"
|
||||
" puts stderr {}"
|
||||
" puts stderr {Package to test long description message generated in modulefile.}"
|
||||
" puts stderr {Message too long is wrapped over multiple lines.}"
|
||||
' puts stderr "Name : libdwarf"'
|
||||
' puts stderr "Version: 20130729"'
|
||||
' puts stderr "Target : core2"'
|
||||
"}"
|
||||
)
|
||||
assert help_msg in "".join(content)
|
||||
@@ -383,14 +360,14 @@ def test_setup_environment(self, modulefile_content, module_configuration):
|
||||
content = modulefile_content("mpileaks")
|
||||
|
||||
assert len([x for x in content if "setenv FOOBAR" in x]) == 1
|
||||
assert len([x for x in content if "setenv FOOBAR {mpileaks}" in x]) == 1
|
||||
assert len([x for x in content if 'setenv FOOBAR "mpileaks"' in x]) == 1
|
||||
|
||||
spec = spack.spec.Spec("mpileaks")
|
||||
spec.concretize()
|
||||
content = modulefile_content(str(spec["callpath"]))
|
||||
|
||||
assert len([x for x in content if "setenv FOOBAR" in x]) == 1
|
||||
assert len([x for x in content if "setenv FOOBAR {callpath}" in x]) == 1
|
||||
assert len([x for x in content if 'setenv FOOBAR "callpath"' in x]) == 1
|
||||
|
||||
def test_override_config(self, module_configuration, factory):
|
||||
"""Tests overriding some sections of the configuration file."""
|
||||
@@ -431,7 +408,7 @@ def test_extend_context(self, modulefile_content, module_configuration):
|
||||
|
||||
assert 'puts stderr "sentence from package"' in content
|
||||
|
||||
short_description = "module-whatis {This package updates the context for Tcl modulefiles.}"
|
||||
short_description = 'module-whatis "This package updates the context for Tcl modulefiles."'
|
||||
assert short_description in content
|
||||
|
||||
@pytest.mark.regression("4400")
|
||||
|
@@ -100,7 +100,7 @@ def test_buildcache(mock_archive, tmpdir):
|
||||
parser = argparse.ArgumentParser()
|
||||
buildcache.setup_parser(parser)
|
||||
|
||||
create_args = ["create", "-a", "-f", "-d", mirror_path, pkghash]
|
||||
create_args = ["create", "-a", "-f", mirror_path, pkghash]
|
||||
# Create a private key to sign package with if gpg2 available
|
||||
spack.util.gpg.create(
|
||||
name="test key 1", expires="0", email="spack@googlegroups.com", comment="Spack test key"
|
||||
@@ -116,7 +116,7 @@ def test_buildcache(mock_archive, tmpdir):
|
||||
# Uninstall the package
|
||||
pkg.do_uninstall(force=True)
|
||||
|
||||
install_args = ["install", "-a", "-f", pkghash]
|
||||
install_args = ["install", "-f", pkghash]
|
||||
args = parser.parse_args(install_args)
|
||||
# Test install
|
||||
buildcache.buildcache(parser, args)
|
||||
@@ -131,30 +131,6 @@ def test_buildcache(mock_archive, tmpdir):
|
||||
assert buildinfo["relocate_textfiles"] == ["dummy.txt"]
|
||||
assert buildinfo["relocate_links"] == ["link_to_dummy.txt"]
|
||||
|
||||
# create build cache with relative path
|
||||
create_args.insert(create_args.index("-a"), "-f")
|
||||
create_args.insert(create_args.index("-a"), "-r")
|
||||
args = parser.parse_args(create_args)
|
||||
buildcache.buildcache(parser, args)
|
||||
|
||||
# Uninstall the package
|
||||
pkg.do_uninstall(force=True)
|
||||
|
||||
args = parser.parse_args(install_args)
|
||||
buildcache.buildcache(parser, args)
|
||||
|
||||
# test overwrite install
|
||||
install_args.insert(install_args.index("-a"), "-f")
|
||||
args = parser.parse_args(install_args)
|
||||
buildcache.buildcache(parser, args)
|
||||
|
||||
files = os.listdir(spec.prefix)
|
||||
assert "link_to_dummy.txt" in files
|
||||
assert "dummy.txt" in files
|
||||
# assert os.path.realpath(
|
||||
# os.path.join(spec.prefix, 'link_to_dummy.txt')
|
||||
# ) == os.path.realpath(os.path.join(spec.prefix, 'dummy.txt'))
|
||||
|
||||
args = parser.parse_args(["keys"])
|
||||
buildcache.buildcache(parser, args)
|
||||
|
||||
|
@@ -173,14 +173,6 @@ def test_ensure_binary_is_relocatable(source_file, is_relocatable):
|
||||
assert relocatable == is_relocatable
|
||||
|
||||
|
||||
@pytest.mark.requires_executables("patchelf", "strings", "file")
|
||||
@skip_unless_linux
|
||||
def test_patchelf_is_relocatable():
|
||||
patchelf = os.path.realpath(spack.relocate._patchelf())
|
||||
assert llnl.util.filesystem.is_exe(patchelf)
|
||||
spack.relocate.ensure_binary_is_relocatable(patchelf)
|
||||
|
||||
|
||||
@skip_unless_linux
|
||||
def test_ensure_binary_is_relocatable_errors(tmpdir):
|
||||
# The file passed in as argument must exist...
|
||||
@@ -241,30 +233,6 @@ def test_normalize_relative_paths(start_path, relative_paths, expected):
|
||||
assert normalized == expected
|
||||
|
||||
|
||||
def test_set_elf_rpaths(mock_patchelf):
|
||||
# Try to relocate a mock version of patchelf and check
|
||||
# the call made to patchelf itself
|
||||
patchelf = mock_patchelf("echo $@")
|
||||
rpaths = ["/usr/lib", "/usr/lib64", "/opt/local/lib"]
|
||||
output = spack.relocate._set_elf_rpaths(str(patchelf), rpaths)
|
||||
|
||||
# Assert that the arguments of the call to patchelf are as expected
|
||||
assert "--force-rpath" in output
|
||||
assert "--set-rpath " + ":".join(rpaths) in output
|
||||
assert str(patchelf) in output
|
||||
|
||||
|
||||
@skip_unless_linux
|
||||
def test_set_elf_rpaths_warning(mock_patchelf):
|
||||
# Mock a failing patchelf command and ensure it warns users
|
||||
patchelf = mock_patchelf("exit 1")
|
||||
rpaths = ["/usr/lib", "/usr/lib64", "/opt/local/lib"]
|
||||
# To avoid using capfd in order to check if the warning was triggered
|
||||
# here we just check that output is not set
|
||||
output = spack.relocate._set_elf_rpaths(str(patchelf), rpaths)
|
||||
assert output is None
|
||||
|
||||
|
||||
@pytest.mark.requires_executables("patchelf", "strings", "file", "gcc")
|
||||
@skip_unless_linux
|
||||
def test_relocate_text_bin(binary_with_rpaths, prefix_like):
|
||||
|
@@ -125,7 +125,7 @@ def _mock_installed(self):
|
||||
# use the installed C. It should *not* force A to use the installed D
|
||||
# *if* we're doing a fresh installation.
|
||||
a_spec = Spec(a)
|
||||
a_spec._add_dependency(c_spec, deptypes=("build", "link"))
|
||||
a_spec._add_dependency(c_spec, deptypes=("build", "link"), virtuals=())
|
||||
a_spec.concretize()
|
||||
assert spack.version.Version("2") == a_spec[c][d].version
|
||||
assert spack.version.Version("2") == a_spec[e].version
|
||||
@@ -148,7 +148,7 @@ def test_specify_preinstalled_dep(tmpdir, monkeypatch):
|
||||
monkeypatch.setattr(Spec, "installed", property(lambda x: x.name != "a"))
|
||||
|
||||
a_spec = Spec("a")
|
||||
a_spec._add_dependency(b_spec, deptypes=("build", "link"))
|
||||
a_spec._add_dependency(b_spec, deptypes=("build", "link"), virtuals=())
|
||||
a_spec.concretize()
|
||||
|
||||
assert set(x.name for x in a_spec.traverse()) == set(["a", "b", "c"])
|
||||
@@ -989,9 +989,9 @@ def test_synthetic_construction_of_split_dependencies_from_same_package(mock_pac
|
||||
link_run_spec = Spec("c@=1.0").concretized()
|
||||
build_spec = Spec("c@=2.0").concretized()
|
||||
|
||||
root.add_dependency_edge(link_run_spec, deptypes="link")
|
||||
root.add_dependency_edge(link_run_spec, deptypes="run")
|
||||
root.add_dependency_edge(build_spec, deptypes="build")
|
||||
root.add_dependency_edge(link_run_spec, deptypes="link", virtuals=())
|
||||
root.add_dependency_edge(link_run_spec, deptypes="run", virtuals=())
|
||||
root.add_dependency_edge(build_spec, deptypes="build", virtuals=())
|
||||
|
||||
# Check dependencies from the perspective of root
|
||||
assert len(root.dependencies()) == 2
|
||||
@@ -1017,7 +1017,7 @@ def test_synthetic_construction_bootstrapping(mock_packages, config):
|
||||
root = Spec("b@=2.0").concretized()
|
||||
bootstrap = Spec("b@=1.0").concretized()
|
||||
|
||||
root.add_dependency_edge(bootstrap, deptypes="build")
|
||||
root.add_dependency_edge(bootstrap, deptypes="build", virtuals=())
|
||||
|
||||
assert len(root.dependencies()) == 1
|
||||
assert root.dependencies()[0].name == "b"
|
||||
@@ -1036,7 +1036,7 @@ def test_addition_of_different_deptypes_in_multiple_calls(mock_packages, config)
|
||||
bootstrap = Spec("b@=1.0").concretized()
|
||||
|
||||
for current_deptype in ("build", "link", "run"):
|
||||
root.add_dependency_edge(bootstrap, deptypes=current_deptype)
|
||||
root.add_dependency_edge(bootstrap, deptypes=current_deptype, virtuals=())
|
||||
|
||||
# Check edges in dependencies
|
||||
assert len(root.edges_to_dependencies()) == 1
|
||||
@@ -1063,9 +1063,9 @@ def test_adding_same_deptype_with_the_same_name_raises(
|
||||
c1 = Spec("b@=1.0").concretized()
|
||||
c2 = Spec("b@=2.0").concretized()
|
||||
|
||||
p.add_dependency_edge(c1, deptypes=c1_deptypes)
|
||||
p.add_dependency_edge(c1, deptypes=c1_deptypes, virtuals=())
|
||||
with pytest.raises(spack.error.SpackError):
|
||||
p.add_dependency_edge(c2, deptypes=c2_deptypes)
|
||||
p.add_dependency_edge(c2, deptypes=c2_deptypes, virtuals=())
|
||||
|
||||
|
||||
@pytest.mark.regression("33499")
|
||||
@@ -1084,16 +1084,16 @@ def test_indexing_prefers_direct_or_transitive_link_deps():
|
||||
z3_flavor_1 = Spec("z3 +through_a1")
|
||||
z3_flavor_2 = Spec("z3 +through_z1")
|
||||
|
||||
root.add_dependency_edge(a1, deptypes=("build", "run", "test"))
|
||||
root.add_dependency_edge(a1, deptypes=("build", "run", "test"), virtuals=())
|
||||
|
||||
# unique package as a dep of a build/run/test type dep.
|
||||
a1.add_dependency_edge(a2, deptypes="all")
|
||||
a1.add_dependency_edge(z3_flavor_1, deptypes="all")
|
||||
a1.add_dependency_edge(a2, deptypes="all", virtuals=())
|
||||
a1.add_dependency_edge(z3_flavor_1, deptypes="all", virtuals=())
|
||||
|
||||
# chain of link type deps root -> z1 -> z2 -> z3
|
||||
root.add_dependency_edge(z1, deptypes="link")
|
||||
z1.add_dependency_edge(z2, deptypes="link")
|
||||
z2.add_dependency_edge(z3_flavor_2, deptypes="link")
|
||||
root.add_dependency_edge(z1, deptypes="link", virtuals=())
|
||||
z1.add_dependency_edge(z2, deptypes="link", virtuals=())
|
||||
z2.add_dependency_edge(z3_flavor_2, deptypes="link", virtuals=())
|
||||
|
||||
# Indexing should prefer the link-type dep.
|
||||
assert "through_z1" in root["z3"].variants
|
||||
|
@@ -660,6 +660,7 @@ def test_spec_formatting(self, default_mock_concretization):
|
||||
("{architecture.os}", "", "os", lambda spec: spec.architecture),
|
||||
("{architecture.target}", "", "target", lambda spec: spec.architecture),
|
||||
("{prefix}", "", "prefix", lambda spec: spec),
|
||||
("{external}", "", "external", lambda spec: spec), # test we print "False"
|
||||
]
|
||||
|
||||
hash_segments = [
|
||||
@@ -970,7 +971,7 @@ def test_error_message_unknown_variant(self):
|
||||
def test_satisfies_dependencies_ordered(self):
|
||||
d = Spec("zmpi ^fake")
|
||||
s = Spec("mpileaks")
|
||||
s._add_dependency(d, deptypes=())
|
||||
s._add_dependency(d, deptypes=(), virtuals=())
|
||||
assert s.satisfies("mpileaks ^zmpi ^fake")
|
||||
|
||||
@pytest.mark.parametrize("transitive", [True, False])
|
||||
@@ -1017,6 +1018,7 @@ def test_is_extension_after_round_trip_to_dict(config, mock_packages, spec_str):
|
||||
|
||||
|
||||
def test_malformed_spec_dict():
|
||||
# FIXME: This test was really testing the specific implementation with an ad-hoc test
|
||||
with pytest.raises(SpecError, match="malformed"):
|
||||
Spec.from_dict(
|
||||
{"spec": {"_meta": {"version": 2}, "nodes": [{"dependencies": {"name": "foo"}}]}}
|
||||
@@ -1024,6 +1026,7 @@ def test_malformed_spec_dict():
|
||||
|
||||
|
||||
def test_spec_dict_hashless_dep():
|
||||
# FIXME: This test was really testing the specific implementation with an ad-hoc test
|
||||
with pytest.raises(SpecError, match="Couldn't parse"):
|
||||
Spec.from_dict(
|
||||
{
|
||||
@@ -1117,7 +1120,7 @@ def test_concretize_partial_old_dag_hash_spec(mock_packages, config):
|
||||
|
||||
# add it to an abstract spec as a dependency
|
||||
top = Spec("dt-diamond")
|
||||
top.add_dependency_edge(bottom, deptypes=())
|
||||
top.add_dependency_edge(bottom, deptypes=(), virtuals=())
|
||||
|
||||
# concretize with the already-concrete dependency
|
||||
top.concretize()
|
||||
|
@@ -43,12 +43,6 @@ def check_json_round_trip(spec):
|
||||
assert spec.eq_dag(spec_from_json)
|
||||
|
||||
|
||||
def test_simple_spec():
|
||||
spec = Spec("mpileaks")
|
||||
check_yaml_round_trip(spec)
|
||||
check_json_round_trip(spec)
|
||||
|
||||
|
||||
def test_read_spec_from_signed_json():
|
||||
spec_dir = os.path.join(spack.paths.test_path, "data", "mirrors", "signed_json")
|
||||
file_name = (
|
||||
@@ -70,13 +64,6 @@ def check_spec(spec_to_check):
|
||||
check_spec(s)
|
||||
|
||||
|
||||
def test_normal_spec(mock_packages):
|
||||
spec = Spec("mpileaks+debug~opt")
|
||||
spec.normalize()
|
||||
check_yaml_round_trip(spec)
|
||||
check_json_round_trip(spec)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_yaml", ["playing_playlist: {{ action }} playlist {{ playlist_name }}"]
|
||||
)
|
||||
@@ -95,37 +82,28 @@ def test_invalid_json_spec(invalid_json, error_message):
|
||||
assert error_message in exc_msg
|
||||
|
||||
|
||||
def test_external_spec(config, mock_packages):
|
||||
spec = Spec("externaltool")
|
||||
spec.concretize()
|
||||
check_yaml_round_trip(spec)
|
||||
check_json_round_trip(spec)
|
||||
|
||||
spec = Spec("externaltest")
|
||||
spec.concretize()
|
||||
check_yaml_round_trip(spec)
|
||||
check_json_round_trip(spec)
|
||||
|
||||
|
||||
def test_ambiguous_version_spec(mock_packages):
|
||||
spec = Spec("mpileaks@1.0:5.0,6.1,7.3+debug~opt")
|
||||
spec.normalize()
|
||||
check_yaml_round_trip(spec)
|
||||
check_json_round_trip(spec)
|
||||
|
||||
|
||||
def test_concrete_spec(config, mock_packages):
|
||||
spec = Spec("mpileaks+debug~opt")
|
||||
spec.concretize()
|
||||
check_yaml_round_trip(spec)
|
||||
check_json_round_trip(spec)
|
||||
|
||||
|
||||
def test_yaml_multivalue(config, mock_packages):
|
||||
spec = Spec('multivalue-variant foo="bar,baz"')
|
||||
spec.concretize()
|
||||
check_yaml_round_trip(spec)
|
||||
check_json_round_trip(spec)
|
||||
@pytest.mark.parametrize(
|
||||
"abstract_spec",
|
||||
[
|
||||
# Externals
|
||||
"externaltool",
|
||||
"externaltest",
|
||||
# Ambiguous version spec
|
||||
"mpileaks@1.0:5.0,6.1,7.3+debug~opt",
|
||||
# Variants
|
||||
"mpileaks+debug~opt",
|
||||
'multivalue-variant foo="bar,baz"',
|
||||
# Virtuals on edges
|
||||
"callpath",
|
||||
"mpileaks",
|
||||
],
|
||||
)
|
||||
def test_roundtrip_concrete_specs(abstract_spec, default_mock_concretization):
|
||||
check_yaml_round_trip(Spec(abstract_spec))
|
||||
check_json_round_trip(Spec(abstract_spec))
|
||||
concrete_spec = default_mock_concretization(abstract_spec)
|
||||
check_yaml_round_trip(concrete_spec)
|
||||
check_json_round_trip(concrete_spec)
|
||||
|
||||
|
||||
def test_yaml_subdag(config, mock_packages):
|
||||
@@ -506,6 +484,8 @@ def test_legacy_yaml(tmpdir, install_mockery, mock_packages):
|
||||
("specfiles/hdf5.v017.json.gz", "xqh5iyjjtrp2jw632cchacn3l7vqzf3m", spack.spec.SpecfileV2),
|
||||
# Use "full hash" everywhere, see https://github.com/spack/spack/pull/28504
|
||||
("specfiles/hdf5.v019.json.gz", "iulacrbz7o5v5sbj7njbkyank3juh6d3", spack.spec.SpecfileV3),
|
||||
# Add properties on edges, see https://github.com/spack/spack/pull/34821
|
||||
("specfiles/hdf5.v020.json.gz", "vlirlcgazhvsvtundz4kug75xkkqqgou", spack.spec.SpecfileV4),
|
||||
],
|
||||
)
|
||||
def test_load_json_specfiles(specfile, expected_hash, reader_cls):
|
||||
|
@@ -19,7 +19,7 @@ def create_dag(nodes, edges):
|
||||
"""
|
||||
specs = {name: Spec(name) for name in nodes}
|
||||
for parent, child, deptypes in edges:
|
||||
specs[parent].add_dependency_edge(specs[child], deptypes=deptypes)
|
||||
specs[parent].add_dependency_edge(specs[child], deptypes=deptypes, virtuals=())
|
||||
return specs
|
||||
|
||||
|
||||
|
@@ -119,7 +119,10 @@ def test_dump_environment(prepare_environment_for_tests, tmpdir):
|
||||
dumpfile_path = str(tmpdir.join("envdump.txt"))
|
||||
envutil.dump_environment(dumpfile_path)
|
||||
with open(dumpfile_path, "r") as dumpfile:
|
||||
assert "TEST_ENV_VAR={0}; export TEST_ENV_VAR\n".format(test_paths) in list(dumpfile)
|
||||
if sys.platform == "win32":
|
||||
assert 'set "TEST_ENV_VAR={}"\n'.format(test_paths) in list(dumpfile)
|
||||
else:
|
||||
assert "TEST_ENV_VAR={0}; export TEST_ENV_VAR\n".format(test_paths) in list(dumpfile)
|
||||
|
||||
|
||||
def test_reverse_environment_modifications(working_env):
|
||||
|
@@ -244,7 +244,6 @@ def check_ast_roundtrip(code1, filename="internal", mode="exec"):
|
||||
assert ast.dump(ast1) == ast.dump(ast2), error_msg
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="https://github.com/spack/spack/pull/38424")
|
||||
def test_core_lib_files():
|
||||
"""Roundtrip source files from the Python core libs."""
|
||||
test_directories = [
|
||||
|
@@ -17,7 +17,6 @@
|
||||
import spack.package_base
|
||||
import spack.spec
|
||||
from spack.version import (
|
||||
SEMVER_REGEX,
|
||||
GitVersion,
|
||||
StandardVersion,
|
||||
Version,
|
||||
@@ -977,25 +976,3 @@ def test_unresolvable_git_versions_error(config, mock_packages):
|
||||
# The package exists, but does not have a git property set. When dereferencing
|
||||
# the version, we should get VersionLookupError, not a generic AttributeError.
|
||||
spack.spec.Spec(f"git-test-commit@{'a' * 40}").version.ref_version
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"tag,expected",
|
||||
[
|
||||
("v100.2.3", "100.2.3"),
|
||||
("v1.2.3", "1.2.3"),
|
||||
("v1.2.3-pre.release+build.1", "1.2.3-pre.release+build.1"),
|
||||
("v1.2.3+build.1", "1.2.3+build.1"),
|
||||
("v1.2.3+build_1", None),
|
||||
("v1.2.3-pre.release", "1.2.3-pre.release"),
|
||||
("v1.2.3-pre_release", None),
|
||||
("1.2.3", "1.2.3"),
|
||||
("1.2.3.", None),
|
||||
],
|
||||
)
|
||||
def test_semver_regex(tag, expected):
|
||||
result = SEMVER_REGEX.search(tag)
|
||||
if expected is None:
|
||||
assert result is None
|
||||
else:
|
||||
assert result.group() == expected
|
||||
|
@@ -4,7 +4,6 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import collections
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -34,7 +33,6 @@ def _create_url(relative_url):
|
||||
root_with_fragment = _create_url("index_with_fragment.html")
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
@pytest.mark.parametrize(
|
||||
"depth,expected_found,expected_not_found,expected_text",
|
||||
[
|
||||
@@ -99,20 +97,17 @@ def test_spider_no_response(monkeypatch):
|
||||
assert not pages and not links
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
def test_find_versions_of_archive_0():
|
||||
versions = spack.util.web.find_versions_of_archive(root_tarball, root, list_depth=0)
|
||||
assert Version("0.0.0") in versions
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
def test_find_versions_of_archive_1():
|
||||
versions = spack.util.web.find_versions_of_archive(root_tarball, root, list_depth=1)
|
||||
assert Version("0.0.0") in versions
|
||||
assert Version("1.0.0") in versions
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
def test_find_versions_of_archive_2():
|
||||
versions = spack.util.web.find_versions_of_archive(root_tarball, root, list_depth=2)
|
||||
assert Version("0.0.0") in versions
|
||||
@@ -120,14 +115,12 @@ def test_find_versions_of_archive_2():
|
||||
assert Version("2.0.0") in versions
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
def test_find_exotic_versions_of_archive_2():
|
||||
versions = spack.util.web.find_versions_of_archive(root_tarball, root, list_depth=2)
|
||||
# up for grabs to make this better.
|
||||
assert Version("2.0.0b2") in versions
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
def test_find_versions_of_archive_3():
|
||||
versions = spack.util.web.find_versions_of_archive(root_tarball, root, list_depth=3)
|
||||
assert Version("0.0.0") in versions
|
||||
@@ -137,7 +130,6 @@ def test_find_versions_of_archive_3():
|
||||
assert Version("4.5") in versions
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
def test_find_exotic_versions_of_archive_3():
|
||||
versions = spack.util.web.find_versions_of_archive(root_tarball, root, list_depth=3)
|
||||
assert Version("2.0.0b2") in versions
|
||||
@@ -145,7 +137,6 @@ def test_find_exotic_versions_of_archive_3():
|
||||
assert Version("4.5-rc5") in versions
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
def test_find_versions_of_archive_with_fragment():
|
||||
versions = spack.util.web.find_versions_of_archive(
|
||||
root_tarball, root_with_fragment, list_depth=0
|
||||
@@ -206,7 +197,6 @@ def test_etag_parser():
|
||||
assert spack.util.web.parse_etag("abc def") is None
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
|
||||
def test_list_url(tmpdir):
|
||||
testpath = str(tmpdir)
|
||||
testpath_url = url_util.path_to_file_url(testpath)
|
||||
|
@@ -211,7 +211,9 @@ def get_visitor_from_args(cover, direction, deptype, key=id, visited=None, visit
|
||||
def with_artificial_edges(specs):
|
||||
"""Initialize a list of edges from an imaginary root node to the root specs."""
|
||||
return [
|
||||
EdgeAndDepth(edge=spack.spec.DependencySpec(parent=None, spec=s, deptypes=()), depth=0)
|
||||
EdgeAndDepth(
|
||||
edge=spack.spec.DependencySpec(parent=None, spec=s, deptypes=(), virtuals=()), depth=0
|
||||
)
|
||||
for s in specs
|
||||
]
|
||||
|
||||
@@ -552,8 +554,3 @@ def traverse_tree(specs, cover="nodes", deptype="all", key=id, depth_first=True)
|
||||
return traverse_breadth_first_tree_nodes(None, edges)
|
||||
|
||||
return traverse_edges(specs, order="pre", cover=cover, deptype=deptype, key=key, depth=True)
|
||||
|
||||
|
||||
def by_dag_hash(s: "spack.spec.Spec") -> str:
|
||||
"""Used very often as a key function for traversals."""
|
||||
return s.dag_hash()
|
||||
|
@@ -171,7 +171,11 @@ def path_put_first(var_name: str, directories: List[Path]):
|
||||
BASH_FUNCTION_FINDER = re.compile(r"BASH_FUNC_(.*?)\(\)")
|
||||
|
||||
|
||||
def _env_var_to_source_line(var: str, val: str) -> str:
|
||||
def _win_env_var_to_set_line(var: str, val: str) -> str:
|
||||
return f'set "{var}={val}"'
|
||||
|
||||
|
||||
def _nix_env_var_to_source_line(var: str, val: str) -> str:
|
||||
if var.startswith("BASH_FUNC"):
|
||||
source_line = "function {fname}{decl}; export -f {fname}".format(
|
||||
fname=BASH_FUNCTION_FINDER.sub(r"\1", var), decl=val
|
||||
@@ -181,6 +185,13 @@ def _env_var_to_source_line(var: str, val: str) -> str:
|
||||
return source_line
|
||||
|
||||
|
||||
def _env_var_to_source_line(var: str, val: str) -> str:
|
||||
if sys.platform == "win32":
|
||||
return _win_env_var_to_set_line(var, val)
|
||||
else:
|
||||
return _nix_env_var_to_source_line(var, val)
|
||||
|
||||
|
||||
@system_path_filter(arg_slice=slice(1))
|
||||
def dump_environment(path: Path, environment: Optional[MutableMapping[str, str]] = None):
|
||||
"""Dump an environment dictionary to a source-able file.
|
||||
@@ -340,20 +351,13 @@ def execute(self, env: MutableMapping[str, str]):
|
||||
|
||||
|
||||
class SetEnv(NameValueModifier):
|
||||
__slots__ = ("force", "raw")
|
||||
__slots__ = ("force",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
value: str,
|
||||
*,
|
||||
trace: Optional[Trace] = None,
|
||||
force: bool = False,
|
||||
raw: bool = False,
|
||||
self, name: str, value: str, *, trace: Optional[Trace] = None, force: bool = False
|
||||
):
|
||||
super().__init__(name, value, trace=trace)
|
||||
self.force = force
|
||||
self.raw = raw
|
||||
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
tty.debug(f"SetEnv: {self.name}={str(self.value)}", level=3)
|
||||
@@ -497,16 +501,15 @@ def _trace(self) -> Optional[Trace]:
|
||||
return Trace(filename=filename, lineno=lineno, context=current_context)
|
||||
|
||||
@system_env_normalize
|
||||
def set(self, name: str, value: str, *, force: bool = False, raw: bool = False):
|
||||
def set(self, name: str, value: str, *, force: bool = False):
|
||||
"""Stores a request to set an environment variable.
|
||||
|
||||
Args:
|
||||
name: name of the environment variable
|
||||
value: value of the environment variable
|
||||
force: if True, audit will not consider this modification a warning
|
||||
raw: if True, format of value string is skipped
|
||||
"""
|
||||
item = SetEnv(name, value, trace=self._trace(), force=force, raw=raw)
|
||||
item = SetEnv(name, value, trace=self._trace(), force=force)
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
@@ -765,21 +768,16 @@ def from_sourcing_file(
|
||||
"PS1",
|
||||
"PS2",
|
||||
"ENV",
|
||||
# Environment Modules or Lmod
|
||||
# Environment modules v4
|
||||
"LOADEDMODULES",
|
||||
"_LMFILES_",
|
||||
"MODULEPATH",
|
||||
"MODULERCFILE",
|
||||
"BASH_FUNC_ml()",
|
||||
"BASH_FUNC_module()",
|
||||
# Environment Modules-specific configuration
|
||||
"MODULESHOME",
|
||||
"BASH_FUNC__module_raw()",
|
||||
r"MODULES_(.*)",
|
||||
r"__MODULES_(.*)",
|
||||
"MODULEPATH",
|
||||
"MODULES_(.*)",
|
||||
r"(\w*)_mod(quar|share)",
|
||||
# Lmod-specific configuration
|
||||
# Lmod configuration
|
||||
r"LMOD_(.*)",
|
||||
"MODULERCFILE",
|
||||
]
|
||||
)
|
||||
|
||||
|
@@ -4,7 +4,6 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import errno
|
||||
import math
|
||||
import os
|
||||
import shutil
|
||||
|
||||
@@ -152,17 +151,18 @@ def __exit__(cm, type, value, traceback):
|
||||
|
||||
return WriteTransaction(self._get_lock(key), acquire=WriteContextManager)
|
||||
|
||||
def mtime(self, key) -> float:
|
||||
"""Return modification time of cache file, or -inf if it does not exist.
|
||||
def mtime(self, key):
|
||||
"""Return modification time of cache file, or 0 if it does not exist.
|
||||
|
||||
Time is in units returned by os.stat in the mtime field, which is
|
||||
platform-dependent.
|
||||
|
||||
"""
|
||||
if not self.init_entry(key):
|
||||
return -math.inf
|
||||
return 0
|
||||
else:
|
||||
return os.stat(self.cache_path(key)).st_mtime
|
||||
sinfo = os.stat(self.cache_path(key))
|
||||
return sinfo.st_mtime
|
||||
|
||||
def remove(self, key):
|
||||
file = self.cache_path(key)
|
||||
|
@@ -454,10 +454,6 @@ def visit_ClassDef(self, node):
|
||||
self.fill("@")
|
||||
self.dispatch(deco)
|
||||
self.fill("class " + node.name)
|
||||
if getattr(node, "type_params", False):
|
||||
self.write("[")
|
||||
interleave(lambda: self.write(", "), self.dispatch, node.type_params)
|
||||
self.write("]")
|
||||
with self.delimit_if("(", ")", condition=node.bases or node.keywords):
|
||||
comma = False
|
||||
for e in node.bases:
|
||||
@@ -503,10 +499,6 @@ def __FunctionDef_helper(self, node, fill_suffix):
|
||||
self.dispatch(deco)
|
||||
def_str = fill_suffix + " " + node.name
|
||||
self.fill(def_str)
|
||||
if getattr(node, "type_params", False):
|
||||
self.write("[")
|
||||
interleave(lambda: self.write(", "), self.dispatch, node.type_params)
|
||||
self.write("]")
|
||||
with self.delimit("(", ")"):
|
||||
self.dispatch(node.args)
|
||||
if getattr(node, "returns", False):
|
||||
@@ -1257,23 +1249,3 @@ def visit_MatchOr(self, node):
|
||||
with self.require_parens(_Precedence.BOR, node):
|
||||
self.set_precedence(pnext(_Precedence.BOR), *node.patterns)
|
||||
interleave(lambda: self.write(" | "), self.dispatch, node.patterns)
|
||||
|
||||
def visit_TypeAlias(self, node):
|
||||
self.fill("type ")
|
||||
self.dispatch(node.name)
|
||||
self.write(" = ")
|
||||
self.dispatch(node.value)
|
||||
|
||||
def visit_TypeVar(self, node):
|
||||
self.write(node.name)
|
||||
if node.bound:
|
||||
self.write(": ")
|
||||
self.dispatch(node.bound)
|
||||
|
||||
def visit_TypeVarTuple(self, node):
|
||||
self.write("*")
|
||||
self.write(node.name)
|
||||
|
||||
def visit_ParamSpec(self, node):
|
||||
self.write("**")
|
||||
self.write(node.name)
|
||||
|
@@ -17,6 +17,7 @@
|
||||
import traceback
|
||||
import urllib.parse
|
||||
from html.parser import HTMLParser
|
||||
from pathlib import Path, PurePosixPath
|
||||
from urllib.error import URLError
|
||||
from urllib.request import HTTPSHandler, Request, build_opener
|
||||
|
||||
@@ -498,7 +499,8 @@ def list_url(url, recursive=False):
|
||||
|
||||
if local_path:
|
||||
if recursive:
|
||||
return list(_iter_local_prefix(local_path))
|
||||
# convert backslash to forward slash as required for URLs
|
||||
return [str(PurePosixPath(Path(p))) for p in list(_iter_local_prefix(local_path))]
|
||||
return [
|
||||
subpath
|
||||
for subpath in os.listdir(local_path)
|
||||
@@ -738,7 +740,8 @@ def find_versions_of_archive(
|
||||
|
||||
# We'll be a bit more liberal and just look for the archive
|
||||
# part, not the full path.
|
||||
url_regex = os.path.basename(url_regex)
|
||||
# this is a URL so it is a posixpath even on Windows
|
||||
url_regex = PurePosixPath(url_regex).name
|
||||
|
||||
# We need to add a / to the beginning of the regex to prevent
|
||||
# Spack from picking up similarly named packages like:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user