Compare commits
670 Commits
e4s-21.05
...
features/k
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
702774edea | ||
|
|
7713dd4063 | ||
|
|
24c01d57cf | ||
|
|
620836a809 | ||
|
|
0c5402ea5c | ||
|
|
a22686279c | ||
|
|
0dd04ffbfb | ||
|
|
24a4d81097 | ||
|
|
b5d2c30d26 | ||
|
|
7a9fe189e1 | ||
|
|
f5c1ae32d1 | ||
|
|
e0b901153b | ||
|
|
4fd8640586 | ||
|
|
970bf4318c | ||
|
|
218ae0c5d1 | ||
|
|
ad7984c5c0 | ||
|
|
b1f4f91f41 | ||
|
|
2914f9076e | ||
|
|
663c37cac4 | ||
|
|
36ba640cbd | ||
|
|
5e33b20230 | ||
|
|
d3c04ed345 | ||
|
|
20a191ad93 | ||
|
|
d06537f75c | ||
|
|
09d89ef265 | ||
|
|
0e3f7ce0ed | ||
|
|
e914e561ec | ||
|
|
3c9a58bd0b | ||
|
|
59eea2859a | ||
|
|
c12dc1a5de | ||
|
|
ea2d4b05bc | ||
|
|
f9ecc4966d | ||
|
|
545f971bec | ||
|
|
9d36f7f518 | ||
|
|
e65ab166b9 | ||
|
|
f8743d0cbf | ||
|
|
9055deea16 | ||
|
|
1e3c012fea | ||
|
|
61242db8f9 | ||
|
|
9550703132 | ||
|
|
e450612188 | ||
|
|
115c39e762 | ||
|
|
b8f1bd407e | ||
|
|
cea11f3714 | ||
|
|
b35d6d13a7 | ||
|
|
6a1a4d4bb6 | ||
|
|
713fd67b4a | ||
|
|
2ded87d40e | ||
|
|
9963642c1c | ||
|
|
8e37c30e2f | ||
|
|
04289b2009 | ||
|
|
d764b776d7 | ||
|
|
1cb2855054 | ||
|
|
95b0eb9fdd | ||
|
|
a2a273832f | ||
|
|
cf6aa8f012 | ||
|
|
fd11c6f5f7 | ||
|
|
eaa918c8f3 | ||
|
|
eacba1ffac | ||
|
|
a3f6df33ef | ||
|
|
3b94e22ad4 | ||
|
|
e568564e2f | ||
|
|
6547f41096 | ||
|
|
c895332284 | ||
|
|
3d11716e54 | ||
|
|
f88d90e432 | ||
|
|
8089b86dc2 | ||
|
|
f1842f363d | ||
|
|
7ced07a141 | ||
|
|
189968e207 | ||
|
|
f54fad40ba | ||
|
|
38a010b580 | ||
|
|
e1694afdde | ||
|
|
d842c08a9b | ||
|
|
54219852d9 | ||
|
|
4a8a6b4c9d | ||
|
|
c5a27980df | ||
|
|
406117148d | ||
|
|
e6700d47aa | ||
|
|
ca550cd819 | ||
|
|
8c46e82862 | ||
|
|
d0bbe18c79 | ||
|
|
ca538e18a4 | ||
|
|
59028aa0a5 | ||
|
|
c8868f1922 | ||
|
|
89bed5773e | ||
|
|
1639ac8e86 | ||
|
|
7a794f8b0a | ||
|
|
4f9b539644 | ||
|
|
7753c816f0 | ||
|
|
0bbd71d561 | ||
|
|
b8512983d9 | ||
|
|
ea261e3530 | ||
|
|
acd1b04ea2 | ||
|
|
f2d60261c9 | ||
|
|
8ad1dd6036 | ||
|
|
c832ac28ae | ||
|
|
a647ae2aeb | ||
|
|
d00082e70b | ||
|
|
501f87fb22 | ||
|
|
55dd306790 | ||
|
|
a2b7f9997d | ||
|
|
1c6504d2f5 | ||
|
|
cc1285c1e1 | ||
|
|
304249604a | ||
|
|
1eb2798c43 | ||
|
|
e284cd136a | ||
|
|
f5474a2b8b | ||
|
|
c824cad2ea | ||
|
|
3fe1ecd807 | ||
|
|
2b65c53d2b | ||
|
|
327cca7e2e | ||
|
|
09fa155333 | ||
|
|
a7b6149cc0 | ||
|
|
b87d9c29c1 | ||
|
|
cc20dbf645 | ||
|
|
9a9b5dee2e | ||
|
|
69d69cbc79 | ||
|
|
2284007db9 | ||
|
|
744cedc7e9 | ||
|
|
e631ccc6f7 | ||
|
|
3cfc1dbc14 | ||
|
|
2970c02639 | ||
|
|
77a98cabfa | ||
|
|
b6aea0d6bf | ||
|
|
c06db97970 | ||
|
|
90dc90e8d1 | ||
|
|
f5ef532bdc | ||
|
|
2bd2ef27a2 | ||
|
|
a4a393d097 | ||
|
|
a6ce000e09 | ||
|
|
3e65828a7e | ||
|
|
6f950bc8ee | ||
|
|
963b931309 | ||
|
|
9bd9cc2c7b | ||
|
|
4c149ade7f | ||
|
|
ecc950d10c | ||
|
|
9b2e7e6140 | ||
|
|
19a973eca0 | ||
|
|
ce16503bd3 | ||
|
|
ef67ecde60 | ||
|
|
2b1916d845 | ||
|
|
469e580034 | ||
|
|
80585562c9 | ||
|
|
2aa9e337ee | ||
|
|
06a1cf2449 | ||
|
|
2a9b9c9046 | ||
|
|
b12cee32de | ||
|
|
17f9ddb2b5 | ||
|
|
dbf030f27a | ||
|
|
8937102006 | ||
|
|
cf0b3632ff | ||
|
|
6b852bc170 | ||
|
|
843c38e69e | ||
|
|
2bc0c0ea59 | ||
|
|
3087d74ca7 | ||
|
|
03f54ea4bb | ||
|
|
25522b5c9c | ||
|
|
f4b96a21c8 | ||
|
|
291703f146 | ||
|
|
6bf1f69b4c | ||
|
|
b9eeef8c38 | ||
|
|
ec2d4c07b3 | ||
|
|
7dafc827a7 | ||
|
|
26f740b25a | ||
|
|
0c996671b8 | ||
|
|
4eb4994472 | ||
|
|
916cdfbb56 | ||
|
|
d7405ddd39 | ||
|
|
010b431692 | ||
|
|
e45800126a | ||
|
|
7456a0348f | ||
|
|
1367cc97c2 | ||
|
|
9d0b8b575b | ||
|
|
8f2f5639c8 | ||
|
|
cf38a96b14 | ||
|
|
b1009b48b9 | ||
|
|
d3a1da8496 | ||
|
|
4985215072 | ||
|
|
db403391c8 | ||
|
|
3d631377c0 | ||
|
|
387ee5a0b7 | ||
|
|
1bccd866ae | ||
|
|
97f0c3ccd9 | ||
|
|
2db858e9c4 | ||
|
|
4da0561496 | ||
|
|
477c8ce820 | ||
|
|
323b47a94e | ||
|
|
acc11f676d | ||
|
|
02b92dbf10 | ||
|
|
09a6f3533b | ||
|
|
e4c38ba14c | ||
|
|
d292541edb | ||
|
|
07fe558509 | ||
|
|
377f031461 | ||
|
|
d63566915d | ||
|
|
11ad6e1a8a | ||
|
|
ccece0e197 | ||
|
|
65e7e1f969 | ||
|
|
b0a915a3b6 | ||
|
|
e3b220f699 | ||
|
|
512edfcceb | ||
|
|
8e249c03de | ||
|
|
726537e01b | ||
|
|
d71a0590b7 | ||
|
|
3039237a0e | ||
|
|
5e48d2c16f | ||
|
|
31e6967c49 | ||
|
|
c9932b2d1e | ||
|
|
c83f4b01aa | ||
|
|
7b6ca59038 | ||
|
|
62653b9c36 | ||
|
|
ebcc222181 | ||
|
|
9984e61347 | ||
|
|
76632d6710 | ||
|
|
d394e9978e | ||
|
|
5f415c9782 | ||
|
|
c432076280 | ||
|
|
73d7444ca7 | ||
|
|
93c75fe3f7 | ||
|
|
aa65293709 | ||
|
|
767f03f82f | ||
|
|
4ba6a850d9 | ||
|
|
91ef60eb0e | ||
|
|
383d4cc84c | ||
|
|
ca9ff82ad0 | ||
|
|
4690fdc081 | ||
|
|
1b368e433c | ||
|
|
94d6d3951a | ||
|
|
58272c9d57 | ||
|
|
1b51f09bf0 | ||
|
|
e3f4036212 | ||
|
|
eeacda3dce | ||
|
|
c6961ba4d3 | ||
|
|
32f1aa607c | ||
|
|
8ad05d6a74 | ||
|
|
57467d05e1 | ||
|
|
9750459e05 | ||
|
|
2c1e9cc7b7 | ||
|
|
e7ac422982 | ||
|
|
e916b699ee | ||
|
|
fa89ca2eb0 | ||
|
|
1c22742eed | ||
|
|
d4b5911671 | ||
|
|
47e9b62b43 | ||
|
|
100078ec3a | ||
|
|
54d8fea9fc | ||
|
|
3eee93ee76 | ||
|
|
b5cb75e5ec | ||
|
|
75675de02a | ||
|
|
b8ad621907 | ||
|
|
eac757da8c | ||
|
|
011a940f44 | ||
|
|
85c5589620 | ||
|
|
ee9b1a6ea5 | ||
|
|
986776c937 | ||
|
|
2739edd42c | ||
|
|
e4d80c997a | ||
|
|
3571c1b812 | ||
|
|
7831d6be75 | ||
|
|
c8f58c5f1d | ||
|
|
56f1904538 | ||
|
|
10608edd24 | ||
|
|
3adee93d14 | ||
|
|
d31d339bf6 | ||
|
|
5692c15e3a | ||
|
|
f0a85059c2 | ||
|
|
551ae264fe | ||
|
|
a92bed0dc5 | ||
|
|
3f9f2c2abe | ||
|
|
72c6fc2fda | ||
|
|
38088dd898 | ||
|
|
4f40454800 | ||
|
|
46214b0caa | ||
|
|
ce0eb4862f | ||
|
|
058ae3f0fd | ||
|
|
2439b8d59c | ||
|
|
891207f20e | ||
|
|
5ec708cb48 | ||
|
|
822d6a93fb | ||
|
|
64f3e37479 | ||
|
|
8a938978a4 | ||
|
|
a067b48112 | ||
|
|
ca1d1c427c | ||
|
|
b330474a13 | ||
|
|
1c44912f9b | ||
|
|
5971372be7 | ||
|
|
53dae0040a | ||
|
|
cdc28a9623 | ||
|
|
d4e04f9410 | ||
|
|
1bf84d170f | ||
|
|
d7263b5da0 | ||
|
|
ba65cc73ef | ||
|
|
c302887f9b | ||
|
|
5521aae4f7 | ||
|
|
229247c899 | ||
|
|
b92abd79ab | ||
|
|
26c645650d | ||
|
|
39cdd085c9 | ||
|
|
8793d93e8c | ||
|
|
34c9c89b55 | ||
|
|
d993ee7972 | ||
|
|
22fe56ad24 | ||
|
|
9cfcc16084 | ||
|
|
dcabbca1c5 | ||
|
|
25bca688ce | ||
|
|
0b769855a1 | ||
|
|
0d73fd2b11 | ||
|
|
dc8626b801 | ||
|
|
1b71d22194 | ||
|
|
95c9a031ee | ||
|
|
d6cbf72b19 | ||
|
|
ae91d49f21 | ||
|
|
8a0a60c575 | ||
|
|
163fe86bda | ||
|
|
8b75e81666 | ||
|
|
177750b215 | ||
|
|
b0f348315c | ||
|
|
11f370e7be | ||
|
|
4a8785d371 | ||
|
|
adc4699c3a | ||
|
|
44a8e17549 | ||
|
|
b4bf0c3476 | ||
|
|
a588d5dc58 | ||
|
|
31c4cdf59c | ||
|
|
98ee702b37 | ||
|
|
dbdf8f2ce7 | ||
|
|
ea08e93f2f | ||
|
|
dcb3fbf98e | ||
|
|
202510869d | ||
|
|
ed695f3267 | ||
|
|
a83b75b878 | ||
|
|
eefcd3d00d | ||
|
|
722376c201 | ||
|
|
269615b9ca | ||
|
|
ec2d8a1571 | ||
|
|
c630594092 | ||
|
|
e291fa1b1a | ||
|
|
8c7f94db1c | ||
|
|
f7391c1970 | ||
|
|
5926056f3a | ||
|
|
1c81438343 | ||
|
|
31bca57e89 | ||
|
|
9da1cb615f | ||
|
|
e4a79dab47 | ||
|
|
fd5b13b7a4 | ||
|
|
31c0bcf346 | ||
|
|
849943c63d | ||
|
|
47ef59c885 | ||
|
|
9c0fb86b48 | ||
|
|
29c4d5901a | ||
|
|
0dce021f94 | ||
|
|
8f34a66502 | ||
|
|
7499212bc1 | ||
|
|
7e9ed7e56d | ||
|
|
75db07e674 | ||
|
|
968d393f6b | ||
|
|
ac3b46fc95 | ||
|
|
fd03d539cc | ||
|
|
92bef1da6f | ||
|
|
3291be6cb1 | ||
|
|
d0fdbc1ab2 | ||
|
|
92be358582 | ||
|
|
f33c4e7280 | ||
|
|
e321578bbe | ||
|
|
a2e9a1b642 | ||
|
|
beed6047e8 | ||
|
|
11fd88ee3c | ||
|
|
418db4e910 | ||
|
|
f231ae97f4 | ||
|
|
e1bd3ae4db | ||
|
|
729d66a3f8 | ||
|
|
4d55203ce5 | ||
|
|
2bdeaa1b48 | ||
|
|
3d0bad465b | ||
|
|
506d5744aa | ||
|
|
026cf7aa30 | ||
|
|
e12b030def | ||
|
|
057bf434ce | ||
|
|
004f86aab7 | ||
|
|
c01730e33b | ||
|
|
1fed008410 | ||
|
|
b0590bf4e8 | ||
|
|
c2901ea14a | ||
|
|
b17046723d | ||
|
|
f07be01fa8 | ||
|
|
559db31511 | ||
|
|
e1d194b9a3 | ||
|
|
6ed7d40be7 | ||
|
|
1533c2fade | ||
|
|
986bcef160 | ||
|
|
09d317c293 | ||
|
|
7093fb214f | ||
|
|
534df5cd68 | ||
|
|
6c21d64c50 | ||
|
|
3db5029a4b | ||
|
|
7449d6950a | ||
|
|
9f8e40e95c | ||
|
|
af3ebeeea1 | ||
|
|
42df61d631 | ||
|
|
e741211c09 | ||
|
|
4cc27f58db | ||
|
|
7d3a3af621 | ||
|
|
ff73ac6e9a | ||
|
|
5c37db5db3 | ||
|
|
13978d68ea | ||
|
|
54b9fe219b | ||
|
|
1fd1f1c93f | ||
|
|
a0259cc4f4 | ||
|
|
d5d1d9548f | ||
|
|
e28e6d2618 | ||
|
|
d8fc38a467 | ||
|
|
c4c14e0c69 | ||
|
|
c09eea5947 | ||
|
|
b03049e938 | ||
|
|
b63a8b3e27 | ||
|
|
ea390198f4 | ||
|
|
fb05d9830a | ||
|
|
4ad779c4c4 | ||
|
|
1775383f5f | ||
|
|
a85bc4eee1 | ||
|
|
9903d05be9 | ||
|
|
70c81069ab | ||
|
|
e4a559a571 | ||
|
|
8aae76eee0 | ||
|
|
b83f06df0c | ||
|
|
7845da58a7 | ||
|
|
54bce50a17 | ||
|
|
c3898ca3bf | ||
|
|
1efeb933ec | ||
|
|
473e9aa08e | ||
|
|
7e168b8535 | ||
|
|
a8c7d9a2ed | ||
|
|
a478a8cf9a | ||
|
|
f7c9e497f1 | ||
|
|
ef9d3a464f | ||
|
|
08a4212ec3 | ||
|
|
038bd61e14 | ||
|
|
b4e347d2ef | ||
|
|
e1d578299e | ||
|
|
3b148f1192 | ||
|
|
28517deeeb | ||
|
|
194c8ee803 | ||
|
|
b369ff461a | ||
|
|
281b0e8c92 | ||
|
|
29554d867f | ||
|
|
410da48e81 | ||
|
|
e37d663881 | ||
|
|
3356c5fc71 | ||
|
|
622223823e | ||
|
|
ef47fe53ba | ||
|
|
237ff4b2b2 | ||
|
|
90e92bee4c | ||
|
|
b082f12730 | ||
|
|
66013eecd7 | ||
|
|
314329deea | ||
|
|
e8afc5db15 | ||
|
|
690558f927 | ||
|
|
c90f24d908 | ||
|
|
73c78358a8 | ||
|
|
50dac14d10 | ||
|
|
707a3f7df8 | ||
|
|
c6d21fa154 | ||
|
|
c015e84291 | ||
|
|
379482b653 | ||
|
|
8fe2be0010 | ||
|
|
4c3d58ad83 | ||
|
|
f8794afcbd | ||
|
|
389b02cf71 | ||
|
|
2cd8139cd7 | ||
|
|
e4edbe89cc | ||
|
|
f1d2ab38a0 | ||
|
|
ab254e7d86 | ||
|
|
c596dba039 | ||
|
|
26e1a8287f | ||
|
|
f35c3ef9ef | ||
|
|
976a97f045 | ||
|
|
bb5fd5c567 | ||
|
|
40803365f3 | ||
|
|
5fb68b4441 | ||
|
|
175e6e8c1e | ||
|
|
4a7b0afde2 | ||
|
|
ea4a2c9120 | ||
|
|
e5513f914e | ||
|
|
1fae271be8 | ||
|
|
c6da94473d | ||
|
|
adf2e8230a | ||
|
|
f3d506b582 | ||
|
|
647bee732c | ||
|
|
9d0b8208e4 | ||
|
|
9a902b67a1 | ||
|
|
444ba3d4cf | ||
|
|
bc78cf3a2c | ||
|
|
c8df8f2702 | ||
|
|
7bae865c7e | ||
|
|
8cdf42e1db | ||
|
|
ae2fc50861 | ||
|
|
c4e4d3587b | ||
|
|
bd6145589d | ||
|
|
7bdd906580 | ||
|
|
d4585f4328 | ||
|
|
120c718da5 | ||
|
|
9936182f60 | ||
|
|
6f534acbef | ||
|
|
f6febd2ef5 | ||
|
|
7490d63c38 | ||
|
|
9b99f85abf | ||
|
|
3c9c3c678d | ||
|
|
f8223303bb | ||
|
|
91f66ea0a4 | ||
|
|
4262de6a32 | ||
|
|
4171ee6650 | ||
|
|
0054e9bb08 | ||
|
|
405314195e | ||
|
|
e0fa0145e3 | ||
|
|
a9197d6e6d | ||
|
|
2507929308 | ||
|
|
a975cad6c6 | ||
|
|
27c8aac3b6 | ||
|
|
4365ed9205 | ||
|
|
fe302893ae | ||
|
|
d593aa5048 | ||
|
|
ebf6f71355 | ||
|
|
16d4b1ed32 | ||
|
|
f0eb4ca2d8 | ||
|
|
e06a3b7d45 | ||
|
|
c2e1e48fdc | ||
|
|
50ea1f8577 | ||
|
|
0c290ef1c3 | ||
|
|
1dd6bc2725 | ||
|
|
f1dc49bf42 | ||
|
|
de6e83f566 | ||
|
|
6a9e2eeb83 | ||
|
|
c4063b11fe | ||
|
|
6fc0e8dc9b | ||
|
|
031ef00a1f | ||
|
|
429b71bf57 | ||
|
|
850cac5ea3 | ||
|
|
e2399bcd0e | ||
|
|
b375500134 | ||
|
|
b255c698d5 | ||
|
|
53e4f32a31 | ||
|
|
e74d10fd78 | ||
|
|
f31bc986a8 | ||
|
|
ef56462867 | ||
|
|
b91dff4aaf | ||
|
|
214182529f | ||
|
|
dd0bd179c5 | ||
|
|
f92b7eca5e | ||
|
|
cc4029daab | ||
|
|
4e8d87e5cc | ||
|
|
30547f60d1 | ||
|
|
84ad5e444a | ||
|
|
cf15c42c1e | ||
|
|
d990c93cab | ||
|
|
b9a66966a8 | ||
|
|
2b78b04dc5 | ||
|
|
b120b51605 | ||
|
|
7473388f25 | ||
|
|
c9355ad8a4 | ||
|
|
a40e39f1f4 | ||
|
|
578de4c505 | ||
|
|
507ce17908 | ||
|
|
39a3dc4991 | ||
|
|
b7f7d901d1 | ||
|
|
f1e0053bf4 | ||
|
|
a9e3f21002 | ||
|
|
6d2d99d1fe | ||
|
|
35f7959f54 | ||
|
|
db65f458ec | ||
|
|
9e03284758 | ||
|
|
2421e489e4 | ||
|
|
f3e3e5514d | ||
|
|
b596abe037 | ||
|
|
b75ad9f950 | ||
|
|
051bcef697 | ||
|
|
de27e6cbdd | ||
|
|
1b6b5e1611 | ||
|
|
dbde984de1 | ||
|
|
3c587b14ad | ||
|
|
f2ce57bf77 | ||
|
|
3cef5663d8 | ||
|
|
b44bb952eb | ||
|
|
e22da8df05 | ||
|
|
c5389c430b | ||
|
|
a284edb852 | ||
|
|
29deb399b4 | ||
|
|
c9b957b71a | ||
|
|
929d1de3e5 | ||
|
|
56e7e2a406 | ||
|
|
6d29f0d61f | ||
|
|
cb13ba0fd8 | ||
|
|
7c73a786b3 | ||
|
|
cbd46be21b | ||
|
|
bed1644d52 | ||
|
|
00963149e1 | ||
|
|
fb2c3cce6d | ||
|
|
231490ce9a | ||
|
|
9426b26c22 | ||
|
|
bb13ce308a | ||
|
|
51a0228aed | ||
|
|
b7bcd31d9b | ||
|
|
d46e49ef7a | ||
|
|
b7d0b3ea75 | ||
|
|
4153c2e319 | ||
|
|
7f56394af9 | ||
|
|
b6416376db | ||
|
|
e952aa890e | ||
|
|
9a185b1d0b | ||
|
|
b793422e12 | ||
|
|
27e9f02d32 | ||
|
|
ec00d68ba1 | ||
|
|
d45674c1cb | ||
|
|
17473a08ff | ||
|
|
f1fe03cd59 | ||
|
|
80f0c78f00 | ||
|
|
818664d55a | ||
|
|
76c5a02125 | ||
|
|
0fd94d4486 | ||
|
|
fb156ae4bc | ||
|
|
30dd61264a | ||
|
|
13fed376f2 | ||
|
|
fb27c7ad0c | ||
|
|
4a7581eda3 | ||
|
|
0d173bb32b | ||
|
|
8a7bfe97c3 | ||
|
|
f1f94ad31a | ||
|
|
2655e21bd0 | ||
|
|
5546b22c70 | ||
|
|
2496c7b514 | ||
|
|
43cea1b354 | ||
|
|
cbd55332e3 | ||
|
|
c8a10e4910 | ||
|
|
a5213dabb1 | ||
|
|
6e714808fa | ||
|
|
9f99e8ad64 | ||
|
|
18880a668b | ||
|
|
e7494b627b | ||
|
|
b11dd0478a | ||
|
|
31a07f9bc4 | ||
|
|
61e619bb27 | ||
|
|
4d148a430e | ||
|
|
9717e0244f | ||
|
|
a823cffc40 | ||
|
|
f1c7402c64 | ||
|
|
16f7a02654 | ||
|
|
d8cbd37aaa | ||
|
|
4e6a6e4f27 | ||
|
|
1000deb5f9 | ||
|
|
cd61b2352d | ||
|
|
6c1b348d91 | ||
|
|
68ef6fce92 | ||
|
|
0b5c5b8068 | ||
|
|
add339cbfe | ||
|
|
316c292685 | ||
|
|
bd9929f9dc | ||
|
|
2a5f46d8d3 | ||
|
|
095ace9028 | ||
|
|
f30fc6cd33 | ||
|
|
4e5e1e8f35 | ||
|
|
0678d5df90 | ||
|
|
2a4d2f905c | ||
|
|
14e179398f | ||
|
|
8d13193434 | ||
|
|
94bb37c107 | ||
|
|
a59fcd60f5 | ||
|
|
566becbbfe | ||
|
|
8c05387ebc | ||
|
|
393a105c06 | ||
|
|
a3714b3292 |
@@ -14,3 +14,8 @@ ignore:
|
||||
- share/spack/qa/.*
|
||||
|
||||
comment: off
|
||||
|
||||
# Inline codecov annotations make the code hard to read, and they add
|
||||
# annotations in files that seemingly have nothing to do with the PR.
|
||||
github_checks:
|
||||
annotations: false
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
FROM python:3.7-alpine
|
||||
|
||||
RUN pip install pygithub
|
||||
|
||||
ADD entrypoint.py /entrypoint.py
|
||||
ENTRYPOINT ["/entrypoint.py"]
|
||||
@@ -1,85 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2013-2021 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)
|
||||
|
||||
"""Maintainer review action.
|
||||
|
||||
This action checks which packages have changed in a PR, and adds their
|
||||
maintainers to the pull request for review.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from github import Github
|
||||
|
||||
|
||||
def spack(*args):
|
||||
"""Run the spack executable with arguments, and return the output split.
|
||||
|
||||
This does just enough to run `spack pkg` and `spack maintainers`, the
|
||||
two commands used by this action.
|
||||
"""
|
||||
github_workspace = os.environ['GITHUB_WORKSPACE']
|
||||
spack = os.path.join(github_workspace, 'bin', 'spack')
|
||||
output = subprocess.check_output([spack] + list(args))
|
||||
split = re.split(r'\s*', output.decode('utf-8').strip())
|
||||
return [s for s in split if s]
|
||||
|
||||
|
||||
def main():
|
||||
# get these first so that we'll fail early
|
||||
token = os.environ['GITHUB_TOKEN']
|
||||
event_path = os.environ['GITHUB_EVENT_PATH']
|
||||
|
||||
with open(event_path) as file:
|
||||
data = json.load(file)
|
||||
|
||||
# make sure it's a pull_request event
|
||||
assert 'pull_request' in data
|
||||
|
||||
# only request reviews on open, edit, or reopen
|
||||
action = data['action']
|
||||
if action not in ('opened', 'edited', 'reopened'):
|
||||
return
|
||||
|
||||
# get data from the event payload
|
||||
pr_data = data['pull_request']
|
||||
base_branch_name = pr_data['base']['ref']
|
||||
full_repo_name = pr_data['base']['repo']['full_name']
|
||||
pr_number = pr_data['number']
|
||||
requested_reviewers = pr_data['requested_reviewers']
|
||||
author = pr_data['user']['login']
|
||||
|
||||
# get a list of packages that this PR modified
|
||||
changed_pkgs = spack(
|
||||
'pkg', 'changed', '--type', 'ac', '%s...' % base_branch_name)
|
||||
|
||||
# get maintainers for all modified packages
|
||||
maintainers = set()
|
||||
for pkg in changed_pkgs:
|
||||
pkg_maintainers = set(spack('maintainers', pkg))
|
||||
maintainers |= pkg_maintainers
|
||||
|
||||
# remove any maintainers who are already on the PR, and the author,
|
||||
# as you can't review your own PR)
|
||||
maintainers -= set(requested_reviewers)
|
||||
maintainers -= set([author])
|
||||
|
||||
if not maintainers:
|
||||
return
|
||||
|
||||
# request reviews from each maintainer
|
||||
gh = Github(token)
|
||||
repo = gh.get_repo(full_repo_name)
|
||||
pr = repo.get_pull(pr_number)
|
||||
pr.create_review_request(list(maintainers))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
2
.github/workflows/linux_build_tests.yaml
vendored
2
.github/workflows/linux_build_tests.yaml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
- ruby-rake # RubyPackage
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2.1.5
|
||||
- uses: actions/cache@v2.1.6
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ccache-build-${{ matrix.package }}
|
||||
|
||||
26
.github/workflows/unit_tests.yaml
vendored
26
.github/workflows/unit_tests.yaml
vendored
@@ -24,9 +24,9 @@ jobs:
|
||||
pip install --upgrade pip
|
||||
pip install --upgrade vermin
|
||||
- name: vermin (Spack's Core)
|
||||
run: vermin --backport argparse --backport typing -t=2.6- -t=3.5- -v lib/spack/spack/ lib/spack/llnl/ bin/
|
||||
run: vermin --backport argparse --violations --backport typing -t=2.6- -t=3.5- -vvv lib/spack/spack/ lib/spack/llnl/ bin/
|
||||
- name: vermin (Repositories)
|
||||
run: vermin --backport argparse --backport typing -t=2.6- -t=3.5- -v var/spack/repos
|
||||
run: vermin --backport argparse --violations --backport typing -t=2.6- -t=3.5- -vvv var/spack/repos
|
||||
# Run style checks on the files that have been changed
|
||||
style:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
python-version: 3.9
|
||||
- name: Install Python packages
|
||||
run: |
|
||||
pip install --upgrade pip six setuptools flake8 mypy>=0.800 black
|
||||
pip install --upgrade pip six setuptools flake8 isort>=4.3.5 mypy>=0.800 black types-six
|
||||
- name: Setup git configuration
|
||||
run: |
|
||||
# Need this for the git tests to succeed.
|
||||
@@ -129,8 +129,9 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
# Needed for unit tests
|
||||
sudo apt-get install -y coreutils gfortran graphviz gnupg2 mercurial
|
||||
sudo apt-get install -y ninja-build patchelf
|
||||
sudo apt-get -y install \
|
||||
coreutils cvs gfortran graphviz gnupg2 mercurial ninja-build \
|
||||
patchelf
|
||||
# Needed for kcov
|
||||
sudo apt-get -y install cmake binutils-dev libcurl4-openssl-dev
|
||||
sudo apt-get -y install zlib1g-dev libdw-dev libiberty-dev
|
||||
@@ -155,6 +156,8 @@ jobs:
|
||||
make -C ${KCOV_ROOT}/build && sudo make -C ${KCOV_ROOT}/build install
|
||||
- name: Bootstrap clingo from sources
|
||||
if: ${{ matrix.concretizer == 'clingo' }}
|
||||
env:
|
||||
SPACK_PYTHON: python
|
||||
run: |
|
||||
. share/spack/setup-env.sh
|
||||
spack external find --not-buildable cmake bison
|
||||
@@ -162,6 +165,7 @@ jobs:
|
||||
- name: Run unit tests (full suite with coverage)
|
||||
if: ${{ needs.changes.outputs.with_coverage == 'true' }}
|
||||
env:
|
||||
SPACK_PYTHON: python
|
||||
COVERAGE: true
|
||||
SPACK_TEST_SOLVER: ${{ matrix.concretizer }}
|
||||
run: |
|
||||
@@ -171,6 +175,7 @@ jobs:
|
||||
- name: Run unit tests (reduced suite without coverage)
|
||||
if: ${{ needs.changes.outputs.with_coverage == 'false' }}
|
||||
env:
|
||||
SPACK_PYTHON: python
|
||||
ONLY_PACKAGES: true
|
||||
SPACK_TEST_SOLVER: ${{ matrix.concretizer }}
|
||||
run: |
|
||||
@@ -283,12 +288,10 @@ jobs:
|
||||
useradd spack-test
|
||||
chown -R spack-test .
|
||||
- name: Run unit tests
|
||||
env:
|
||||
SPACK_PYTHON: /usr/libexec/platform-python
|
||||
shell: runuser -u spack-test -- bash {0}
|
||||
run: |
|
||||
source share/spack/setup-env.sh
|
||||
spack unit-test -k 'not svn and not hg' -x --verbose
|
||||
spack unit-test -k 'not cvs and not svn and not hg' -x --verbose
|
||||
# Test for the clingo based solver (using clingo-cffi)
|
||||
clingo-cffi:
|
||||
needs: [ validate, style, documentation, changes ]
|
||||
@@ -304,8 +307,9 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
# Needed for unit tests
|
||||
sudo apt-get install -y coreutils gfortran graphviz gnupg2 mercurial
|
||||
sudo apt-get install -y ninja-build patchelf
|
||||
sudo apt-get -y install \
|
||||
coreutils cvs gfortran graphviz gnupg2 mercurial ninja-build \
|
||||
patchelf
|
||||
# Needed for kcov
|
||||
sudo apt-get -y install cmake binutils-dev libcurl4-openssl-dev
|
||||
sudo apt-get -y install zlib1g-dev libdw-dev libiberty-dev
|
||||
@@ -366,7 +370,7 @@ jobs:
|
||||
run: |
|
||||
pip install --upgrade pip six setuptools
|
||||
pip install --upgrade codecov coverage
|
||||
pip install --upgrade flake8 pep8-naming mypy
|
||||
pip install --upgrade flake8 isort>=4.3.5 mypy>=0.800
|
||||
- name: Setup Homebrew packages
|
||||
run: |
|
||||
brew install dash fish gcc gnupg2 kcov
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -508,4 +508,4 @@ $RECYCLE.BIN/
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
*.lnk
|
||||
|
||||
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,3 +1,30 @@
|
||||
# v0.16.2 (2021-05-22)
|
||||
|
||||
* Major performance improvement for `spack load` and other commands. (#23661)
|
||||
* `spack fetch` is now environment-aware. (#19166)
|
||||
* Numerous fixes for the new, `clingo`-based concretizer. (#23016, #23307,
|
||||
#23090, #22896, #22534, #20644, #20537, #21148)
|
||||
* Supoprt for automatically bootstrapping `clingo` from source. (#20652, #20657
|
||||
#21364, #21446, #21913, #22354, #22444, #22460, #22489, #22610, #22631)
|
||||
* Python 3.10 support: `collections.abc` (#20441)
|
||||
* Fix import issues by using `__import__` instead of Spack package importe.
|
||||
(#23288, #23290)
|
||||
* Bugfixes and `--source-dir` argument for `spack location`. (#22755, #22348,
|
||||
#22321)
|
||||
* Better support for externals in shared prefixes. (#22653)
|
||||
* `spack build-env` now prefers specs defined in the active environment.
|
||||
(#21642)
|
||||
* Remove erroneous warnings about quotes in `from_sourcing_files`. (#22767)
|
||||
* Fix clearing cache of `InternalConfigScope`. (#22609)
|
||||
* Bugfix for active when pkg is already active error. (#22587)
|
||||
* Make `SingleFileScope` able to repopulate the cache after clearing it.
|
||||
(#22559)
|
||||
* Channelflow: Fix the package. (#22483)
|
||||
* More descriptive error message for bugs in `package.py` (#21811)
|
||||
* Use package-supplied `autogen.sh`. (#20319)
|
||||
* Respect `-k/verify-ssl-false` in `_existing_url` method. (#21864)
|
||||
|
||||
|
||||
# v0.16.1 (2021-02-22)
|
||||
|
||||
This minor release includes a new feature and associated fixes:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[](https://github.com/spack/spack/actions?query=workflow%3A%22macOS+builds+nightly%22)
|
||||
[](https://codecov.io/gh/spack/spack)
|
||||
[](https://spack.readthedocs.io)
|
||||
[](https://spackpm.herokuapp.com)
|
||||
[](https://slack.spack.io)
|
||||
|
||||
Spack is a multi-platform package manager that builds and installs
|
||||
multiple versions and configurations of software. It works on Linux,
|
||||
@@ -58,7 +58,7 @@ packages to bugfixes, documentation, or even new core features.
|
||||
Resources:
|
||||
|
||||
* **Slack workspace**: [spackpm.slack.com](https://spackpm.slack.com).
|
||||
To get an invitation, [**click here**](https://spackpm.herokuapp.com).
|
||||
To get an invitation, visit [slack.spack.io](https://slack.spack.io).
|
||||
* **Mailing list**: [groups.google.com/d/forum/spack](https://groups.google.com/d/forum/spack)
|
||||
* **Twitter**: [@spackpm](https://twitter.com/spackpm). Be sure to
|
||||
`@mention` us!
|
||||
@@ -72,7 +72,7 @@ When you send your request, make ``develop`` the destination branch on the
|
||||
|
||||
Your PR must pass Spack's unit tests and documentation tests, and must be
|
||||
[PEP 8](https://www.python.org/dev/peps/pep-0008/) compliant. We enforce
|
||||
these guidelines with our CI process. To run these tests locally, and for
|
||||
these guidelines with our CI process. To run these tests locally, and for
|
||||
helpful tips on git, see our
|
||||
[Contribution Guide](https://spack.readthedocs.io/en/latest/contribution_guide.html).
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
# See https://stackoverflow.com/a/47886254
|
||||
""":"
|
||||
# prefer SPACK_PYTHON environment variable, python3, python, then python2
|
||||
for cmd in "${SPACK_PYTHON:-}" python3 python python2; do
|
||||
SPACK_PREFERRED_PYTHONS="python3 python python2 /usr/libexec/platform-python"
|
||||
for cmd in "${SPACK_PYTHON:-}" ${SPACK_PREFERRED_PYTHONS}; do
|
||||
if command -v > /dev/null "$cmd"; then
|
||||
export SPACK_PYTHON="$(command -v "$cmd")"
|
||||
exec "${SPACK_PYTHON}" "$0" "$@"
|
||||
|
||||
@@ -33,13 +33,6 @@ config:
|
||||
template_dirs:
|
||||
- $spack/share/spack/templates
|
||||
|
||||
|
||||
# Locations where different types of modules should be installed.
|
||||
module_roots:
|
||||
tcl: $spack/share/spack/modules
|
||||
lmod: $spack/share/spack/lmod
|
||||
|
||||
|
||||
# Temporary locations Spack can try to use for builds.
|
||||
#
|
||||
# Recommended options are given below.
|
||||
|
||||
21
etc/spack/defaults/cray/modules.yaml
Normal file
21
etc/spack/defaults/cray/modules.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# -------------------------------------------------------------------------
|
||||
# This is the default configuration for Spack's module file generation.
|
||||
#
|
||||
# Settings here are versioned with Spack and are intended to provide
|
||||
# sensible defaults out of the box. Spack maintainers should edit this
|
||||
# file to keep it current.
|
||||
#
|
||||
# Users can override these settings by editing the following files.
|
||||
#
|
||||
# Per-spack-instance settings (overrides defaults):
|
||||
# $SPACK_ROOT/etc/spack/modules.yaml
|
||||
#
|
||||
# Per-user settings (overrides default and site settings):
|
||||
# ~/.spack/modules.yaml
|
||||
# -------------------------------------------------------------------------
|
||||
modules:
|
||||
prefix_inspections:
|
||||
lib:
|
||||
- LD_LIBRARY_PATH
|
||||
lib64:
|
||||
- LD_LIBRARY_PATH
|
||||
@@ -21,12 +21,10 @@ packages:
|
||||
- gcc
|
||||
- intel
|
||||
providers:
|
||||
elf:
|
||||
- libelf
|
||||
unwind:
|
||||
- apple-libunwind
|
||||
uuid:
|
||||
- apple-libuuid
|
||||
elf: [libelf]
|
||||
fuse: [macfuse]
|
||||
unwind: [apple-libunwind]
|
||||
uuid: [apple-libuuid]
|
||||
apple-libunwind:
|
||||
buildable: false
|
||||
externals:
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
mirrors:
|
||||
spack-public: https://spack-llnl-mirror.s3-us-west-2.amazonaws.com/
|
||||
spack-public: https://mirror.spack.io
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
# ~/.spack/modules.yaml
|
||||
# -------------------------------------------------------------------------
|
||||
modules:
|
||||
enable:
|
||||
- tcl
|
||||
# Paths to check when creating modules for all module sets
|
||||
prefix_inspections:
|
||||
bin:
|
||||
- PATH
|
||||
@@ -34,6 +33,20 @@ modules:
|
||||
'':
|
||||
- CMAKE_PREFIX_PATH
|
||||
|
||||
lmod:
|
||||
hierarchy:
|
||||
- mpi
|
||||
# These are configurations for the module set named "default"
|
||||
default:
|
||||
# These values are defaulted in the code. They are not defaulted here so
|
||||
# that we can enable backwards compatibility with the old syntax more
|
||||
# easily (old value is in the config yaml, config:module_roots)
|
||||
# Where to install modules
|
||||
# roots:
|
||||
# tcl: $spack/share/spack/modules
|
||||
# lmod: $spack/share/spack/lmod
|
||||
# What type of modules to use
|
||||
enable:
|
||||
- tcl
|
||||
|
||||
# Default configurations if lmod is enabled
|
||||
lmod:
|
||||
hierarchy:
|
||||
- mpi
|
||||
|
||||
@@ -17,39 +17,43 @@ packages:
|
||||
all:
|
||||
compiler: [gcc, intel, pgi, clang, xl, nag, fj, aocc]
|
||||
providers:
|
||||
D: [ldc]
|
||||
awk: [gawk]
|
||||
blas: [openblas, amdblis]
|
||||
D: [ldc]
|
||||
daal: [intel-daal]
|
||||
elf: [elfutils]
|
||||
fftw-api: [fftw, amdfftw]
|
||||
flame: [libflame, amdlibflame]
|
||||
fuse: [libfuse]
|
||||
gl: [mesa+opengl, mesa18, opengl]
|
||||
glx: [mesa+glx, mesa18+glx, opengl]
|
||||
glu: [mesa-glu, openglu]
|
||||
glx: [mesa+glx, mesa18+glx, opengl]
|
||||
golang: [gcc]
|
||||
iconv: [libiconv]
|
||||
ipp: [intel-ipp]
|
||||
java: [openjdk, jdk, ibm-java]
|
||||
jpeg: [libjpeg-turbo, libjpeg]
|
||||
lapack: [openblas, amdlibflame]
|
||||
lua-lang: [lua, lua-luajit]
|
||||
mariadb-client: [mariadb-c-client, mariadb]
|
||||
mkl: [intel-mkl]
|
||||
mpe: [mpe2]
|
||||
mpi: [openmpi, mpich]
|
||||
mysql-client: [mysql, mariadb-c-client]
|
||||
opencl: [pocl]
|
||||
onedal: [intel-oneapi-dal]
|
||||
osmesa: [mesa+osmesa, mesa18+osmesa]
|
||||
pil: [py-pillow]
|
||||
pkgconfig: [pkgconf, pkg-config]
|
||||
rpc: [libtirpc]
|
||||
scalapack: [netlib-scalapack, amdscalapack]
|
||||
sycl: [hipsycl]
|
||||
szip: [libszip, libaec]
|
||||
szip: [libaec, libszip]
|
||||
tbb: [intel-tbb]
|
||||
unwind: [libunwind]
|
||||
yacc: [bison, byacc]
|
||||
flame: [libflame, amdlibflame]
|
||||
uuid: [util-linux-uuid, libuuid]
|
||||
xxd: [xxd-standalone, vim]
|
||||
yacc: [bison, byacc]
|
||||
ziglang: [zig]
|
||||
permissions:
|
||||
read: world
|
||||
|
||||
@@ -1730,6 +1730,39 @@ This issue typically manifests with the error below:
|
||||
|
||||
A nicer error message is TBD in future versions of Spack.
|
||||
|
||||
---------------
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
The ``spack audit`` command:
|
||||
|
||||
.. command-output:: spack audit -h
|
||||
|
||||
can be used to detect a number of configuration issues. This command detects
|
||||
configuration settings which might not be strictly wrong but are not likely
|
||||
to be useful outside of special cases.
|
||||
|
||||
It can also be used to detect dependency issues with packages - for example
|
||||
cases where a package constrains a dependency with a variant that doesn't
|
||||
exist (in this case Spack could report the problem ahead of time but
|
||||
automatically performing the check would slow down most runs of Spack).
|
||||
|
||||
A detailed list of the checks currently implemented for each subcommand can be
|
||||
printed with:
|
||||
|
||||
.. command-output:: spack -v audit list
|
||||
|
||||
Depending on the use case, users might run the appropriate subcommands to obtain
|
||||
diagnostics. Issues, if found, are reported to stdout:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% spack audit packages lammps
|
||||
PKG-DIRECTIVES: 1 issue found
|
||||
1. lammps: wrong variant in "conflicts" directive
|
||||
the variant 'adios' does not exist
|
||||
in /home/spack/spack/var/spack/repos/builtin/packages/lammps/package.py
|
||||
|
||||
|
||||
------------
|
||||
Getting Help
|
||||
|
||||
@@ -31,9 +31,25 @@ Build caches are created via:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack buildcache create spec
|
||||
$ spack buildcache create <spec>
|
||||
|
||||
|
||||
If you wanted to create a build cache in a local directory, you would provide
|
||||
the ``-d`` argument to target that directory, again also specifying the spec.
|
||||
Here is an example creating a local directory, "spack-cache" and creating
|
||||
build cache files for the "ninja" spec:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ mkdir -p ./spack-cache
|
||||
$ spack buildcache create -d ./spack-cache ninja
|
||||
==> Buildcache files will be output to file:///home/spackuser/spack/spack-cache/build_cache
|
||||
gpgconf: socketdir is '/run/user/1000/gnupg'
|
||||
gpg: using "E6DF6A8BD43208E4D6F392F23777740B7DBD643D" as default secret key for signing
|
||||
|
||||
Note that the targeted spec must already be installed. Once you have a build cache,
|
||||
you can add it as a mirror, discussed next.
|
||||
|
||||
---------------------------------------
|
||||
Finding or installing build cache files
|
||||
---------------------------------------
|
||||
@@ -43,19 +59,98 @@ with:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack mirror add <name> <url>
|
||||
$ spack mirror add <name> <url>
|
||||
|
||||
|
||||
Note that the url can be a web url _or_ a local filesystem location. In the previous
|
||||
example, you might add the directory "spack-cache" and call it ``mymirror``:
|
||||
|
||||
Build caches are found via:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack buildcache list
|
||||
$ spack mirror add mymirror ./spack-cache
|
||||
|
||||
Build caches are installed via:
|
||||
|
||||
You can see that the mirror is added with ``spack mirror list`` as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack buildcache install
|
||||
|
||||
$ spack mirror list
|
||||
mymirror file:///home/spackuser/spack/spack-cache
|
||||
spack-public https://spack-llnl-mirror.s3-us-west-2.amazonaws.com/
|
||||
|
||||
|
||||
At this point, you've create a buildcache, but spack hasn't indexed it, so if
|
||||
you run ``spack buildcache list`` you won't see any results. You need to index
|
||||
this new build cache as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack buildcache update-index -d spack-cache/
|
||||
|
||||
Now you can use list:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack buildcache list
|
||||
==> 1 cached build.
|
||||
-- linux-ubuntu20.04-skylake / gcc@9.3.0 ------------------------
|
||||
ninja@1.10.2
|
||||
|
||||
|
||||
Great! So now let's say you have a different spack installation, or perhaps just
|
||||
a different environment for the same one, and you want to install a package from
|
||||
that build cache. Let's first uninstall the actual library "ninja" to see if we can
|
||||
re-install it from the cache.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack uninstall ninja
|
||||
|
||||
|
||||
And now reinstall from the buildcache
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack buildcache install ninja
|
||||
==> buildcache spec(s) matching ninja
|
||||
==> Fetching file:///home/spackuser/spack/spack-cache/build_cache/linux-ubuntu20.04-skylake/gcc-9.3.0/ninja-1.10.2/linux-ubuntu20.04-skylake-gcc-9.3.0-ninja-1.10.2-i4e5luour7jxdpc3bkiykd4imke3mkym.spack
|
||||
####################################################################################################################################### 100.0%
|
||||
==> Installing buildcache for spec ninja@1.10.2%gcc@9.3.0 arch=linux-ubuntu20.04-skylake
|
||||
gpgconf: socketdir is '/run/user/1000/gnupg'
|
||||
gpg: Signature made Tue 23 Mar 2021 10:16:29 PM MDT
|
||||
gpg: using RSA key E6DF6A8BD43208E4D6F392F23777740B7DBD643D
|
||||
gpg: Good signature from "spackuser (GPG created for Spack) <spackuser@noreply.users.github.com>" [ultimate]
|
||||
|
||||
|
||||
It worked! You've just completed a full example of creating a build cache with
|
||||
a spec of interest, adding it as a mirror, updating it's index, listing the contents,
|
||||
and finally, installing from it.
|
||||
|
||||
|
||||
Note that the above command is intended to install a particular package to a
|
||||
build cache you have created, and not to install a package from a build cache.
|
||||
For the latter, once a mirror is added, by default when you do ``spack install`` the ``--use-cache``
|
||||
flag is set, and you will install a package from a build cache if it is available.
|
||||
If you want to always use the cache, you can do:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack install --cache-only <package>
|
||||
|
||||
For example, to combine all of the commands above to add the E4S build cache
|
||||
and then install from it exclusively, you would do:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack mirror add E4S https://cache.e4s.io
|
||||
$ spack buildcache keys --install --trust
|
||||
$ spack install --cache-only <package>
|
||||
|
||||
We use ``--install`` and ``--trust`` to say that we are installing keys to our
|
||||
keyring, and trusting all downloaded keys.
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
List of popular build caches
|
||||
|
||||
@@ -10,7 +10,7 @@ CudaPackage
|
||||
-----------
|
||||
|
||||
Different from other packages, ``CudaPackage`` does not represent a build system.
|
||||
Instead its goal is to simplify and unify usage of ``CUDA`` in other packages by providing a ` mixin-class <https://en.wikipedia.org/wiki/Mixin>`__.
|
||||
Instead its goal is to simplify and unify usage of ``CUDA`` in other packages by providing a `mixin-class <https://en.wikipedia.org/wiki/Mixin>`_.
|
||||
|
||||
You can find source for the package at
|
||||
`<https://github.com/spack/spack/blob/develop/lib/spack/spack/build_systems/cuda.py>`__.
|
||||
|
||||
@@ -25,7 +25,7 @@ use Spack to build packages with the tools.
|
||||
The Spack Python class ``IntelOneapiPackage`` is a base class that is
|
||||
used by ``IntelOneapiCompilers``, ``IntelOneapiMkl``,
|
||||
``IntelOneapiTbb`` and other classes to implement the oneAPI
|
||||
packages. See the :ref:<package-list> for the full list of available
|
||||
packages. See the :ref:`package-list` for the full list of available
|
||||
oneAPI packages or use::
|
||||
|
||||
spack list -d oneAPI
|
||||
@@ -35,7 +35,7 @@ For more information on a specific package, do::
|
||||
spack info <package-name>
|
||||
|
||||
Intel no longer releases new versions of Parallel Studio, which can be
|
||||
used in Spack via the :ref:<intelpackage>. All of its components can
|
||||
used in Spack via the :ref:`intelpackage`. All of its components can
|
||||
now be found in oneAPI.
|
||||
|
||||
Examples
|
||||
@@ -145,11 +145,11 @@ More information
|
||||
================
|
||||
|
||||
This section describes basic use of oneAPI, especially if it has
|
||||
changed compared to Parallel Studio. See :ref:<intelpackage> for more
|
||||
information on :ref:<intel-virtual-packages>,
|
||||
:ref:<intel-unrelated-packages>,
|
||||
:ref:<intel-integrating-external-libraries>, and
|
||||
:ref:<using-mkl-tips>.
|
||||
changed compared to Parallel Studio. See :ref:`intelpackage` for more
|
||||
information on :ref:`intel-virtual-packages`,
|
||||
:ref:`intel-unrelated-packages`,
|
||||
:ref:`intel-integrating-external-libraries`, and
|
||||
:ref:`using-mkl-tips`.
|
||||
|
||||
|
||||
.. _`Intel installers`: https://software.intel.com/content/www/us/en/develop/documentation/installation-guide-for-intel-oneapi-toolkits-linux/top.html
|
||||
|
||||
@@ -147,8 +147,10 @@ and a ``filter_file`` method to help with this. For example:
|
||||
def edit(self, spec, prefix):
|
||||
makefile = FileFilter('Makefile')
|
||||
|
||||
makefile.filter('CC = gcc', 'CC = cc')
|
||||
makefile.filter('CXX = g++', 'CC = c++')
|
||||
makefile.filter(r'^\s*CC\s*=.*', 'CC = ' + spack_cc)
|
||||
makefile.filter(r'^\s*CXX\s*=.*', 'CXX = ' + spack_cxx)
|
||||
makefile.filter(r'^\s*F77\s*=.*', 'F77 = ' + spack_f77)
|
||||
makefile.filter(r'^\s*FC\s*=.*', 'FC = ' + spack_fc)
|
||||
|
||||
|
||||
`stream <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/stream/package.py>`_
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from glob import glob
|
||||
|
||||
from sphinx.ext.apidoc import main as sphinx_apidoc
|
||||
@@ -82,6 +82,8 @@
|
||||
# Disable duplicate cross-reference warnings.
|
||||
#
|
||||
from sphinx.domains.python import PythonDomain
|
||||
|
||||
|
||||
class PatchedPythonDomain(PythonDomain):
|
||||
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
|
||||
if 'refspecific' in node:
|
||||
@@ -136,6 +138,7 @@ def setup(sphinx):
|
||||
#
|
||||
# The short X.Y version.
|
||||
import spack
|
||||
|
||||
version = '.'.join(str(s) for s in spack.spack_version_info[:2])
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = spack.spack_version
|
||||
@@ -179,7 +182,8 @@ def setup(sphinx):
|
||||
# We use our own extension of the default style with a few modifications
|
||||
from pygments.style import Style
|
||||
from pygments.styles.default import DefaultStyle
|
||||
from pygments.token import Generic, Comment, Text
|
||||
from pygments.token import Comment, Generic, Text
|
||||
|
||||
|
||||
class SpackStyle(DefaultStyle):
|
||||
styles = DefaultStyle.styles.copy()
|
||||
@@ -188,6 +192,7 @@ class SpackStyle(DefaultStyle):
|
||||
styles[Generic.Prompt] = "bold #346ec9"
|
||||
|
||||
import pkg_resources
|
||||
|
||||
dist = pkg_resources.Distribution(__file__)
|
||||
sys.path.append('.') # make 'conf' module findable
|
||||
ep = pkg_resources.EntryPoint.parse('spack = conf:SpackStyle', dist=dist)
|
||||
|
||||
@@ -867,6 +867,50 @@ just like you would with the normal ``python`` command.
|
||||
|
||||
.. _cmd-spack-url:
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^^
|
||||
``spack blame``
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Spack blame is a way to quickly see contributors to packages or files
|
||||
in the spack repository. You should provide a target package name or
|
||||
file name to the command. Here is an example asking to see contributions
|
||||
for the package "python":
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack blame python
|
||||
LAST_COMMIT LINES % AUTHOR EMAIL
|
||||
2 weeks ago 3 0.3 Mickey Mouse <cheddar@gmouse.org>
|
||||
a month ago 927 99.7 Minnie Mouse <swiss@mouse.org>
|
||||
|
||||
2 weeks ago 930 100.0
|
||||
|
||||
|
||||
By default, you will get a table view (shown above) sorted by date of contribution,
|
||||
with the most recent contribution at the top. If you want to sort instead
|
||||
by percentage of code contribution, then add ``-p``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack blame -p python
|
||||
|
||||
|
||||
And to see the git blame view, add ``-g`` instead:
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack blame -g python
|
||||
|
||||
|
||||
Finally, to get a json export of the data, add ``--json``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack blame --json python
|
||||
|
||||
|
||||
^^^^^^^^^^^^^
|
||||
``spack url``
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
@@ -363,7 +363,7 @@ to ``spack install`` on the command line, ``--no-add`` is the default,
|
||||
while for dependency specs on the other hand, it is optional. In other
|
||||
words, if there is an unambiguous match in the active concrete environment
|
||||
for a root spec provided to ``spack install`` on the command line, spack
|
||||
does not require you to specify the ``--no-add` option to prevent the spec
|
||||
does not require you to specify the ``--no-add`` option to prevent the spec
|
||||
from being added again. At the same time, a spec that already exists in the
|
||||
environment, but only as a dependency, will be added to the environment as a
|
||||
root spec without the ``--no-add`` option.
|
||||
@@ -723,6 +723,8 @@ Spack Environment managed views are updated every time the environment
|
||||
is written out to the lock file ``spack.lock``, so the concrete
|
||||
environment and the view are always compatible.
|
||||
|
||||
.. _configuring_environment_views:
|
||||
|
||||
"""""""""""""""""""""""""""""
|
||||
Configuring environment views
|
||||
"""""""""""""""""""""""""""""
|
||||
|
||||
@@ -70,7 +70,13 @@ Sourcing these files will put the ``spack`` command in your ``PATH``, set
|
||||
up your ``MODULEPATH`` to use Spack's packages, and add other useful
|
||||
shell integration for :ref:`certain commands <packaging-shell-support>`,
|
||||
:ref:`environments <environments>`, and :ref:`modules <modules>`. For
|
||||
``bash``, it also sets up tab completion.
|
||||
``bash`` and ``zsh``, it also sets up tab completion.
|
||||
|
||||
In order to know which directory to add to your ``MODULEPATH``, these scripts
|
||||
query the ``spack`` command. On shared filesystems, this can be a bit slow,
|
||||
especially if you log in frequently. If you don't use modules, or want to set
|
||||
``MODULEPATH`` manually instead, you can set the ``SPACK_SKIP_MODULES``
|
||||
environment variable to skip this step and speed up sourcing the file.
|
||||
|
||||
If you do not want to use Spack's shell support, you can always just run
|
||||
the ``spack`` command directly from ``spack/bin/spack``.
|
||||
@@ -1119,6 +1125,33 @@ Secret keys may also be later exported using the
|
||||
<https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged>`_
|
||||
provides a good overview of sources of randomness.
|
||||
|
||||
Here is an example of creating a key. Note that we provide a name for the key first
|
||||
(which we can use to reference the key later) and an email address:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack gpg create dinosaur dinosaur@thedinosaurthings.com
|
||||
|
||||
|
||||
If you want to export the key as you create it:
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack gpg create --export key.pub dinosaur dinosaur@thedinosaurthings.com
|
||||
|
||||
Or the private key:
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack gpg create --export-secret key.priv dinosaur dinosaur@thedinosaurthings.com
|
||||
|
||||
|
||||
You can include both ``--export`` and ``--export-secret``, each with
|
||||
an output file of choice, to export both.
|
||||
|
||||
|
||||
^^^^^^^^^^^^
|
||||
Listing keys
|
||||
^^^^^^^^^^^^
|
||||
@@ -1127,7 +1160,22 @@ In order to list the keys available in the keyring, the
|
||||
``spack gpg list`` command will list trusted keys with the ``--trusted`` flag
|
||||
and keys available for signing using ``--signing``. If you would like to
|
||||
remove keys from your keyring, ``spack gpg untrust <keyid>``. Key IDs can be
|
||||
email addresses, names, or (best) fingerprints.
|
||||
email addresses, names, or (best) fingerprints. Here is an example of listing
|
||||
the key that we just created:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
gpgconf: socketdir is '/run/user/1000/gnupg'
|
||||
/home/spackuser/spack/opt/spack/gpg/pubring.kbx
|
||||
----------------------------------------------------------
|
||||
pub rsa4096 2021-03-25 [SC]
|
||||
60D2685DAB647AD4DB54125961E09BB6F2A0ADCB
|
||||
uid [ultimate] dinosaur (GPG created for Spack) <dinosaur@thedinosaurthings.com>
|
||||
|
||||
|
||||
Note that the name "dinosaur" can be seen under the uid, which is the unique
|
||||
id. We might need this reference if we want to export or otherwise reference the key.
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Signing and Verifying Packages
|
||||
@@ -1142,6 +1190,38 @@ may also be used to create a signed file which contains the contents, but it
|
||||
is not recommended. Signed packages may be verified by using
|
||||
``spack gpg verify <file>``.
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^
|
||||
Exporting Keys
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
You likely might want to export a public key, and that looks like this. Let's
|
||||
use the previous example and ask spack to export the key with uid "dinosaur."
|
||||
We will provide an output location (typically a `*.pub` file) and the name of
|
||||
the key.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack gpg export dinosaur.pub dinosaur
|
||||
|
||||
You can then look at the created file, `dinosaur.pub`, to see the exported key.
|
||||
If you want to include the private key, then just add `--secret`:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack gpg export --secret dinosaur.priv dinosaur
|
||||
|
||||
This will write the private key to the file `dinosaur.priv`.
|
||||
|
||||
.. warning::
|
||||
|
||||
You should be very careful about exporting private keys. You likely would
|
||||
only want to do this in the context of moving your spack installation to
|
||||
a different server, and wanting to preserve keys for a buildcache. If you
|
||||
are unsure about exporting, you can ask your local system administrator
|
||||
or for help on an issue or the Spack slack.
|
||||
|
||||
|
||||
.. _cray-support:
|
||||
|
||||
-------------
|
||||
|
||||
@@ -71,9 +71,24 @@ Module file customization
|
||||
-------------------------
|
||||
|
||||
Module files are generated by post-install hooks after the successful
|
||||
installation of a package. The table below summarizes the essential
|
||||
information associated with the different file formats
|
||||
that can be generated by Spack:
|
||||
installation of a package.
|
||||
|
||||
.. note::
|
||||
|
||||
Spack only generates modulefiles when a package is installed. If
|
||||
you attempt to install a package and it is already installed, Spack
|
||||
will not regenerate modulefiles for the package. This may to
|
||||
inconsistent modulefiles if the Spack module configuration has
|
||||
changed since the package was installed, either by editing a file
|
||||
or changing scopes or environments.
|
||||
|
||||
Later in this section there is a subsection on :ref:`regenerating
|
||||
modules <cmd-spack-module-refresh>` that will allow you to bring
|
||||
your modules to a consistent state.
|
||||
|
||||
The table below summarizes the essential information associated with
|
||||
the different file formats that can be generated by Spack:
|
||||
|
||||
|
||||
+-----------------------------+--------------------+-------------------------------+----------------------------------------------+----------------------+
|
||||
| | **Hook name** | **Default root directory** | **Default template file** | **Compatible tools** |
|
||||
@@ -163,6 +178,46 @@ the installation folder of each package for the presence of a set of subdirector
|
||||
(``bin``, ``man``, ``share/man``, etc.). If any is found its full path is prepended
|
||||
to the environment variables listed below the folder name.
|
||||
|
||||
Spack modules can be configured for multiple module sets. The default
|
||||
module set is named ``default``. All Spack commands which operate on
|
||||
modules default to apply the ``default`` module set, but can be
|
||||
applied to any module set in the configuration. Settings applied at
|
||||
the root of the configuration (e.g. ``modules:enable`` rather than
|
||||
``modules:default:enable``) are applied to the default module set for
|
||||
backwards compatibility.
|
||||
|
||||
"""""""""""""""""""""""""
|
||||
Changing the modules root
|
||||
"""""""""""""""""""""""""
|
||||
|
||||
As shown in the table above, the default module root for ``lmod`` is
|
||||
``$spack/share/spack/lmod`` and the default root for ``tcl`` is
|
||||
``$spack/share/spack/modules``. This can be overridden for any module
|
||||
set by changing the ``roots`` key of the configuration.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
modules:
|
||||
default:
|
||||
roots:
|
||||
tcl: /path/to/install/tcl/modules
|
||||
my_custom_lmod_modules:
|
||||
roots:
|
||||
lmod: /path/to/install/custom/lmod/modules
|
||||
...
|
||||
|
||||
This configuration will create two module sets. The default module set
|
||||
will install its ``tcl`` modules to ``/path/to/install/tcl/modules``
|
||||
(and still install its lmod modules, if any, to the default
|
||||
location). The set ``my_custom_lmod_modules`` will install its lmod
|
||||
modules to ``/path/to/install/custom/lmod/modules`` (and still install
|
||||
its tcl modules, if any, to the default location).
|
||||
|
||||
Obviously, having multiple module sets install modules to the default
|
||||
location could be confusing to users of your modules. In the next
|
||||
section, we will discuss enabling and disabling module types (module
|
||||
file generators) for each module set.
|
||||
|
||||
""""""""""""""""""""
|
||||
Activate other hooks
|
||||
""""""""""""""""""""
|
||||
@@ -178,13 +233,14 @@ to the generator being customized:
|
||||
.. code-block:: yaml
|
||||
|
||||
modules:
|
||||
enable:
|
||||
- tcl
|
||||
- lmod
|
||||
tcl:
|
||||
# contains environment modules specific customizations
|
||||
lmod:
|
||||
# contains lmod specific customizations
|
||||
default:
|
||||
enable:
|
||||
- tcl
|
||||
- lmod
|
||||
tcl:
|
||||
# contains environment modules specific customizations
|
||||
lmod:
|
||||
# contains lmod specific customizations
|
||||
|
||||
In general, the configuration options that you can use in ``modules.yaml`` will
|
||||
either change the layout of the module files on the filesystem, or they will affect
|
||||
@@ -399,10 +455,16 @@ that are already in the LMod hierarchy.
|
||||
Customize environment modifications
|
||||
"""""""""""""""""""""""""""""""""""
|
||||
|
||||
You can control which prefixes in a Spack package are added to environment
|
||||
variables with the ``prefix_inspections`` section; this section maps relative
|
||||
prefixes to the list of environment variables which should be updated with
|
||||
those prefixes.
|
||||
You can control which prefixes in a Spack package are added to
|
||||
environment variables with the ``prefix_inspections`` section; this
|
||||
section maps relative prefixes to the list of environment variables
|
||||
which should be updated with those prefixes.
|
||||
|
||||
The ``prefix_inspections`` configuration is different from other
|
||||
settings in that a ``prefix_inspections`` configuration at the
|
||||
``modules`` level of the configuration file applies to all module
|
||||
sets. This allows users to make general overrides to the default
|
||||
inspections and customize them per-module-set.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
@@ -415,10 +477,66 @@ those prefixes.
|
||||
'':
|
||||
- CMAKE_PREFIX_PATH
|
||||
|
||||
In this case, for a Spack package ``foo`` installed to ``/spack/prefix/foo``,
|
||||
the generated module file for ``foo`` would update ``PATH`` to contain
|
||||
Prefix inspections are only applied if the relative path inside the
|
||||
installation prefix exists. In this case, for a Spack package ``foo``
|
||||
installed to ``/spack/prefix/foo``, if ``foo`` installs executables to
|
||||
``bin`` but no libraries in ``lib``, the generated module file for
|
||||
``foo`` would update ``PATH`` to contain ``/spack/prefix/foo/bin`` and
|
||||
``CMAKE_PREFIX_PATH`` to contain ``/spack/prefix/foo``, but would not
|
||||
update ``LIBRARY_PATH``.
|
||||
|
||||
There is a special case for prefix inspections relative to environment
|
||||
views. If all of the following conditions hold for a module set
|
||||
configuration:
|
||||
|
||||
#. The configuration is for an :ref:`environment <environments>` and
|
||||
will never be applied outside the environment,
|
||||
#. The environment in question is configured to use a :ref:`view
|
||||
<filesystem-views>`,
|
||||
#. The :ref:`environment view is configured
|
||||
<configuring_environment_views>` with a projection that ensures
|
||||
every package is linked to a unique directory,
|
||||
|
||||
then the module set may be configured to create modules relative to
|
||||
the environment view. This is specified by the ``use_view``
|
||||
configuration option in the module set. If ``True``, the module set is
|
||||
constructed relative to the default view of the
|
||||
environment. Otherwise, the value must be the name of the environment
|
||||
view relative to which to construct modules, or ``False-ish`` to
|
||||
disable the feature explicitly (the default is ``False``).
|
||||
|
||||
If the ``use_view`` value is set in the config, then the prefix
|
||||
inspections for the package are done relative to the package's path in
|
||||
the view.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
spack:
|
||||
modules:
|
||||
view_relative_modules:
|
||||
use_view: my_view
|
||||
prefix_inspections:
|
||||
bin:
|
||||
- PATH
|
||||
view:
|
||||
my_view:
|
||||
projections:
|
||||
root: /path/to/my/view
|
||||
all: '{name}-{hash}'
|
||||
|
||||
The ``spack`` key is relevant to :ref:`environment <environments>`
|
||||
configuration, and the view key is discussed in detail in the section
|
||||
on :ref:`Configuring environment views
|
||||
<configuring_environment_views>`. With this configuration the
|
||||
generated module for package ``foo`` would set ``PATH`` to include
|
||||
``/path/to/my/view/foo-<hash>/bin`` instead of
|
||||
``/spack/prefix/foo/bin``.
|
||||
|
||||
The ``use_view`` option is useful when deploying a large software
|
||||
stack to users who are likely to inspect the modules to find full
|
||||
paths to software, when it is desirable to present the users with a
|
||||
simpler set of paths than those generated by the Spack install tree.
|
||||
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
Filter out environment modifications
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
@@ -102,3 +102,164 @@ more tags to your build, you can do:
|
||||
# Add two tags, "pizza" and "pasta"
|
||||
$ spack install --monitor --monitor-tags pizza,pasta hdf5
|
||||
|
||||
|
||||
----------------------------
|
||||
Monitoring with Containerize
|
||||
----------------------------
|
||||
|
||||
The same argument group is available to add to a containerize command.
|
||||
|
||||
^^^^^^
|
||||
Docker
|
||||
^^^^^^
|
||||
|
||||
To add monitoring to a Docker container recipe generation using the defaults,
|
||||
and assuming a monitor server running on localhost, you would
|
||||
start with a spack.yaml in your present working directory:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
spack:
|
||||
specs:
|
||||
- samtools
|
||||
|
||||
And then do:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# preview first
|
||||
spack containerize --monitor
|
||||
|
||||
# and then write to a Dockerfile
|
||||
spack containerize --monitor > Dockerfile
|
||||
|
||||
|
||||
The install command will be edited to include commands for enabling monitoring.
|
||||
However, getting secrets into the container for your monitor server is something
|
||||
that should be done carefully. Specifically you should:
|
||||
|
||||
- Never try to define secrets as ENV, ARG, or using ``--build-arg``
|
||||
- Do not try to get the secret into the container via a "temporary" file that you remove (it in fact will still exist in a layer)
|
||||
|
||||
Instead, it's recommended to use buildkit `as explained here <https://pythonspeed.com/articles/docker-build-secrets/>`_.
|
||||
You'll need to again export environment variables for your spack monitor server:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ export SPACKMON_TOKEN=50445263afd8f67e59bd79bff597836ee6c05438
|
||||
$ export SPACKMON_USER=spacky
|
||||
|
||||
And then use buildkit along with your build and identifying the name of the secret:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ DOCKER_BUILDKIT=1 docker build --secret id=st,env=SPACKMON_TOKEN --secret id=su,env=SPACKMON_USER -t spack/container .
|
||||
|
||||
The secrets are expected to come from your environment, and then will be temporarily mounted and available
|
||||
at ``/run/secrets/<name>``. If you forget to supply them (and authentication is required) the build
|
||||
will fail. If you need to build on your host (and interact with a spack monitor at localhost) you'll
|
||||
need to tell Docker to use the host network:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ DOCKER_BUILDKIT=1 docker build --network="host" --secret id=st,env=SPACKMON_TOKEN --secret id=su,env=SPACKMON_USER -t spack/container .
|
||||
|
||||
|
||||
^^^^^^^^^^^
|
||||
Singularity
|
||||
^^^^^^^^^^^
|
||||
|
||||
To add monitoring to a Singularity container build, the spack.yaml needs to
|
||||
be modified slightly to specify wanting a different format:
|
||||
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
spack:
|
||||
specs:
|
||||
- samtools
|
||||
container:
|
||||
format: singularity
|
||||
|
||||
|
||||
Again, generate the recipe:
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# preview first
|
||||
$ spack containerize --monitor
|
||||
|
||||
# then write to a Singularity recipe
|
||||
$ spack containerize --monitor > Singularity
|
||||
|
||||
|
||||
Singularity doesn't have a direct way to define secrets at build time, so we have
|
||||
to do a bit of a manual command to add a file, source secrets in it, and remove it.
|
||||
Since Singularity doesn't have layers like Docker, deleting a file will truly
|
||||
remove it from the container and history. So let's say we have this file,
|
||||
``secrets.sh``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# secrets.sh
|
||||
export SPACKMON_USER=spack
|
||||
export SPACKMON_TOKEN=50445263afd8f67e59bd79bff597836ee6c05438
|
||||
|
||||
|
||||
We would then generate the Singularity recipe, and add a files section,
|
||||
a source of that file at the start of ``%post``, and **importantly**
|
||||
a removal of the final at the end of that same section.
|
||||
|
||||
.. code-block::
|
||||
|
||||
Bootstrap: docker
|
||||
From: spack/ubuntu-bionic:latest
|
||||
Stage: build
|
||||
|
||||
%files
|
||||
secrets.sh /opt/secrets.sh
|
||||
|
||||
%post
|
||||
. /opt/secrets.sh
|
||||
|
||||
# spack install commands are here
|
||||
...
|
||||
|
||||
# Don't forget to remove here!
|
||||
rm /opt/secrets.sh
|
||||
|
||||
|
||||
You can then build the container as your normally would.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ sudo singularity build container.sif Singularity
|
||||
|
||||
|
||||
------------------
|
||||
Monitoring Offline
|
||||
------------------
|
||||
|
||||
In the case that you want to save monitor results to your filesystem
|
||||
and then upload them later (perhaps you are in an environment where you don't
|
||||
have credentials or it isn't safe to use them) you can use the ``--monitor-save-local``
|
||||
flag.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack install --monitor --monitor-save-local hdf5
|
||||
|
||||
This will save results in a subfolder, "monitor" in your designated spack
|
||||
reports folder, which defaults to ``$HOME/.spack/reports/monitor``. When
|
||||
you are ready to upload them to a spack monitor server:
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack monitor upload ~/.spack/reports/monitor
|
||||
|
||||
|
||||
You can choose the root directory of results as shown above, or a specific
|
||||
subdirectory. The command accepts other arguments to specify configuration
|
||||
for the monitor.
|
||||
|
||||
@@ -920,12 +920,13 @@ For some packages, source code is provided in a Version Control System
|
||||
(VCS) repository rather than in a tarball. Spack can fetch packages
|
||||
from VCS repositories. Currently, Spack supports fetching with `Git
|
||||
<git-fetch_>`_, `Mercurial (hg) <hg-fetch_>`_, `Subversion (svn)
|
||||
<svn-fetch_>`_, and `Go <go-fetch_>`_. In all cases, the destination
|
||||
<svn-fetch_>`_, `CVS (cvs) <cvs-fetch_>`_, and `Go <go-fetch_>`_.
|
||||
In all cases, the destination
|
||||
is the standard stage source path.
|
||||
|
||||
To fetch a package from a source repository, Spack needs to know which
|
||||
VCS to use and where to download from. Much like with ``url``, package
|
||||
authors can specify a class-level ``git``, ``hg``, ``svn``, or ``go``
|
||||
authors can specify a class-level ``git``, ``hg``, ``svn``, ``cvs``, or ``go``
|
||||
attribute containing the correct download location.
|
||||
|
||||
Many packages developed with Git have both a Git repository as well as
|
||||
@@ -1173,6 +1174,55 @@ you can check out a branch or tag by changing the URL. If you want to
|
||||
package multiple branches, simply add a ``svn`` argument to each
|
||||
version directive.
|
||||
|
||||
.. _cvs-fetch:
|
||||
|
||||
^^^
|
||||
CVS
|
||||
^^^
|
||||
|
||||
CVS (Concurrent Versions System) is an old centralized version control
|
||||
system. It is a predecessor of Subversion.
|
||||
|
||||
To fetch with CVS, use the ``cvs``, branch, and ``date`` parameters.
|
||||
The destination directory will be the standard stage source path.
|
||||
|
||||
Fetching the head
|
||||
Simply add a ``cvs`` parameter to the package:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Example(Package):
|
||||
|
||||
cvs = ":pserver:outreach.scidac.gov/cvsroot%module=modulename"
|
||||
|
||||
version('1.1.2.4')
|
||||
|
||||
CVS repository locations are described using an older syntax that
|
||||
is different from today's ubiquitous URL syntax. ``:pserver:``
|
||||
denotes the transport method. CVS servers can host multiple
|
||||
repositories (called "modules") at the same location, and one needs
|
||||
to specify both the server location and the module name to access.
|
||||
Spack combines both into one string using the ``%module=modulename``
|
||||
suffix shown above.
|
||||
|
||||
This download method is untrusted.
|
||||
|
||||
Fetching a date
|
||||
Versions in CVS are commonly specified by date. To fetch a
|
||||
particular branch or date, add a ``branch`` and/or ``date`` argument
|
||||
to the version directive:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
version('2021.4.22', branch='branchname', date='2021-04-22')
|
||||
|
||||
Unfortunately, CVS does not identify repository-wide commits via a
|
||||
revision or hash like Subversion, Git, or Mercurial do. This makes
|
||||
it impossible to specify an exact commit to check out.
|
||||
|
||||
CVS has more features, but since CVS is rarely used these days, Spack
|
||||
does not support all of them.
|
||||
|
||||
.. _go-fetch:
|
||||
|
||||
^^
|
||||
@@ -1207,7 +1257,7 @@ Variants
|
||||
Many software packages can be configured to enable optional
|
||||
features, which often come at the expense of additional dependencies or
|
||||
longer build times. To be flexible enough and support a wide variety of
|
||||
use cases, Spack permits to expose to the end-user the ability to choose
|
||||
use cases, Spack allows you to expose to the end-user the ability to choose
|
||||
which features should be activated in a package at the time it is installed.
|
||||
The mechanism to be employed is the :py:func:`spack.directives.variant` directive.
|
||||
|
||||
@@ -2725,6 +2775,57 @@ packages be built with MVAPICH and GCC.
|
||||
|
||||
See the :ref:`concretization-preferences` section for more details.
|
||||
|
||||
|
||||
.. _group_when_spec:
|
||||
|
||||
----------------------------
|
||||
Common ``when=`` constraints
|
||||
----------------------------
|
||||
|
||||
In case a package needs many directives to share the whole ``when=``
|
||||
argument, or just part of it, Spack allows you to group the common part
|
||||
under a context manager:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Gcc(AutotoolsPackage):
|
||||
|
||||
with when('+nvptx'):
|
||||
depends_on('cuda')
|
||||
conflicts('@:6', msg='NVPTX only supported in gcc 7 and above')
|
||||
conflicts('languages=ada')
|
||||
conflicts('languages=brig')
|
||||
conflicts('languages=go')
|
||||
|
||||
The snippet above is equivalent to the more verbose:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Gcc(AutotoolsPackage):
|
||||
|
||||
depends_on('cuda', when='+nvptx')
|
||||
conflicts('@:6', when='+nvptx', msg='NVPTX only supported in gcc 7 and above')
|
||||
conflicts('languages=ada', when='+nvptx')
|
||||
conflicts('languages=brig', when='+nvptx')
|
||||
conflicts('languages=go', when='+nvptx')
|
||||
|
||||
Constraints stemming from the context are added to what is explicitly present in the
|
||||
``when=`` argument of a directive, so:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with when('+elpa'):
|
||||
depends_on('elpa+openmp', when='+openmp')
|
||||
|
||||
is equivalent to:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
depends_on('elpa+openmp', when='+openmp+elpa')
|
||||
|
||||
Constraints from nested context managers are also added together, but they are rarely
|
||||
needed or recommended.
|
||||
|
||||
.. _install-method:
|
||||
|
||||
------------------
|
||||
@@ -4045,31 +4146,31 @@ other checks.
|
||||
* - Build System Class
|
||||
- Post-Build Phase Method (Runs)
|
||||
- Post-Install Phase Method (Runs)
|
||||
* - `AutotoolsPackage <build_systems/autotoolspackage>`
|
||||
* - :ref:`AutotoolsPackage <autotoolspackage>`
|
||||
- ``check`` (``make test``, ``make check``)
|
||||
- ``installcheck`` (``make installcheck``)
|
||||
* - `CMakePackage <build_systems/cmakepackage>`
|
||||
* - :ref:`CMakePackage <cmakepackage>`
|
||||
- ``check`` (``make check``, ``make test``)
|
||||
- Not applicable
|
||||
* - `MakefilePackage <build_systems/makefilepackage>`
|
||||
* - :ref:`MakefilePackage <makefilepackage>`
|
||||
- ``check`` (``make test``, ``make check``)
|
||||
- ``installcheck`` (``make installcheck``)
|
||||
* - `MesonPackage <build_systems/mesonpackage>`
|
||||
* - :ref:`MesonPackage <mesonpackage>`
|
||||
- ``check`` (``make test``, ``make check``)
|
||||
- Not applicable
|
||||
* - `PerlPackage <build_systems/perlpackage>`
|
||||
* - :ref:`PerlPackage <perlpackage>`
|
||||
- ``check`` (``make test``)
|
||||
- Not applicable
|
||||
* - `PythonPackage <build_systems/pythonpackage>`
|
||||
* - :ref:`PythonPackage <pythonpackage>`
|
||||
- Not applicable
|
||||
- ``test`` (module imports)
|
||||
* - `QMakePackage <build_systems/qmakepackage>`
|
||||
* - :ref:`QMakePackage <qmakepackage>`
|
||||
- ``check`` (``make check``)
|
||||
- Not applicable
|
||||
* - `SConsPackage <build_systems/sconspackage>`
|
||||
* - :ref:`SConsPackage <sconspackage>`
|
||||
- ``build_test`` (must be overridden)
|
||||
- Not applicable
|
||||
* - `SIPPackage <build_systems/sippackage>`
|
||||
* - :ref:`SIPPackage <sippackage>`
|
||||
- Not applicable
|
||||
- ``test`` (module imports)
|
||||
|
||||
@@ -4293,19 +4394,37 @@ can be implemented as shown below.
|
||||
|
||||
In this case, the method copies the associated files from the build
|
||||
stage **after** the software is installed to the package's metadata
|
||||
directory. The result is the following directory and files will be
|
||||
available for use in stand-alone tests:
|
||||
directory. The result is the directory and files will be cached in
|
||||
paths under ``self.install_test_root`` as follows:
|
||||
|
||||
* ``join_path(self.install_test_root, 'tests')`` along with its files and subdirectories
|
||||
* ``join_path(self.install_test_root, 'tests')`` along with its files
|
||||
and subdirectories
|
||||
* ``join_path(self.install_test_root, 'examples', 'foo.c')``
|
||||
* ``join_path(self.install_test_root, 'examples', 'bar.c')``
|
||||
|
||||
These paths are **automatically copied** to the test stage directory
|
||||
where they are available to the package's ``test`` method through the
|
||||
``self.test_suite.current_test_cache_dir`` property. In our example,
|
||||
the method can access the directory and files using the following
|
||||
paths:
|
||||
|
||||
* ``join_path(self.test_suite.current_test_cache_dir, 'tests')``
|
||||
* ``join_path(self.test_suite.current_test_cache_dir, 'examples', 'foo.c')``
|
||||
* ``join_path(self.test_suite.current_test_cache_dir, 'examples', 'bar.c')``
|
||||
|
||||
.. note::
|
||||
|
||||
Library developers will want to build the associated tests under
|
||||
the ``self.test_suite.current_test_cache_dir`` and against their
|
||||
**installed** libraries before running them.
|
||||
|
||||
.. note::
|
||||
|
||||
While source and input files are generally recommended, binaries
|
||||
**may** also be cached by the build process for install testing.
|
||||
Only you, as the package writer or maintainer, know whether these
|
||||
would be appropriate stand-alone tests.
|
||||
would be appropriate for ensuring the installed software continues
|
||||
to work as the underlying system evolves.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -4327,11 +4446,12 @@ Examples include:
|
||||
- expected test output
|
||||
|
||||
These extra files should be added to the ``test`` subdirectory of the
|
||||
package in the Spack repository. Spack will automatically copy any files
|
||||
in that directory to the test staging directory during stand-alone testing.
|
||||
package in the Spack repository.
|
||||
|
||||
The ``test`` method can access those files from the
|
||||
``self.test_suite.current_test_data_dir`` directory.
|
||||
Spack will **automatically copy** the contents of that directory to the
|
||||
test staging directory for stand-alone testing. The ``test`` method can
|
||||
access those files using the ``self.test_suite.current_test_data_dir``
|
||||
property.
|
||||
|
||||
.. _expected_test_output_from_file:
|
||||
|
||||
@@ -4530,13 +4650,17 @@ where each argument has the following meaning:
|
||||
|
||||
The default of ``None`` corresponds to the current directory (``'.'``).
|
||||
|
||||
"""""""""""""""""""""""""""""""""""""""""
|
||||
Accessing package- and test-related files
|
||||
"""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
You may need to access files from one or more locations when writing
|
||||
the tests. This can happen if the software's repository does not
|
||||
stand-alone tests. This can happen if the software's repository does not
|
||||
include test source files or includes files but no way to build the
|
||||
executables using the installed headers and libraries. In these
|
||||
cases, you may need to reference the files relative to one or more
|
||||
root directory and associated package property. These are given in
|
||||
the table below.
|
||||
root directory. The properties containing package- and test-related
|
||||
directory paths are provided in the table below.
|
||||
|
||||
.. list-table:: Directory-to-property mapping
|
||||
:header-rows: 1
|
||||
@@ -4550,10 +4674,16 @@ the table below.
|
||||
* - Package Dependency's Files
|
||||
- ``self.spec['<dependency-package>'].prefix``
|
||||
- ``self.spec['trilinos'].prefix.include``
|
||||
* - Copied Build-time Files
|
||||
* - Test Suite Stage Files
|
||||
- ``self.test_suite.stage``
|
||||
- ``join_path(self.test_suite.stage, 'results.txt')``
|
||||
* - Cached Build-time Files
|
||||
- ``self.install_test_root``
|
||||
- ``join_path(self.install_test_root, 'examples', 'foo.c')``
|
||||
* - Custom Package Files
|
||||
* - Staged Cached Build-time Files
|
||||
- ``self.test_suite.current_test_cache_dir``
|
||||
- ``join_path(self.test_suite.current_test_cache_dir, 'examples', 'foo.c')``
|
||||
* - Staged Custom Package Files
|
||||
- ``self.test_suite.current_test_data_dir``
|
||||
- ``join_path(self.test_suite.current_test_data_dir, 'hello.f90')``
|
||||
|
||||
@@ -4800,10 +4930,10 @@ Filtering functions
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
filter_file(r'^CC\s*=.*', spack_cc, 'Makefile')
|
||||
filter_file(r'^CXX\s*=.*', spack_cxx, 'Makefile')
|
||||
filter_file(r'^F77\s*=.*', spack_f77, 'Makefile')
|
||||
filter_file(r'^FC\s*=.*', spack_fc, 'Makefile')
|
||||
filter_file(r'^\s*CC\s*=.*', 'CC = ' + spack_cc, 'Makefile')
|
||||
filter_file(r'^\s*CXX\s*=.*', 'CXX = ' + spack_cxx, 'Makefile')
|
||||
filter_file(r'^\s*F77\s*=.*', 'F77 = ' + spack_f77, 'Makefile')
|
||||
filter_file(r'^\s*FC\s*=.*', 'FC = ' + spack_fc, 'Makefile')
|
||||
|
||||
#. Replacing ``#!/usr/bin/perl`` with ``#!/usr/bin/env perl`` in ``bib2xhtml``:
|
||||
|
||||
|
||||
@@ -30,52 +30,18 @@ at least one `runner <https://docs.gitlab.com/runner/>`_. Then the basic steps
|
||||
for setting up a build pipeline are as follows:
|
||||
|
||||
#. Create a repository on your gitlab instance
|
||||
#. Add a ``spack.yaml`` at the root containing your pipeline environment (see
|
||||
below for details)
|
||||
#. Add a ``spack.yaml`` at the root containing your pipeline environment
|
||||
#. Add a ``.gitlab-ci.yml`` at the root containing two jobs (one to generate
|
||||
the pipeline dynamically, and one to run the generated jobs), similar to
|
||||
this one:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
stages: [generate, build]
|
||||
|
||||
generate-pipeline:
|
||||
stage: generate
|
||||
tags:
|
||||
- <custom-tag>
|
||||
script:
|
||||
- spack env activate --without-view .
|
||||
- spack ci generate
|
||||
--output-file "${CI_PROJECT_DIR}/jobs_scratch_dir/pipeline.yml"
|
||||
artifacts:
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/jobs_scratch_dir/pipeline.yml"
|
||||
|
||||
build-jobs:
|
||||
stage: build
|
||||
trigger:
|
||||
include:
|
||||
- artifact: "jobs_scratch_dir/pipeline.yml"
|
||||
job: generate-pipeline
|
||||
strategy: depend
|
||||
|
||||
|
||||
#. Add any secrets required by the CI process to environment variables using the
|
||||
CI web ui
|
||||
the pipeline dynamically, and one to run the generated jobs).
|
||||
#. Push a commit containing the ``spack.yaml`` and ``.gitlab-ci.yml`` mentioned above
|
||||
to the gitlab repository
|
||||
|
||||
The ``<custom-tag>``, above, is used to pick one of your configured runners to
|
||||
run the pipeline generation phase (this is implemented in the ``spack ci generate``
|
||||
command, which assumes the runner has an appropriate version of spack installed
|
||||
and configured for use). Of course, there are many ways to customize the process.
|
||||
You can configure CDash reporting on the progress of your builds, set up S3 buckets
|
||||
to mirror binaries built by the pipeline, clone a custom spack repository/ref for
|
||||
use by the pipeline, and more.
|
||||
See the :ref:`functional_example` section for a minimal working example. See also
|
||||
the :ref:`custom_Workflow` section for a link to an example of a custom workflow
|
||||
based on spack pipelines.
|
||||
|
||||
While it is possible to set up pipelines on gitlab.com, the builds there are
|
||||
limited to 60 minutes and generic hardware. It is also possible to
|
||||
While it is possible to set up pipelines on gitlab.com, as illustrated above, the
|
||||
builds there are limited to 60 minutes and generic hardware. It is also possible to
|
||||
`hook up <https://about.gitlab.com/blog/2018/04/24/getting-started-gitlab-ci-gcp>`_
|
||||
Gitlab to Google Kubernetes Engine (`GKE <https://cloud.google.com/kubernetes-engine/>`_)
|
||||
or Amazon Elastic Kubernetes Service (`EKS <https://aws.amazon.com/eks>`_), though those
|
||||
@@ -88,21 +54,144 @@ dynamically generated
|
||||
Note that the use of dynamic child pipelines requires running Gitlab version
|
||||
``>= 12.9``.
|
||||
|
||||
.. _functional_example:
|
||||
|
||||
------------------
|
||||
Functional Example
|
||||
------------------
|
||||
|
||||
The simplest fully functional standalone example of a working pipeline can be
|
||||
examined live at this example `project <https://gitlab.com/scott.wittenburg/spack-pipeline-demo>`_
|
||||
on gitlab.com.
|
||||
|
||||
Here's the ``.gitlab-ci.yml`` file from that example that builds and runs the
|
||||
pipeline:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
stages: [generate, build]
|
||||
|
||||
variables:
|
||||
SPACK_REPO: https://github.com/scottwittenburg/spack.git
|
||||
SPACK_REF: pipelines-reproducible-builds
|
||||
|
||||
generate-pipeline:
|
||||
stage: generate
|
||||
tags:
|
||||
- docker
|
||||
image:
|
||||
name: ghcr.io/scottwittenburg/ecpe4s-ubuntu18.04-runner-x86_64:2020-09-01
|
||||
entrypoint: [""]
|
||||
before_script:
|
||||
- git clone ${SPACK_REPO}
|
||||
- pushd spack && git checkout ${SPACK_REF} && popd
|
||||
- . "./spack/share/spack/setup-env.sh"
|
||||
script:
|
||||
- spack env activate --without-view .
|
||||
- spack -d ci generate
|
||||
--artifacts-root "${CI_PROJECT_DIR}/jobs_scratch_dir"
|
||||
--output-file "${CI_PROJECT_DIR}/jobs_scratch_dir/pipeline.yml"
|
||||
artifacts:
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/jobs_scratch_dir"
|
||||
|
||||
build-jobs:
|
||||
stage: build
|
||||
trigger:
|
||||
include:
|
||||
- artifact: "jobs_scratch_dir/pipeline.yml"
|
||||
job: generate-pipeline
|
||||
strategy: depend
|
||||
|
||||
The key thing to note above is that there are two jobs: The first job to run,
|
||||
``generate-pipeline``, runs the ``spack ci generate`` command to generate a
|
||||
dynamic child pipeline and write it to a yaml file, which is then picked up
|
||||
by the second job, ``build-jobs``, and used to trigger the downstream pipeline.
|
||||
|
||||
And here's the spack environment built by the pipeline represented as a
|
||||
``spack.yaml`` file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
spack:
|
||||
view: false
|
||||
concretization: separately
|
||||
|
||||
definitions:
|
||||
- pkgs:
|
||||
- zlib
|
||||
- bzip2
|
||||
- arch:
|
||||
- '%gcc@7.5.0 arch=linux-ubuntu18.04-x86_64'
|
||||
|
||||
specs:
|
||||
- matrix:
|
||||
- - $pkgs
|
||||
- - $arch
|
||||
|
||||
mirrors: { "mirror": "s3://spack-public/mirror" }
|
||||
|
||||
gitlab-ci:
|
||||
before_script:
|
||||
- git clone ${SPACK_REPO}
|
||||
- pushd spack && git checkout ${SPACK_CHECKOUT_VERSION} && popd
|
||||
- . "./spack/share/spack/setup-env.sh"
|
||||
script:
|
||||
- pushd ${SPACK_CONCRETE_ENV_DIR} && spack env activate --without-view . && popd
|
||||
- spack -d ci rebuild
|
||||
mappings:
|
||||
- match: ["os=ubuntu18.04"]
|
||||
runner-attributes:
|
||||
image:
|
||||
name: ghcr.io/scottwittenburg/ecpe4s-ubuntu18.04-runner-x86_64:2020-09-01
|
||||
entrypoint: [""]
|
||||
tags:
|
||||
- docker
|
||||
enable-artifacts-buildcache: True
|
||||
rebuild-index: False
|
||||
|
||||
The elements of this file important to spack ci pipelines are described in more
|
||||
detail below, but there are a couple of things to note about the above working
|
||||
example:
|
||||
|
||||
Normally ``enable-artifacts-buildcache`` is not recommended in production as it
|
||||
results in large binary artifacts getting transferred back and forth between
|
||||
gitlab and the runners. But in this example on gitlab.com where there is no
|
||||
shared, persistent file system, and where no secrets are stored for giving
|
||||
permission to write to an S3 bucket, ``enabled-buildcache-artifacts`` is the only
|
||||
way to propagate binaries from jobs to their dependents.
|
||||
|
||||
Also, it is usually a good idea to let the pipeline generate a final "rebuild the
|
||||
buildcache index" job, so that subsequent pipeline generation can quickly determine
|
||||
which specs are up to date and which need to be rebuilt (it's a good idea for other
|
||||
reasons as well, but those are out of scope for this discussion). In this case we
|
||||
have disabled it (using ``rebuild-index: False``) because the index would only be
|
||||
generated in the artifacts mirror anyway, and consequently would not be available
|
||||
during subesequent pipeline runs.
|
||||
|
||||
.. note::
|
||||
With the addition of reproducible builds (#22887) a previously working
|
||||
pipeline will require some changes:
|
||||
|
||||
* In the build jobs (``runner-attributes``), the environment location changed.
|
||||
This will typically show as a ``KeyError`` in the failing job. Be sure to
|
||||
point to ``${SPACK_CONCRETE_ENV_DIR}``.
|
||||
|
||||
* When using ``include`` in your environment, be sure to make the included
|
||||
files available in the build jobs. This means adding those files to the
|
||||
artifact directory. Those files will also be missing in the reproducibility
|
||||
artifact.
|
||||
|
||||
* Because the location of the environment changed, including files with
|
||||
relative path may have to be adapted to work both in the project context
|
||||
(generation job) and in the concrete env dir context (build job).
|
||||
|
||||
-----------------------------------
|
||||
Spack commands supporting pipelines
|
||||
-----------------------------------
|
||||
|
||||
Spack provides a command ``ci`` with two sub-commands: ``spack ci generate`` generates
|
||||
a pipeline (a .gitlab-ci.yml file) from a spack environment, and ``spack ci rebuild``
|
||||
checks a spec against a remote mirror and possibly rebuilds it from source and updates
|
||||
the binary mirror with the latest built package. Both ``spack ci ...`` commands must
|
||||
be run from within the same environment, as each one makes use of the environment for
|
||||
different purposes. Additionally, some options to the commands (or conditions present
|
||||
in the spack environment file) may require particular environment variables to be
|
||||
set in order to function properly. Examples of these are typically secrets
|
||||
needed for pipeline operation that should not be visible in a spack environment
|
||||
file. These environment variables are described in more detail
|
||||
:ref:`ci_environment_variables`.
|
||||
Spack provides a ``ci`` command with a few sub-commands supporting spack
|
||||
ci pipelines. These commands are covered in more detail in this section.
|
||||
|
||||
.. _cmd-spack-ci:
|
||||
|
||||
@@ -121,6 +210,17 @@ pipeline jobs.
|
||||
|
||||
Concretizes the specs in the active environment, stages them (as described in
|
||||
:ref:`staging_algorithm`), and writes the resulting ``.gitlab-ci.yml`` to disk.
|
||||
During concretization of the environment, ``spack ci generate`` also writes a
|
||||
``spack.lock`` file which is then provided to generated child jobs and made
|
||||
available in all generated job artifacts to aid in reproducing failed builds
|
||||
in a local environment. This means there are two artifacts that need to be
|
||||
exported in your pipeline generation job (defined in your ``.gitlab-ci.yml``).
|
||||
The first is the output yaml file of ``spack ci generate``, and the other is
|
||||
the directory containing the concrete environment files. In the
|
||||
:ref:`functional_example` section, we only mentioned one path in the
|
||||
``artifacts`` ``paths`` list because we used ``--artifacts-root`` as the
|
||||
top level directory containing both the generated pipeline yaml and the
|
||||
concrete environment.
|
||||
|
||||
Using ``--prune-dag`` or ``--no-prune-dag`` configures whether or not jobs are
|
||||
generated for specs that are already up to date on the mirror. If enabling
|
||||
@@ -128,6 +228,16 @@ DAG pruning using ``--prune-dag``, more information may be required in your
|
||||
``spack.yaml`` file, see the :ref:`noop_jobs` section below regarding
|
||||
``service-job-attributes``.
|
||||
|
||||
The optional ``--check-index-only`` argument can be used to speed up pipeline
|
||||
generation by telling spack to consider only remote buildcache indices when
|
||||
checking the remote mirror to determine if each spec in the DAG is up to date
|
||||
or not. The default behavior is for spack to fetch the index and check it,
|
||||
but if the spec is not found in the index, to also perform a direct check for
|
||||
the spec on the mirror. If the remote buildcache index is out of date, which
|
||||
can easily happen if it is not updated frequently, this behavior ensures that
|
||||
spack has a way to know for certain about the status of any concrete spec on
|
||||
the remote mirror, but can slow down pipeline generation significantly.
|
||||
|
||||
The ``--optimize`` argument is experimental and runs the generated pipeline
|
||||
document through a series of optimization passes designed to reduce the size
|
||||
of the generated file.
|
||||
@@ -143,19 +253,64 @@ The optional ``--output-file`` argument should be an absolute path (including
|
||||
file name) to the generated pipeline, and if not given, the default is
|
||||
``./.gitlab-ci.yml``.
|
||||
|
||||
While optional, the ``--artifacts-root`` argument is used to determine where
|
||||
the concretized environment directory should be located. This directory will
|
||||
be created by ``spack ci generate`` and will contain the ``spack.yaml`` and
|
||||
generated ``spack.lock`` which are then passed to all child jobs as an
|
||||
artifact. This directory will also be the root directory for all artifacts
|
||||
generated by jobs in the pipeline.
|
||||
|
||||
.. _cmd-spack-ci-rebuild:
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
``spack ci rebuild``
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This sub-command is responsible for ensuring a single spec from the release
|
||||
environment is up to date on the remote mirror configured in the environment,
|
||||
and as such, corresponds to a single job in the ``.gitlab-ci.yml`` file.
|
||||
The purpose of the ``spack ci rebuild`` is straightforward: take its assigned
|
||||
spec job, check whether the target mirror already has a binary for that spec,
|
||||
and if not, build the spec from source and push the binary to the mirror. To
|
||||
accomplish this in a reproducible way, the sub-command prepares a ``spack install``
|
||||
command line to build a single spec in the DAG, saves that command in a
|
||||
shell script, ``install.sh``, in the current working directory, and then runs
|
||||
it to install the spec. The shell script is also exported as an artifact to
|
||||
aid in reproducing the build outside of the CI environment.
|
||||
|
||||
Rather than taking command-line arguments, this sub-command expects information
|
||||
to be communicated via environment variables, which will typically come via the
|
||||
``.gitlab-ci.yml`` job as ``variables``.
|
||||
If it was necessary to install the spec from source, ``spack ci rebuild`` will
|
||||
also subsequently create a binary package for the spec and try to push it to the
|
||||
mirror.
|
||||
|
||||
The ``spack ci rebuild`` sub-command mainly expects its "input" to come either
|
||||
from environment variables or from the ``gitlab-ci`` section of the ``spack.yaml``
|
||||
environment file. There are two main sources of the environment variables, some
|
||||
are written into ``.gitlab-ci.yml`` by ``spack ci generate``, and some are
|
||||
provided by the GitLab CI runtime.
|
||||
|
||||
.. _cmd-spack-ci-rebuild-index:
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
``spack ci rebuild-index``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This is a convenience command to rebuild the buildcache index associated with
|
||||
the mirror in the active, gitlab-enabled environment (specifying the mirror
|
||||
url or name is not required).
|
||||
|
||||
.. _cmd-spack-ci-reproduce-build:
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
``spack ci reproduce-build``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Given the url to a gitlab pipeline rebuild job, downloads and unzips the
|
||||
artifacts into a local directory (which can be specified with the optional
|
||||
``--working-dir`` argument), then finds the target job in the generated
|
||||
pipeline to extract details about how it was run. Assuming the job used a
|
||||
docker image, the command prints a ``docker run`` command line and some basic
|
||||
instructions on how to reproduce the build locally.
|
||||
|
||||
Note that jobs failing in the pipeline will print messages giving the
|
||||
arguments you can pass to ``spack ci reproduce-build`` in order to reproduce
|
||||
a particular build locally.
|
||||
|
||||
------------------------------------
|
||||
A pipeline-enabled spack environment
|
||||
@@ -364,8 +519,9 @@ scheduled on that runner. This allows users to do any custom preparation or
|
||||
cleanup tasks that fit their particular workflow, as well as completely
|
||||
customize the rebuilding of a spec if they so choose. Spack will not generate
|
||||
a ``before_script`` or ``after_script`` for jobs, but if you do not provide
|
||||
a custom ``script``, spack will generate one for you that assumes your
|
||||
``spack.yaml`` is at the root of the repository, activates that environment for
|
||||
a custom ``script``, spack will generate one for you that assumes the concrete
|
||||
environment directory is located within your ``--artifacts_root`` (or if not
|
||||
provided, within your ``$CI_PROJECT_DIR``), activates that environment for
|
||||
you, and invokes ``spack ci rebuild``.
|
||||
|
||||
.. _staging_algorithm:
|
||||
@@ -490,14 +646,15 @@ Using a custom spack in your pipeline
|
||||
If your runners will not have a version of spack ready to invoke, or if for some
|
||||
other reason you want to use a custom version of spack to run your pipelines,
|
||||
this section provides an example of how you could take advantage of
|
||||
user-provided pipeline scripts to accomplish this fairly simply. First, you
|
||||
could use the GitLab user interface to create CI environment variables
|
||||
containing the url and branch or tag you want to use (calling them, for
|
||||
example, ``SPACK_REPO`` and ``SPACK_REF``), then refer to those in a custom shell
|
||||
script invoked both from your pipeline generation job, as well as in your rebuild
|
||||
user-provided pipeline scripts to accomplish this fairly simply. First, consider
|
||||
specifying the source and version of spack you want to use with variables, either
|
||||
written directly into your ``.gitlab-ci.yml``, or provided by CI variables defined
|
||||
in the gitlab UI or from some upstream pipeline. Let's say you choose the variable
|
||||
names ``SPACK_REPO`` and ``SPACK_REF`` to refer to the particular fork of spack
|
||||
and branch you want for running your pipeline. You can then refer to those in a
|
||||
custom shell script invoked both from your pipeline generation job and your rebuild
|
||||
jobs. Here's the ``generate-pipeline`` job from the top of this document,
|
||||
updated to invoke a custom shell script that will clone and source a custom
|
||||
spack:
|
||||
updated to clone and source a custom spack:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
@@ -505,34 +662,24 @@ spack:
|
||||
tags:
|
||||
- <some-other-tag>
|
||||
before_script:
|
||||
- ./cloneSpack.sh
|
||||
- git clone ${SPACK_REPO}
|
||||
- pushd spack && git checkout ${SPACK_REF} && popd
|
||||
- . "./spack/share/spack/setup-env.sh"
|
||||
script:
|
||||
- spack env activate --without-view .
|
||||
- spack ci generate
|
||||
- spack ci generate --check-index-only
|
||||
--artifacts-root "${CI_PROJECT_DIR}/jobs_scratch_dir"
|
||||
--output-file "${CI_PROJECT_DIR}/jobs_scratch_dir/pipeline.yml"
|
||||
after_script:
|
||||
- rm -rf ./spack
|
||||
artifacts:
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/jobs_scratch_dir/pipeline.yml"
|
||||
- "${CI_PROJECT_DIR}/jobs_scratch_dir"
|
||||
|
||||
And the ``cloneSpack.sh`` script could contain:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
git clone ${SPACK_REPO}
|
||||
pushd ./spack
|
||||
git checkout ${SPACK_REF}
|
||||
popd
|
||||
|
||||
. "./spack/share/spack/setup-env.sh"
|
||||
|
||||
spack --version
|
||||
|
||||
Finally, you would also want your generated rebuild jobs to clone that version
|
||||
of spack, so you would update your ``spack.yaml`` from above as follows:
|
||||
That takes care of getting the desired version of spack when your pipeline is
|
||||
generated by ``spack ci generate``. You also want your generated rebuild jobs
|
||||
(all of them) to clone that version of spack, so next you would update your
|
||||
``spack.yaml`` from above as follows:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
@@ -547,17 +694,17 @@ of spack, so you would update your ``spack.yaml`` from above as follows:
|
||||
- spack-kube
|
||||
image: spack/ubuntu-bionic
|
||||
before_script:
|
||||
- ./cloneSpack.sh
|
||||
- git clone ${SPACK_REPO}
|
||||
- pushd spack && git checkout ${SPACK_REF} && popd
|
||||
- . "./spack/share/spack/setup-env.sh"
|
||||
script:
|
||||
- spack env activate --without-view .
|
||||
- spack env activate --without-view ${SPACK_CONCRETE_ENV_DIR}
|
||||
- spack -d ci rebuild
|
||||
after_script:
|
||||
- rm -rf ./spack
|
||||
|
||||
Now all of the generated rebuild jobs will use the same shell script to clone
|
||||
spack before running their actual workload. Note in the above example the
|
||||
provision of a custom ``script`` section. The reason for this is to run
|
||||
``spack ci rebuild`` in debug mode to get more information when builds fail.
|
||||
spack before running their actual workload.
|
||||
|
||||
Now imagine you have long pipelines with many specs to be built, and you
|
||||
are pointing to a spack repository and branch that has a tendency to change
|
||||
@@ -571,13 +718,32 @@ simply contains the human-readable value produced by ``spack -V`` at pipeline
|
||||
generation time, the ``SPACK_CHECKOUT_VERSION`` variable can be used in a
|
||||
``git checkout`` command to make sure all child jobs checkout the same version
|
||||
of spack used to generate the pipeline. To take advantage of this, you could
|
||||
simply replace ``git checkout ${SPACK_REF}`` in the example ``cloneSpack.sh``
|
||||
script above with ``git checkout ${SPACK_CHECKOUT_VERSION}``.
|
||||
simply replace ``git checkout ${SPACK_REF}`` in the example ``spack.yaml``
|
||||
above with ``git checkout ${SPACK_CHECKOUT_VERSION}``.
|
||||
|
||||
On the other hand, if you're pointing to a spack repository and branch under your
|
||||
control, there may be no benefit in using the captured ``SPACK_CHECKOUT_VERSION``,
|
||||
and you can instead just clone using the project CI variables you set (in the
|
||||
earlier example these were ``SPACK_REPO`` and ``SPACK_REF``).
|
||||
and you can instead just clone using the variables you define (``SPACK_REPO``
|
||||
and ``SPACK_REF`` in the example aboves).
|
||||
|
||||
.. _custom_workflow:
|
||||
|
||||
---------------
|
||||
Custom Workflow
|
||||
---------------
|
||||
|
||||
There are many ways to take advantage of spack CI pipelines to achieve custom
|
||||
workflows for building packages or other resources. One example of a custom
|
||||
pipelines workflow is the spack tutorial container
|
||||
`repo <https://github.com/spack/spack-tutorial-container>`_. This project uses
|
||||
GitHub (for source control), GitLab (for automated spack ci pipelines), and
|
||||
DockerHub automated builds to build Docker images (complete with fully populate
|
||||
binary mirror) used by instructors and participants of a spack tutorial.
|
||||
|
||||
Take a look a the repo to see how it is accomplished using spack CI pipelines,
|
||||
and see the following markdown files at the root of the repository for
|
||||
descriptions and documentation describing the workflow: ``DESCRIPTION.md``,
|
||||
``DOCKERHUB_SETUP.md``, ``GITLAB_SETUP.md``, and ``UPDATING.md``.
|
||||
|
||||
.. _ci_environment_variables:
|
||||
|
||||
@@ -594,28 +760,33 @@ environment variables used by the pipeline infrastructure are described here.
|
||||
AWS_ACCESS_KEY_ID
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Needed when binary mirror is an S3 bucket.
|
||||
Optional. Only needed when binary mirror is an S3 bucket.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
AWS_SECRET_ACCESS_KEY
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Needed when binary mirror is an S3 bucket.
|
||||
Optional. Only needed when binary mirror is an S3 bucket.
|
||||
|
||||
^^^^^^^^^^^^^^^
|
||||
S3_ENDPOINT_URL
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Needed when binary mirror is an S3 bucket that is *not* on AWS.
|
||||
Optional. Only needed when binary mirror is an S3 bucket that is *not* on AWS.
|
||||
|
||||
^^^^^^^^^^^^^^^^^
|
||||
CDASH_AUTH_TOKEN
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Needed in order to report build groups to CDash.
|
||||
Optional. Only needed in order to report build groups to CDash.
|
||||
|
||||
^^^^^^^^^^^^^^^^^
|
||||
SPACK_SIGNING_KEY
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Needed to sign/verify binary packages from the remote binary mirror.
|
||||
Optional. Only needed if you want ``spack ci rebuild`` to trust the key you
|
||||
store in this variable, in which case, it will subsequently be used to sign and
|
||||
verify binary packages (when installing or creating buildcaches). You could
|
||||
also have already trusted a key spack know about, or if no key is present anywhere,
|
||||
spack will install specs using ``--no-check-signature`` and create buildcaches
|
||||
using ``-u`` (for unsigned binaries).
|
||||
|
||||
@@ -543,7 +543,8 @@ specified from the command line using the ``--projection-file`` option
|
||||
to the ``spack view`` command.
|
||||
|
||||
The projections configuration file is a mapping of partial specs to
|
||||
spec format strings, as shown in the example below.
|
||||
spec format strings, defined by the :meth:`~spack.spec.Spec.format`
|
||||
function, as shown in the example below.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
2
lib/spack/external/__init__.py
vendored
2
lib/spack/external/__init__.py
vendored
@@ -11,7 +11,7 @@
|
||||
|
||||
* Homepage: https://pypi.python.org/pypi/archspec
|
||||
* Usage: Labeling, comparison and detection of microarchitectures
|
||||
* Version: 0.1.2 (commit 130607c373fd88cd3c43da94c0d3afd3a44084b0)
|
||||
* Version: 0.1.2 (commit 26dec9d47e509daf8c970de4c89da200da52ad20)
|
||||
|
||||
argparse
|
||||
--------
|
||||
|
||||
@@ -1725,6 +1725,12 @@
|
||||
"versions": ":",
|
||||
"flags": "-march=armv8-a -mtune=generic"
|
||||
}
|
||||
],
|
||||
"arm": [
|
||||
{
|
||||
"versions": ":",
|
||||
"flags": "-march=armv8-a -mtune=generic"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -1828,6 +1834,12 @@
|
||||
"versions": "5:",
|
||||
"flags": "-march=armv8.2-a+crc+crypto+fp16+sve"
|
||||
}
|
||||
],
|
||||
"arm": [
|
||||
{
|
||||
"versions": "20:",
|
||||
"flags": "-march=armv8.2-a+crc+crypto+fp16+sve"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import re
|
||||
import argparse
|
||||
import errno
|
||||
import re
|
||||
import sys
|
||||
|
||||
from six import StringIO
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import collections
|
||||
import errno
|
||||
import hashlib
|
||||
import glob
|
||||
import grp
|
||||
import hashlib
|
||||
import itertools
|
||||
import numbers
|
||||
import os
|
||||
@@ -19,10 +19,11 @@
|
||||
from contextlib import contextmanager
|
||||
|
||||
import six
|
||||
|
||||
from llnl.util import tty
|
||||
from llnl.util.lang import dedupe, memoized
|
||||
from spack.util.executable import Executable
|
||||
|
||||
from spack.util.executable import Executable
|
||||
|
||||
if sys.version_info >= (3, 3):
|
||||
from collections.abc import Sequence # novm
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
import functools
|
||||
import inspect
|
||||
from datetime import datetime, timedelta
|
||||
from six import string_types
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from six import string_types
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
from itertools import izip_longest # novm
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import filecmp
|
||||
import os
|
||||
import shutil
|
||||
import filecmp
|
||||
|
||||
from llnl.util.filesystem import traverse_tree, mkdirp, touch
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import mkdirp, touch, traverse_tree
|
||||
|
||||
__all__ = ['LinkTree']
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import os
|
||||
import fcntl
|
||||
import errno
|
||||
import time
|
||||
import fcntl
|
||||
import os
|
||||
import socket
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import llnl.util.tty as tty
|
||||
import spack.util.string
|
||||
|
||||
import spack.util.string
|
||||
|
||||
__all__ = ['Lock', 'LockTransaction', 'WriteTransaction', 'ReadTransaction',
|
||||
'LockError', 'LockTimeoutError',
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
import termios
|
||||
import textwrap
|
||||
import traceback
|
||||
import six
|
||||
from datetime import datetime
|
||||
|
||||
import six
|
||||
from six import StringIO
|
||||
from six.moves import input
|
||||
|
||||
from llnl.util.tty.color import cprint, cwrite, cescape, clen
|
||||
from llnl.util.tty.color import cescape, clen, cprint, cwrite
|
||||
|
||||
# Globals
|
||||
_debug = 0
|
||||
|
||||
@@ -10,10 +10,11 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from six import StringIO, text_type
|
||||
|
||||
from llnl.util.tty import terminal_size
|
||||
from llnl.util.tty.color import clen, cextra
|
||||
from llnl.util.tty.color import cextra, clen
|
||||
|
||||
|
||||
class ColumnConfig:
|
||||
|
||||
@@ -60,9 +60,9 @@
|
||||
To output an @, use '@@'. To output a } inside braces, use '}}'.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
import six
|
||||
|
||||
@@ -13,15 +13,14 @@
|
||||
import os
|
||||
import re
|
||||
import select
|
||||
import signal
|
||||
import sys
|
||||
import traceback
|
||||
import signal
|
||||
from contextlib import contextmanager
|
||||
from six import string_types
|
||||
from six import StringIO
|
||||
|
||||
from typing import Optional # novm
|
||||
from types import ModuleType # novm
|
||||
from typing import Optional # novm
|
||||
|
||||
from six import StringIO, string_types
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
@@ -771,28 +770,39 @@ def _writer_daemon(stdin_multiprocess_fd, read_multiprocess_fd, write_fd, echo,
|
||||
raise
|
||||
|
||||
if in_pipe in rlist:
|
||||
# Handle output from the calling process.
|
||||
line = _retry(in_pipe.readline)()
|
||||
if not line:
|
||||
break
|
||||
line_count = 0
|
||||
try:
|
||||
while line_count < 100:
|
||||
# Handle output from the calling process.
|
||||
line = _retry(in_pipe.readline)()
|
||||
if not line:
|
||||
return
|
||||
line_count += 1
|
||||
|
||||
# find control characters and strip them.
|
||||
controls = control.findall(line)
|
||||
line = control.sub('', line)
|
||||
# find control characters and strip them.
|
||||
clean_line, num_controls = control.subn('', line)
|
||||
|
||||
# Echo to stdout if requested or forced.
|
||||
if echo or force_echo:
|
||||
sys.stdout.write(line)
|
||||
sys.stdout.flush()
|
||||
# Echo to stdout if requested or forced.
|
||||
if echo or force_echo:
|
||||
sys.stdout.write(clean_line)
|
||||
|
||||
# Stripped output to log file.
|
||||
log_file.write(_strip(line))
|
||||
log_file.flush()
|
||||
# Stripped output to log file.
|
||||
log_file.write(_strip(clean_line))
|
||||
|
||||
if xon in controls:
|
||||
force_echo = True
|
||||
if xoff in controls:
|
||||
force_echo = False
|
||||
if num_controls > 0:
|
||||
controls = control.findall(line)
|
||||
if xon in controls:
|
||||
force_echo = True
|
||||
if xoff in controls:
|
||||
force_echo = False
|
||||
|
||||
if not _input_available(in_pipe):
|
||||
break
|
||||
finally:
|
||||
if line_count > 0:
|
||||
if echo or force_echo:
|
||||
sys.stdout.flush()
|
||||
log_file.flush()
|
||||
|
||||
except BaseException:
|
||||
tty.error("Exception occurred in writer daemon!")
|
||||
@@ -844,3 +854,7 @@ def wrapped(*args, **kwargs):
|
||||
continue
|
||||
raise
|
||||
return wrapped
|
||||
|
||||
|
||||
def _input_available(f):
|
||||
return f in select.select([f], [], [], 0)[0]
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import signal
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import sys
|
||||
import termios
|
||||
import time
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
from llnl.util.lang import memoized
|
||||
|
||||
import spack.spec
|
||||
from spack.compilers.clang import Clang
|
||||
from spack.spec import CompilerSpec
|
||||
from spack.util.executable import Executable, ProcessError
|
||||
from spack.compilers.clang import Clang
|
||||
|
||||
|
||||
class ABI(object):
|
||||
|
||||
@@ -10,11 +10,10 @@
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import spack.util.classes
|
||||
import spack.paths
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.paths
|
||||
import spack.util.classes
|
||||
|
||||
mod_path = spack.paths.analyzers_path
|
||||
analyzers = spack.util.classes.list_classes("spack.analyzers", mod_path)
|
||||
|
||||
@@ -7,14 +7,15 @@
|
||||
and (optionally) interact with a Spack Monitor
|
||||
"""
|
||||
|
||||
import spack.monitor
|
||||
import spack.hooks
|
||||
import llnl.util.tty as tty
|
||||
import spack.util.path
|
||||
import spack.config
|
||||
|
||||
import os
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.config
|
||||
import spack.hooks
|
||||
import spack.monitor
|
||||
import spack.util.path
|
||||
|
||||
|
||||
def get_analyzer_dir(spec, analyzer_dir=None):
|
||||
"""
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
directory."""
|
||||
|
||||
|
||||
import spack.monitor
|
||||
from .analyzer_base import AnalyzerBase
|
||||
|
||||
import os
|
||||
|
||||
import spack.monitor
|
||||
|
||||
from .analyzer_base import AnalyzerBase
|
||||
|
||||
|
||||
class ConfigArgs(AnalyzerBase):
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
an index of key, value pairs for environment variables."""
|
||||
|
||||
|
||||
from .analyzer_base import AnalyzerBase
|
||||
import os
|
||||
|
||||
from spack.util.environment import EnvironmentModifications
|
||||
|
||||
|
||||
import os
|
||||
from .analyzer_base import AnalyzerBase
|
||||
|
||||
|
||||
class EnvironmentVariables(AnalyzerBase):
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
analyzer folder for further processing."""
|
||||
|
||||
|
||||
import spack.monitor
|
||||
from .analyzer_base import AnalyzerBase
|
||||
|
||||
import os
|
||||
|
||||
import spack.monitor
|
||||
|
||||
from .analyzer_base import AnalyzerBase
|
||||
|
||||
|
||||
class InstallFiles(AnalyzerBase):
|
||||
|
||||
|
||||
@@ -4,20 +4,20 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
|
||||
import spack
|
||||
import spack.error
|
||||
import spack.bootstrap
|
||||
import spack.hooks
|
||||
import spack.monitor
|
||||
import spack.binary_distribution
|
||||
import spack.package
|
||||
import spack.repo
|
||||
import os
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
from .analyzer_base import AnalyzerBase
|
||||
import spack
|
||||
import spack.binary_distribution
|
||||
import spack.bootstrap
|
||||
import spack.error
|
||||
import spack.hooks
|
||||
import spack.monitor
|
||||
import spack.package
|
||||
import spack.repo
|
||||
|
||||
import os
|
||||
from .analyzer_base import AnalyzerBase
|
||||
|
||||
|
||||
class Libabigail(AnalyzerBase):
|
||||
|
||||
@@ -60,20 +60,21 @@
|
||||
import functools
|
||||
import warnings
|
||||
|
||||
import archspec.cpu
|
||||
import six
|
||||
|
||||
import llnl.util.tty as tty
|
||||
import archspec.cpu
|
||||
|
||||
import llnl.util.lang as lang
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.compiler
|
||||
import spack.compilers
|
||||
import spack.config
|
||||
import spack.paths
|
||||
import spack.error as serr
|
||||
import spack.paths
|
||||
import spack.util.classes
|
||||
import spack.util.executable
|
||||
import spack.version
|
||||
import spack.util.classes
|
||||
from spack.util.spack_yaml import syaml_dict
|
||||
|
||||
|
||||
|
||||
395
lib/spack/spack/audit.py
Normal file
395
lib/spack/spack/audit.py
Normal file
@@ -0,0 +1,395 @@
|
||||
# Copyright 2013-2021 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)
|
||||
"""Classes and functions to register audit checks for various parts of
|
||||
Spack and run them on-demand.
|
||||
|
||||
To register a new class of sanity checks (e.g. sanity checks for
|
||||
compilers.yaml), the first action required is to create a new AuditClass
|
||||
object:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
audit_cfgcmp = AuditClass(
|
||||
tag='CFG-COMPILER',
|
||||
description='Sanity checks on compilers.yaml',
|
||||
kwargs=()
|
||||
)
|
||||
|
||||
This object is to be used as a decorator to register functions
|
||||
that will perform each a single check:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@audit_cfgcmp
|
||||
def _search_duplicate_compilers(error_cls):
|
||||
pass
|
||||
|
||||
These functions need to take as argument the keywords declared when
|
||||
creating the decorator object plus an ``error_cls`` argument at the
|
||||
end, acting as a factory to create Error objects. It should return a
|
||||
(possibly empty) list of errors.
|
||||
|
||||
Calls to each of these functions are triggered by the ``run`` method of
|
||||
the decorator object, that will forward the keyword arguments passed
|
||||
as input.
|
||||
"""
|
||||
import collections
|
||||
import itertools
|
||||
|
||||
try:
|
||||
from collections.abc import Sequence # novm
|
||||
except ImportError:
|
||||
from collections import Sequence
|
||||
|
||||
#: Map an audit tag to a list of callables implementing checks
|
||||
CALLBACKS = {}
|
||||
|
||||
#: Map a group of checks to the list of related audit tags
|
||||
GROUPS = collections.defaultdict(list)
|
||||
|
||||
|
||||
class Error(object):
|
||||
"""Information on an error reported in a test."""
|
||||
def __init__(self, summary, details):
|
||||
self.summary = summary
|
||||
self.details = tuple(details)
|
||||
|
||||
def __str__(self):
|
||||
return self.summary + '\n' + '\n'.join([
|
||||
' ' + detail for detail in self.details
|
||||
])
|
||||
|
||||
def __eq__(self, other):
|
||||
if self.summary != other.summary or self.details != other.details:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __hash__(self):
|
||||
value = (self.summary, self.details)
|
||||
return hash(value)
|
||||
|
||||
|
||||
class AuditClass(Sequence):
|
||||
def __init__(self, group, tag, description, kwargs):
|
||||
"""Return an object that acts as a decorator to register functions
|
||||
associated with a specific class of sanity checks.
|
||||
|
||||
Args:
|
||||
group (str): group in which this check is to be inserted
|
||||
tag (str): tag uniquely identifying the class of sanity checks
|
||||
description (str): description of the sanity checks performed
|
||||
by this tag
|
||||
kwargs (tuple of str): keyword arguments that each registered
|
||||
function needs to accept
|
||||
"""
|
||||
if tag in CALLBACKS:
|
||||
msg = 'audit class "{0}" already registered'
|
||||
raise ValueError(msg.format(tag))
|
||||
|
||||
self.group = group
|
||||
self.tag = tag
|
||||
self.description = description
|
||||
self.kwargs = kwargs
|
||||
self.callbacks = []
|
||||
|
||||
# Init the list of hooks
|
||||
CALLBACKS[self.tag] = self
|
||||
|
||||
# Update the list of tags in the group
|
||||
GROUPS[self.group].append(self.tag)
|
||||
|
||||
def __call__(self, func):
|
||||
self.callbacks.append(func)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.callbacks[item]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.callbacks)
|
||||
|
||||
def run(self, **kwargs):
|
||||
msg = 'please pass "{0}" as keyword arguments'
|
||||
msg = msg.format(', '.join(self.kwargs))
|
||||
assert set(self.kwargs) == set(kwargs), msg
|
||||
|
||||
errors = []
|
||||
kwargs['error_cls'] = Error
|
||||
for fn in self.callbacks:
|
||||
errors.extend(fn(**kwargs))
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
def run_group(group, **kwargs):
|
||||
"""Run the checks that are part of the group passed as argument.
|
||||
|
||||
Args:
|
||||
group (str): group of checks to be run
|
||||
**kwargs: keyword arguments forwarded to the checks
|
||||
|
||||
Returns:
|
||||
List of (tag, errors) that failed.
|
||||
"""
|
||||
reports = []
|
||||
for check in GROUPS[group]:
|
||||
errors = run_check(check, **kwargs)
|
||||
reports.append((check, errors))
|
||||
return reports
|
||||
|
||||
|
||||
def run_check(tag, **kwargs):
|
||||
"""Run the checks associated with a single tag.
|
||||
|
||||
Args:
|
||||
tag (str): tag of the check
|
||||
**kwargs: keyword arguments forwarded to the checks
|
||||
|
||||
Returns:
|
||||
Errors occurred during the checks
|
||||
"""
|
||||
return CALLBACKS[tag].run(**kwargs)
|
||||
|
||||
|
||||
# TODO: For the generic check to be useful for end users,
|
||||
# TODO: we need to implement hooks like described in
|
||||
# TODO: https://github.com/spack/spack/pull/23053/files#r630265011
|
||||
#: Generic checks relying on global state
|
||||
generic = AuditClass(
|
||||
group='generic',
|
||||
tag='GENERIC',
|
||||
description='Generic checks relying on global variables',
|
||||
kwargs=()
|
||||
)
|
||||
|
||||
|
||||
#: Sanity checks on compilers.yaml
|
||||
config_compiler = AuditClass(
|
||||
group='configs',
|
||||
tag='CFG-COMPILER',
|
||||
description='Sanity checks on compilers.yaml',
|
||||
kwargs=()
|
||||
)
|
||||
|
||||
|
||||
@config_compiler
|
||||
def _search_duplicate_compilers(error_cls):
|
||||
"""Report compilers with the same spec and two different definitions"""
|
||||
import spack.config
|
||||
errors = []
|
||||
|
||||
compilers = list(sorted(
|
||||
spack.config.get('compilers'), key=lambda x: x['compiler']['spec']
|
||||
))
|
||||
for spec, group in itertools.groupby(
|
||||
compilers, key=lambda x: x['compiler']['spec']
|
||||
):
|
||||
group = list(group)
|
||||
if len(group) == 1:
|
||||
continue
|
||||
|
||||
error_msg = 'Compiler defined multiple times: {0}'
|
||||
try:
|
||||
details = [str(x._start_mark).strip() for x in group]
|
||||
except Exception:
|
||||
details = []
|
||||
errors.append(error_cls(
|
||||
summary=error_msg.format(spec), details=details
|
||||
))
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
#: Sanity checks on packages.yaml
|
||||
config_packages = AuditClass(
|
||||
group='configs',
|
||||
tag='CFG-PACKAGES',
|
||||
description='Sanity checks on packages.yaml',
|
||||
kwargs=()
|
||||
)
|
||||
|
||||
|
||||
@config_packages
|
||||
def _search_duplicate_specs_in_externals(error_cls):
|
||||
"""Search for duplicate specs declared as externals"""
|
||||
import spack.config
|
||||
|
||||
errors, externals = [], collections.defaultdict(list)
|
||||
packages_yaml = spack.config.get('packages')
|
||||
|
||||
for name, pkg_config in packages_yaml.items():
|
||||
# No externals can be declared under all
|
||||
if name == 'all' or 'externals' not in pkg_config:
|
||||
continue
|
||||
|
||||
current_externals = pkg_config['externals']
|
||||
for entry in current_externals:
|
||||
# Ask for the string representation of the spec to normalize
|
||||
# aspects of the spec that may be represented in multiple ways
|
||||
# e.g. +foo or foo=true
|
||||
key = str(spack.spec.Spec(entry['spec']))
|
||||
externals[key].append(entry)
|
||||
|
||||
for spec, entries in sorted(externals.items()):
|
||||
# If there's a single external for a spec we are fine
|
||||
if len(entries) < 2:
|
||||
continue
|
||||
|
||||
# Otherwise wwe need to report an error
|
||||
error_msg = 'Multiple externals share the same spec: {0}'.format(spec)
|
||||
try:
|
||||
lines = [str(x._start_mark).strip() for x in entries]
|
||||
details = [
|
||||
'Please remove all but one of the following entries:'
|
||||
] + lines + [
|
||||
'as they might result in non-deterministic hashes'
|
||||
]
|
||||
except TypeError:
|
||||
details = []
|
||||
|
||||
errors.append(error_cls(summary=error_msg, details=details))
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
#: Sanity checks on package directives
|
||||
package_directives = AuditClass(
|
||||
group='packages',
|
||||
tag='PKG-DIRECTIVES',
|
||||
description='Sanity checks on specs used in directives',
|
||||
kwargs=('pkgs',)
|
||||
)
|
||||
|
||||
|
||||
@package_directives
|
||||
def _unknown_variants_in_directives(pkgs, error_cls):
|
||||
"""Report unknown or wrong variants in directives for this package"""
|
||||
import llnl.util.lang
|
||||
|
||||
import spack.repo
|
||||
import spack.spec
|
||||
|
||||
errors = []
|
||||
for pkg_name in pkgs:
|
||||
pkg = spack.repo.get(pkg_name)
|
||||
|
||||
# Check "conflicts" directive
|
||||
for conflict, triggers in pkg.conflicts.items():
|
||||
for trigger, _ in triggers:
|
||||
vrn = spack.spec.Spec(conflict)
|
||||
try:
|
||||
vrn.constrain(trigger)
|
||||
except Exception as e:
|
||||
msg = 'Generic error in conflict for package "{0}": '
|
||||
errors.append(error_cls(msg.format(pkg.name), [str(e)]))
|
||||
continue
|
||||
errors.extend(_analyze_variants_in_directive(
|
||||
pkg, vrn, directive='conflicts', error_cls=error_cls
|
||||
))
|
||||
|
||||
# Check "depends_on" directive
|
||||
for _, triggers in pkg.dependencies.items():
|
||||
triggers = list(triggers)
|
||||
for trigger in list(triggers):
|
||||
vrn = spack.spec.Spec(trigger)
|
||||
errors.extend(_analyze_variants_in_directive(
|
||||
pkg, vrn, directive='depends_on', error_cls=error_cls
|
||||
))
|
||||
|
||||
# Check "patch" directive
|
||||
for _, triggers in pkg.provided.items():
|
||||
triggers = [spack.spec.Spec(x) for x in triggers]
|
||||
for vrn in triggers:
|
||||
errors.extend(_analyze_variants_in_directive(
|
||||
pkg, vrn, directive='patch', error_cls=error_cls
|
||||
))
|
||||
|
||||
# Check "resource" directive
|
||||
for vrn in pkg.resources:
|
||||
errors.extend(_analyze_variants_in_directive(
|
||||
pkg, vrn, directive='resource', error_cls=error_cls
|
||||
))
|
||||
|
||||
return llnl.util.lang.dedupe(errors)
|
||||
|
||||
|
||||
@package_directives
|
||||
def _unknown_variants_in_dependencies(pkgs, error_cls):
|
||||
"""Report unknown dependencies and wrong variants for dependencies"""
|
||||
import spack.repo
|
||||
import spack.spec
|
||||
|
||||
errors = []
|
||||
for pkg_name in pkgs:
|
||||
pkg = spack.repo.get(pkg_name)
|
||||
filename = spack.repo.path.filename_for_package_name(pkg_name)
|
||||
for dependency_name, dependency_data in pkg.dependencies.items():
|
||||
# No need to analyze virtual packages
|
||||
if spack.repo.path.is_virtual(dependency_name):
|
||||
continue
|
||||
|
||||
try:
|
||||
dependency_pkg = spack.repo.get(dependency_name)
|
||||
except spack.repo.UnknownPackageError:
|
||||
# This dependency is completely missing, so report
|
||||
# and continue the analysis
|
||||
summary = (pkg_name + ": unknown package '{0}' in "
|
||||
"'depends_on' directive".format(dependency_name))
|
||||
details = [
|
||||
" in " + filename
|
||||
]
|
||||
errors.append(error_cls(summary=summary, details=details))
|
||||
continue
|
||||
|
||||
for _, dependency_edge in dependency_data.items():
|
||||
dependency_variants = dependency_edge.spec.variants
|
||||
for name, value in dependency_variants.items():
|
||||
try:
|
||||
dependency_pkg.variants[name].validate_or_raise(
|
||||
value, pkg=dependency_pkg
|
||||
)
|
||||
except Exception as e:
|
||||
summary = (pkg_name + ": wrong variant used for a "
|
||||
"dependency in a 'depends_on' directive")
|
||||
error_msg = str(e).strip()
|
||||
if isinstance(e, KeyError):
|
||||
error_msg = ('the variant {0} does not '
|
||||
'exist'.format(error_msg))
|
||||
error_msg += " in package '" + dependency_name + "'"
|
||||
|
||||
errors.append(error_cls(
|
||||
summary=summary, details=[error_msg, 'in ' + filename]
|
||||
))
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
def _analyze_variants_in_directive(pkg, constraint, directive, error_cls):
|
||||
import spack.variant
|
||||
variant_exceptions = (
|
||||
spack.variant.InconsistentValidationError,
|
||||
spack.variant.MultipleValuesInExclusiveVariantError,
|
||||
spack.variant.InvalidVariantValueError,
|
||||
KeyError
|
||||
)
|
||||
errors = []
|
||||
for name, v in constraint.variants.items():
|
||||
try:
|
||||
pkg.variants[name].validate_or_raise(v, pkg=pkg)
|
||||
except variant_exceptions as e:
|
||||
summary = pkg.name + ': wrong variant in "{0}" directive'
|
||||
summary = summary.format(directive)
|
||||
filename = spack.repo.path.filename_for_package_name(pkg.name)
|
||||
|
||||
error_msg = str(e).strip()
|
||||
if isinstance(e, KeyError):
|
||||
error_msg = 'the variant {0} does not exist'.format(error_msg)
|
||||
|
||||
err = error_cls(summary=summary, details=[
|
||||
error_msg, 'in ' + filename
|
||||
])
|
||||
|
||||
errors.append(err)
|
||||
|
||||
return errors
|
||||
@@ -4,22 +4,20 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import codecs
|
||||
import glob
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tarfile
|
||||
import shutil
|
||||
import tempfile
|
||||
import hashlib
|
||||
import glob
|
||||
from ordereddict_backport import OrderedDict
|
||||
|
||||
from contextlib import closing
|
||||
|
||||
import ruamel.yaml as yaml
|
||||
|
||||
import json
|
||||
|
||||
from six.moves.urllib.error import URLError, HTTPError
|
||||
from ordereddict_backport import OrderedDict
|
||||
from six.moves.urllib.error import HTTPError, URLError
|
||||
|
||||
import llnl.util.lang
|
||||
import llnl.util.tty as tty
|
||||
@@ -29,19 +27,18 @@
|
||||
import spack.config as config
|
||||
import spack.database as spack_db
|
||||
import spack.fetch_strategy as fs
|
||||
import spack.util.file_cache as file_cache
|
||||
import spack.mirror
|
||||
import spack.relocate as relocate
|
||||
import spack.util.file_cache as file_cache
|
||||
import spack.util.gpg
|
||||
import spack.util.spack_json as sjson
|
||||
import spack.util.spack_yaml as syaml
|
||||
import spack.mirror
|
||||
import spack.util.url as url_util
|
||||
import spack.util.web as web_util
|
||||
from spack.caches import misc_cache_location
|
||||
from spack.spec import Spec
|
||||
from spack.stage import Stage
|
||||
|
||||
|
||||
_build_cache_relative_path = 'build_cache'
|
||||
_build_cache_keys_relative_path = '_pgp'
|
||||
|
||||
@@ -156,7 +153,7 @@ 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)
|
||||
|
||||
spec_list = db.query_local(installed=False)
|
||||
spec_list = db.query_local(installed=False, in_buildcache=True)
|
||||
|
||||
for indexed_spec in spec_list:
|
||||
dag_hash = indexed_spec.dag_hash()
|
||||
@@ -716,7 +713,7 @@ def generate_package_index(cache_prefix):
|
||||
db_root_dir = os.path.join(tmpdir, 'db_root')
|
||||
db = spack_db.Database(None, db_dir=db_root_dir,
|
||||
enable_transaction_locking=False,
|
||||
record_fields=['spec', 'ref_count'])
|
||||
record_fields=['spec', 'ref_count', 'in_buildcache'])
|
||||
|
||||
try:
|
||||
file_list = (
|
||||
@@ -748,6 +745,7 @@ def generate_package_index(cache_prefix):
|
||||
# s = Spec.from_yaml(yaml_obj)
|
||||
s = Spec.from_yaml(yaml_contents)
|
||||
db.add(s, None)
|
||||
db.mark(s, 'in_buildcache', True)
|
||||
except (URLError, web_util.SpackWebError) as url_err:
|
||||
tty.error('Error reading spec.yaml: {0}'.format(file_path))
|
||||
tty.error(url_err)
|
||||
@@ -1557,7 +1555,9 @@ def push_keys(*mirrors, **kwargs):
|
||||
filename = fingerprint + '.pub'
|
||||
|
||||
export_target = os.path.join(prefix, filename)
|
||||
spack.util.gpg.export_keys(export_target, fingerprint)
|
||||
|
||||
# Export public keys (private is set to False)
|
||||
spack.util.gpg.export_keys(export_target, [fingerprint])
|
||||
|
||||
# If mirror is local, the above export writes directly to the
|
||||
# mirror (export_target points directly to the mirror).
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import contextlib
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
import sysconfig # novm
|
||||
except ImportError:
|
||||
|
||||
@@ -33,44 +33,52 @@
|
||||
calls you can make from within the install() function.
|
||||
"""
|
||||
import inspect
|
||||
import re
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import traceback
|
||||
import types
|
||||
|
||||
from six import StringIO
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.tty.color import cescape, colorize
|
||||
from llnl.util.filesystem import mkdirp, install, install_tree
|
||||
from llnl.util.filesystem import install, install_tree, mkdirp
|
||||
from llnl.util.lang import dedupe
|
||||
from llnl.util.tty.color import cescape, colorize
|
||||
from llnl.util.tty.log import MultiProcessFd
|
||||
|
||||
import spack.architecture as arch
|
||||
import spack.build_systems.cmake
|
||||
import spack.build_systems.meson
|
||||
import spack.config
|
||||
import spack.install_test
|
||||
import spack.main
|
||||
import spack.paths
|
||||
import spack.package
|
||||
import spack.paths
|
||||
import spack.repo
|
||||
import spack.schema.environment
|
||||
import spack.store
|
||||
import spack.install_test
|
||||
import spack.subprocess_context
|
||||
import spack.architecture as arch
|
||||
import spack.util.path
|
||||
from spack.util.string import plural
|
||||
from spack.util.environment import (
|
||||
env_flag, filter_system_paths, get_path, is_system_path,
|
||||
EnvironmentModifications, validate, preserve_environment)
|
||||
from spack.util.environment import system_dirs
|
||||
from spack.error import NoLibrariesError, NoHeadersError
|
||||
from spack.util.executable import Executable
|
||||
from spack.util.module_cmd import load_module, path_from_modules, module
|
||||
from spack.util.log_parse import parse_log_events, make_log_context
|
||||
from spack.error import NoHeadersError, NoLibrariesError
|
||||
from spack.util.cpus import cpus_available
|
||||
from spack.util.environment import (
|
||||
EnvironmentModifications,
|
||||
env_flag,
|
||||
filter_system_paths,
|
||||
get_path,
|
||||
is_system_path,
|
||||
preserve_environment,
|
||||
system_dirs,
|
||||
validate,
|
||||
)
|
||||
from spack.util.executable import Executable
|
||||
from spack.util.log_parse import make_log_context, parse_log_events
|
||||
from spack.util.module_cmd import load_module, module, path_from_modules
|
||||
from spack.util.string import plural
|
||||
|
||||
#
|
||||
# This can be set by the user to globally disable parallel builds.
|
||||
#
|
||||
@@ -78,7 +86,7 @@
|
||||
|
||||
#
|
||||
# These environment variables are set by
|
||||
# set_build_environment_variables and used to pass parameters to
|
||||
# set_wrapper_variables and used to pass parameters to
|
||||
# Spack's compiler wrappers.
|
||||
#
|
||||
SPACK_ENV_PATH = 'SPACK_ENV_PATH'
|
||||
@@ -159,6 +167,12 @@ def clean_environment():
|
||||
env.unset('CPLUS_INCLUDE_PATH')
|
||||
env.unset('OBJC_INCLUDE_PATH')
|
||||
|
||||
env.unset('CMAKE_PREFIX_PATH')
|
||||
|
||||
# Avoid that libraries of build dependencies get hijacked.
|
||||
env.unset('LD_PRELOAD')
|
||||
env.unset('DYLD_INSERT_LIBRARIES')
|
||||
|
||||
# On Cray "cluster" systems, unset CRAY_LD_LIBRARY_PATH to avoid
|
||||
# interference with Spack dependencies.
|
||||
# CNL requires these variables to be set (or at least some of them,
|
||||
@@ -306,113 +320,20 @@ def set_compiler_environment_variables(pkg, env):
|
||||
return env
|
||||
|
||||
|
||||
def _place_externals_last(spec_container):
|
||||
def set_wrapper_variables(pkg, env):
|
||||
"""Set environment variables used by the Spack compiler wrapper
|
||||
(which have the prefix `SPACK_`) and also add the compiler wrappers
|
||||
to PATH.
|
||||
|
||||
This determines the injected -L/-I/-rpath options; each
|
||||
of these specifies a search order and this function computes these
|
||||
options in a manner that is intended to match the DAG traversal order
|
||||
in `modifications_from_dependencies`: that method uses a post-order
|
||||
traversal so that `PrependPath` actions from dependencies take lower
|
||||
precedence; we use a post-order traversal here to match the visitation
|
||||
order of `modifications_from_dependencies` (so we are visiting the
|
||||
lowest priority packages first).
|
||||
"""
|
||||
For a (possibly unordered) container of specs, return an ordered list
|
||||
where all external specs are at the end of the list. External packages
|
||||
may be installed in merged prefixes with other packages, and so
|
||||
they should be deprioritized for any search order (i.e. in PATH, or
|
||||
for a set of -L entries in a compiler invocation).
|
||||
"""
|
||||
first = list(x for x in spec_container if not x.external)
|
||||
second = list(x for x in spec_container if x.external)
|
||||
return first + second
|
||||
|
||||
|
||||
def set_build_environment_variables(pkg, env, dirty):
|
||||
"""Ensure a clean install environment when we build packages.
|
||||
|
||||
This involves unsetting pesky environment variables that may
|
||||
affect the build. It also involves setting environment variables
|
||||
used by Spack's compiler wrappers.
|
||||
|
||||
Args:
|
||||
pkg: The package we are building
|
||||
env: The build environment
|
||||
dirty (bool): Skip unsetting the user's environment settings
|
||||
"""
|
||||
# Gather information about various types of dependencies
|
||||
build_deps = set(pkg.spec.dependencies(deptype=('build', 'test')))
|
||||
link_deps = set(pkg.spec.traverse(root=False, deptype=('link')))
|
||||
build_link_deps = build_deps | link_deps
|
||||
rpath_deps = get_rpath_deps(pkg)
|
||||
# This includes all build dependencies and any other dependencies that
|
||||
# should be added to PATH (e.g. supporting executables run by build
|
||||
# dependencies)
|
||||
build_and_supporting_deps = set()
|
||||
for build_dep in build_deps:
|
||||
build_and_supporting_deps.update(build_dep.traverse(deptype='run'))
|
||||
|
||||
# Establish an arbitrary but fixed ordering of specs so that resulting
|
||||
# environment variable values are stable
|
||||
def _order(specs):
|
||||
return sorted(specs, key=lambda x: x.name)
|
||||
|
||||
# External packages may be installed in a prefix which contains many other
|
||||
# package installs. To avoid having those installations override
|
||||
# Spack-installed packages, they are placed at the end of search paths.
|
||||
# System prefixes are removed entirely later on since they are already
|
||||
# searched.
|
||||
build_deps = _place_externals_last(_order(build_deps))
|
||||
link_deps = _place_externals_last(_order(link_deps))
|
||||
build_link_deps = _place_externals_last(_order(build_link_deps))
|
||||
rpath_deps = _place_externals_last(_order(rpath_deps))
|
||||
build_and_supporting_deps = _place_externals_last(
|
||||
_order(build_and_supporting_deps))
|
||||
|
||||
link_dirs = []
|
||||
include_dirs = []
|
||||
rpath_dirs = []
|
||||
|
||||
# The top-level package is always RPATHed. It hasn't been installed yet
|
||||
# so the RPATHs are added unconditionally (e.g. even though lib64/ may
|
||||
# not be created for the install).
|
||||
for libdir in ['lib', 'lib64']:
|
||||
lib_path = os.path.join(pkg.prefix, libdir)
|
||||
rpath_dirs.append(lib_path)
|
||||
|
||||
# Set up link, include, RPATH directories that are passed to the
|
||||
# compiler wrapper
|
||||
for dep in link_deps:
|
||||
if is_system_path(dep.prefix):
|
||||
continue
|
||||
query = pkg.spec[dep.name]
|
||||
dep_link_dirs = list()
|
||||
try:
|
||||
dep_link_dirs.extend(query.libs.directories)
|
||||
except NoLibrariesError:
|
||||
tty.debug("No libraries found for {0}".format(dep.name))
|
||||
|
||||
for default_lib_dir in ['lib', 'lib64']:
|
||||
default_lib_prefix = os.path.join(dep.prefix, default_lib_dir)
|
||||
if os.path.isdir(default_lib_prefix):
|
||||
dep_link_dirs.append(default_lib_prefix)
|
||||
|
||||
link_dirs.extend(dep_link_dirs)
|
||||
if dep in rpath_deps:
|
||||
rpath_dirs.extend(dep_link_dirs)
|
||||
|
||||
try:
|
||||
include_dirs.extend(query.headers.directories)
|
||||
except NoHeadersError:
|
||||
tty.debug("No headers found for {0}".format(dep.name))
|
||||
|
||||
link_dirs = list(dedupe(filter_system_paths(link_dirs)))
|
||||
include_dirs = list(dedupe(filter_system_paths(include_dirs)))
|
||||
rpath_dirs = list(dedupe(filter_system_paths(rpath_dirs)))
|
||||
|
||||
env.set(SPACK_LINK_DIRS, ':'.join(link_dirs))
|
||||
env.set(SPACK_INCLUDE_DIRS, ':'.join(include_dirs))
|
||||
env.set(SPACK_RPATH_DIRS, ':'.join(rpath_dirs))
|
||||
|
||||
build_and_supporting_prefixes = filter_system_paths(
|
||||
x.prefix for x in build_and_supporting_deps)
|
||||
build_link_prefixes = filter_system_paths(
|
||||
x.prefix for x in build_link_deps)
|
||||
|
||||
# Add dependencies to CMAKE_PREFIX_PATH
|
||||
env.set_path('CMAKE_PREFIX_PATH', build_link_prefixes)
|
||||
|
||||
# Set environment variables if specified for
|
||||
# the given compiler
|
||||
compiler = pkg.compiler
|
||||
@@ -422,16 +343,6 @@ def _order(specs):
|
||||
extra_rpaths = ':'.join(compiler.extra_rpaths)
|
||||
env.set('SPACK_COMPILER_EXTRA_RPATHS', extra_rpaths)
|
||||
|
||||
# Add bin directories from dependencies to the PATH for the build.
|
||||
# These directories are added to the beginning of the search path, and in
|
||||
# the order given by 'build_and_supporting_prefixes' (the iteration order
|
||||
# is reversed because each entry is prepended)
|
||||
for prefix in reversed(build_and_supporting_prefixes):
|
||||
for dirname in ['bin', 'bin64']:
|
||||
bin_dir = os.path.join(prefix, dirname)
|
||||
if os.path.isdir(bin_dir):
|
||||
env.prepend_path('PATH', bin_dir)
|
||||
|
||||
# Add spack build environment path with compiler wrappers first in
|
||||
# the path. We add the compiler wrapper path, which includes default
|
||||
# wrappers (cc, c++, f77, f90), AND a subdirectory containing
|
||||
@@ -451,6 +362,7 @@ def _order(specs):
|
||||
if os.path.isdir(ci):
|
||||
env_paths.append(ci)
|
||||
|
||||
tty.debug("Adding compiler bin/ paths: " + " ".join(env_paths))
|
||||
for item in env_paths:
|
||||
env.prepend_path('PATH', item)
|
||||
env.set_path(SPACK_ENV_PATH, env_paths)
|
||||
@@ -469,14 +381,69 @@ def _order(specs):
|
||||
raise RuntimeError("No ccache binary found in PATH")
|
||||
env.set(SPACK_CCACHE_BINARY, ccache)
|
||||
|
||||
# Add any pkgconfig directories to PKG_CONFIG_PATH
|
||||
for prefix in reversed(build_link_prefixes):
|
||||
for directory in ('lib', 'lib64', 'share'):
|
||||
pcdir = os.path.join(prefix, directory, 'pkgconfig')
|
||||
if os.path.isdir(pcdir):
|
||||
env.prepend_path('PKG_CONFIG_PATH', pcdir)
|
||||
# Gather information about various types of dependencies
|
||||
link_deps = set(pkg.spec.traverse(root=False, deptype=('link')))
|
||||
rpath_deps = get_rpath_deps(pkg)
|
||||
|
||||
return env
|
||||
link_dirs = []
|
||||
include_dirs = []
|
||||
rpath_dirs = []
|
||||
|
||||
def _prepend_all(list_to_modify, items_to_add):
|
||||
# Update the original list (creating a new list would be faster but
|
||||
# may not be convenient)
|
||||
for item in reversed(list(items_to_add)):
|
||||
list_to_modify.insert(0, item)
|
||||
|
||||
def update_compiler_args_for_dep(dep):
|
||||
if dep in link_deps and (not is_system_path(dep.prefix)):
|
||||
query = pkg.spec[dep.name]
|
||||
dep_link_dirs = list()
|
||||
try:
|
||||
dep_link_dirs.extend(query.libs.directories)
|
||||
except NoLibrariesError:
|
||||
tty.debug("No libraries found for {0}".format(dep.name))
|
||||
|
||||
for default_lib_dir in ['lib', 'lib64']:
|
||||
default_lib_prefix = os.path.join(
|
||||
dep.prefix, default_lib_dir)
|
||||
if os.path.isdir(default_lib_prefix):
|
||||
dep_link_dirs.append(default_lib_prefix)
|
||||
|
||||
_prepend_all(link_dirs, dep_link_dirs)
|
||||
if dep in rpath_deps:
|
||||
_prepend_all(rpath_dirs, dep_link_dirs)
|
||||
|
||||
try:
|
||||
_prepend_all(include_dirs, query.headers.directories)
|
||||
except NoHeadersError:
|
||||
tty.debug("No headers found for {0}".format(dep.name))
|
||||
|
||||
for dspec in pkg.spec.traverse(root=False, order='post'):
|
||||
if dspec.external:
|
||||
update_compiler_args_for_dep(dspec)
|
||||
|
||||
# Just above, we prepended entries for -L/-rpath for externals. We
|
||||
# now do this for non-external packages so that Spack-built packages
|
||||
# are searched first for libraries etc.
|
||||
for dspec in pkg.spec.traverse(root=False, order='post'):
|
||||
if not dspec.external:
|
||||
update_compiler_args_for_dep(dspec)
|
||||
|
||||
# The top-level package is always RPATHed. It hasn't been installed yet
|
||||
# so the RPATHs are added unconditionally (e.g. even though lib64/ may
|
||||
# not be created for the install).
|
||||
for libdir in ['lib64', 'lib']:
|
||||
lib_path = os.path.join(pkg.prefix, libdir)
|
||||
rpath_dirs.insert(0, lib_path)
|
||||
|
||||
link_dirs = list(dedupe(filter_system_paths(link_dirs)))
|
||||
include_dirs = list(dedupe(filter_system_paths(include_dirs)))
|
||||
rpath_dirs = list(dedupe(filter_system_paths(rpath_dirs)))
|
||||
|
||||
env.set(SPACK_LINK_DIRS, ':'.join(link_dirs))
|
||||
env.set(SPACK_INCLUDE_DIRS, ':'.join(include_dirs))
|
||||
env.set(SPACK_RPATH_DIRS, ':'.join(rpath_dirs))
|
||||
|
||||
|
||||
def determine_number_of_jobs(
|
||||
@@ -781,42 +748,40 @@ def load_external_modules(pkg):
|
||||
|
||||
def setup_package(pkg, dirty, context='build'):
|
||||
"""Execute all environment setup routines."""
|
||||
if context not in ['build', 'test']:
|
||||
raise ValueError(
|
||||
"'context' must be one of ['build', 'test'] - got: {0}"
|
||||
.format(context))
|
||||
|
||||
set_module_variables_for_package(pkg)
|
||||
|
||||
env = EnvironmentModifications()
|
||||
|
||||
if not dirty:
|
||||
clean_environment()
|
||||
|
||||
# setup compilers and build tools for build contexts
|
||||
# setup compilers for build contexts
|
||||
need_compiler = context == 'build' or (context == 'test' and
|
||||
pkg.test_requires_compiler)
|
||||
if need_compiler:
|
||||
set_compiler_environment_variables(pkg, env)
|
||||
set_build_environment_variables(pkg, env, dirty)
|
||||
set_wrapper_variables(pkg, env)
|
||||
|
||||
env.extend(modifications_from_dependencies(
|
||||
pkg.spec, context, custom_mods_only=False))
|
||||
|
||||
# architecture specific setup
|
||||
pkg.architecture.platform.setup_platform_environment(pkg, env)
|
||||
|
||||
if context == 'build':
|
||||
# recursive post-order dependency information
|
||||
env.extend(
|
||||
modifications_from_dependencies(pkg.spec, context=context)
|
||||
)
|
||||
pkg.setup_build_environment(env)
|
||||
|
||||
if (not dirty) and (not env.is_unset('CPATH')):
|
||||
tty.debug("A dependency has updated CPATH, this may lead pkg-"
|
||||
"config to assume that the package is part of the system"
|
||||
" includes and omit it when invoked with '--cflags'.")
|
||||
|
||||
# setup package itself
|
||||
set_module_variables_for_package(pkg)
|
||||
pkg.setup_build_environment(env)
|
||||
elif context == 'test':
|
||||
import spack.user_environment as uenv # avoid circular import
|
||||
env.extend(uenv.environment_modifications_for_spec(pkg.spec))
|
||||
env.extend(
|
||||
modifications_from_dependencies(pkg.spec, context=context)
|
||||
)
|
||||
set_module_variables_for_package(pkg)
|
||||
pkg.setup_run_environment(env)
|
||||
env.prepend_path('PATH', '.')
|
||||
|
||||
# Loading modules, in particular if they are meant to be used outside
|
||||
@@ -858,39 +823,173 @@ def setup_package(pkg, dirty, context='build'):
|
||||
env.apply_modifications()
|
||||
|
||||
|
||||
def modifications_from_dependencies(spec, context):
|
||||
def _make_runnable(pkg, env):
|
||||
# Helper method which prepends a Package's bin/ prefix to the PATH
|
||||
# environment variable
|
||||
prefix = pkg.prefix
|
||||
|
||||
for dirname in ['bin', 'bin64']:
|
||||
bin_dir = os.path.join(prefix, dirname)
|
||||
if os.path.isdir(bin_dir):
|
||||
env.prepend_path('PATH', bin_dir)
|
||||
|
||||
|
||||
def modifications_from_dependencies(spec, context, custom_mods_only=True):
|
||||
"""Returns the environment modifications that are required by
|
||||
the dependencies of a spec and also applies modifications
|
||||
to this spec's package at module scope, if need be.
|
||||
|
||||
Environment modifications include:
|
||||
|
||||
- Updating PATH so that executables can be found
|
||||
- Updating CMAKE_PREFIX_PATH and PKG_CONFIG_PATH so that their respective
|
||||
tools can find Spack-built dependencies
|
||||
- Running custom package environment modifications
|
||||
|
||||
Custom package modifications can conflict with the default PATH changes
|
||||
we make (specifically for the PATH, CMAKE_PREFIX_PATH, and PKG_CONFIG_PATH
|
||||
environment variables), so this applies changes in a fixed order:
|
||||
|
||||
- All modifications (custom and default) from external deps first
|
||||
- All modifications from non-external deps afterwards
|
||||
|
||||
With that order, `PrependPath` actions from non-external default
|
||||
environment modifications will take precedence over custom modifications
|
||||
from external packages.
|
||||
|
||||
A secondary constraint is that custom and default modifications are
|
||||
grouped on a per-package basis: combined with the post-order traversal this
|
||||
means that default modifications of dependents can override custom
|
||||
modifications of dependencies (again, this would only occur for PATH,
|
||||
CMAKE_PREFIX_PATH, or PKG_CONFIG_PATH).
|
||||
|
||||
Args:
|
||||
spec (Spec): spec for which we want the modifications
|
||||
context (str): either 'build' for build-time modifications or 'run'
|
||||
for run-time modifications
|
||||
"""
|
||||
if context not in ['build', 'run', 'test']:
|
||||
raise ValueError(
|
||||
"Expecting context to be one of ['build', 'run', 'test'], "
|
||||
"got: {0}".format(context))
|
||||
|
||||
env = EnvironmentModifications()
|
||||
pkg = spec.package
|
||||
|
||||
# Maps the context to deptype and method to be called
|
||||
deptype_and_method = {
|
||||
'build': (('build', 'link', 'test'),
|
||||
'setup_dependent_build_environment'),
|
||||
'run': (('link', 'run'), 'setup_dependent_run_environment'),
|
||||
'test': (('link', 'run', 'test'), 'setup_dependent_run_environment')
|
||||
}
|
||||
deptype, method = deptype_and_method[context]
|
||||
# Note: see computation of 'custom_mod_deps' and 'exe_deps' later in this
|
||||
# function; these sets form the building blocks of those collections.
|
||||
build_deps = set(spec.dependencies(deptype=('build', 'test')))
|
||||
link_deps = set(spec.traverse(root=False, deptype='link'))
|
||||
build_link_deps = build_deps | link_deps
|
||||
build_and_supporting_deps = set()
|
||||
for build_dep in build_deps:
|
||||
build_and_supporting_deps.update(build_dep.traverse(deptype='run'))
|
||||
run_and_supporting_deps = set(
|
||||
spec.traverse(root=False, deptype=('run', 'link')))
|
||||
test_and_supporting_deps = set()
|
||||
for test_dep in set(spec.dependencies(deptype='test')):
|
||||
test_and_supporting_deps.update(test_dep.traverse(deptype='run'))
|
||||
|
||||
root = context == 'test'
|
||||
for dspec in spec.traverse(order='post', root=root, deptype=deptype):
|
||||
dpkg = dspec.package
|
||||
set_module_variables_for_package(dpkg)
|
||||
# Allow dependencies to modify the module
|
||||
dpkg.setup_dependent_package(pkg.module, spec)
|
||||
getattr(dpkg, method)(env, spec)
|
||||
# All dependencies that might have environment modifications to apply
|
||||
custom_mod_deps = set()
|
||||
if context == 'build':
|
||||
custom_mod_deps.update(build_and_supporting_deps)
|
||||
# Tests may be performed after build
|
||||
custom_mod_deps.update(test_and_supporting_deps)
|
||||
else:
|
||||
# test/run context
|
||||
custom_mod_deps.update(run_and_supporting_deps)
|
||||
if context == 'test':
|
||||
custom_mod_deps.update(test_and_supporting_deps)
|
||||
custom_mod_deps.update(link_deps)
|
||||
|
||||
# Determine 'exe_deps': the set of packages with binaries we want to use
|
||||
if context == 'build':
|
||||
exe_deps = build_and_supporting_deps | test_and_supporting_deps
|
||||
elif context == 'run':
|
||||
exe_deps = set(spec.traverse(deptype='run'))
|
||||
elif context == 'test':
|
||||
exe_deps = test_and_supporting_deps
|
||||
|
||||
def default_modifications_for_dep(dep):
|
||||
if (dep in build_link_deps and
|
||||
not is_system_path(dep.prefix) and
|
||||
context == 'build'):
|
||||
prefix = dep.prefix
|
||||
|
||||
env.prepend_path('CMAKE_PREFIX_PATH', prefix)
|
||||
|
||||
for directory in ('lib', 'lib64', 'share'):
|
||||
pcdir = os.path.join(prefix, directory, 'pkgconfig')
|
||||
if os.path.isdir(pcdir):
|
||||
env.prepend_path('PKG_CONFIG_PATH', pcdir)
|
||||
|
||||
if dep in exe_deps and not is_system_path(dep.prefix):
|
||||
_make_runnable(dep, env)
|
||||
|
||||
def add_modifications_for_dep(dep):
|
||||
# Some callers of this function only want the custom modifications.
|
||||
# For callers that want both custom and default modifications, we want
|
||||
# to perform the default modifications here (this groups custom
|
||||
# and default modifications together on a per-package basis).
|
||||
if not custom_mods_only:
|
||||
default_modifications_for_dep(dep)
|
||||
|
||||
# Perform custom modifications here (PrependPath actions performed in
|
||||
# the custom method override the default environment modifications
|
||||
# we do to help the build, namely for PATH, CMAKE_PREFIX_PATH, and
|
||||
# PKG_CONFIG_PATH)
|
||||
if dep in custom_mod_deps:
|
||||
dpkg = dep.package
|
||||
set_module_variables_for_package(dpkg)
|
||||
# Allow dependencies to modify the module
|
||||
dpkg.setup_dependent_package(spec.package.module, spec)
|
||||
if context == 'build':
|
||||
dpkg.setup_dependent_build_environment(env, spec)
|
||||
else:
|
||||
dpkg.setup_dependent_run_environment(env, spec)
|
||||
|
||||
# Note that we want to perform environment modifications in a fixed order.
|
||||
# The Spec.traverse method provides this: i.e. in addition to
|
||||
# the post-order semantics, it also guarantees a fixed traversal order
|
||||
# among dependencies which are not constrained by post-order semantics.
|
||||
for dspec in spec.traverse(root=False, order='post'):
|
||||
if dspec.external:
|
||||
add_modifications_for_dep(dspec)
|
||||
|
||||
for dspec in spec.traverse(root=False, order='post'):
|
||||
# Default env modifications for non-external packages can override
|
||||
# custom modifications of external packages (this can only occur
|
||||
# for modifications to PATH, CMAKE_PREFIX_PATH, and PKG_CONFIG_PATH)
|
||||
if not dspec.external:
|
||||
add_modifications_for_dep(dspec)
|
||||
|
||||
return env
|
||||
|
||||
|
||||
def get_cmake_prefix_path(pkg):
|
||||
# Note that unlike modifications_from_dependencies, this does not include
|
||||
# any edits to CMAKE_PREFIX_PATH defined in custom
|
||||
# setup_dependent_build_environment implementations of dependency packages
|
||||
build_deps = set(pkg.spec.dependencies(deptype=('build', 'test')))
|
||||
link_deps = set(pkg.spec.traverse(root=False, deptype=('link')))
|
||||
build_link_deps = build_deps | link_deps
|
||||
spack_built = []
|
||||
externals = []
|
||||
# modifications_from_dependencies updates CMAKE_PREFIX_PATH by first
|
||||
# prepending all externals and then all non-externals
|
||||
for dspec in pkg.spec.traverse(root=False, order='post'):
|
||||
if dspec in build_link_deps:
|
||||
if dspec.external:
|
||||
externals.insert(0, dspec)
|
||||
else:
|
||||
spack_built.insert(0, dspec)
|
||||
|
||||
ordered_build_link_deps = spack_built + externals
|
||||
build_link_prefixes = filter_system_paths(
|
||||
x.prefix for x in ordered_build_link_deps)
|
||||
return build_link_prefixes
|
||||
|
||||
|
||||
def _setup_pkg_and_run(serialized_pkg, function, kwargs, child_pipe,
|
||||
input_multiprocess_fd):
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
# Why doesn't this work for me?
|
||||
# from spack import *
|
||||
from llnl.util.filesystem import filter_file
|
||||
|
||||
from spack.build_systems.autotools import AutotoolsPackage
|
||||
from spack.directives import extends
|
||||
from spack.package import ExtensionError
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
import os
|
||||
import os.path
|
||||
import stat
|
||||
from subprocess import PIPE
|
||||
from subprocess import check_call
|
||||
from subprocess import PIPE, check_call
|
||||
from typing import List # novm
|
||||
|
||||
import llnl.util.tty as tty
|
||||
import llnl.util.filesystem as fs
|
||||
from llnl.util.filesystem import working_dir, force_remove
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import force_remove, working_dir
|
||||
|
||||
from spack.package import PackageBase, run_after, run_before
|
||||
from spack.util.executable import Executable
|
||||
|
||||
@@ -345,8 +345,11 @@ def build(self, spec, prefix):
|
||||
"""Makes the build targets specified by
|
||||
:py:attr:``~.AutotoolsPackage.build_targets``
|
||||
"""
|
||||
# See https://autotools.io/automake/silent.html
|
||||
params = ['V=1']
|
||||
params += self.build_targets
|
||||
with working_dir(self.build_directory):
|
||||
inspect.getmodule(self).make(*self.build_targets)
|
||||
inspect.getmodule(self).make(*params)
|
||||
|
||||
def install(self, spec, prefix):
|
||||
"""Makes the install targets specified by
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import os
|
||||
|
||||
from llnl.util.filesystem import install, mkdirp
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import install, mkdirp
|
||||
|
||||
from spack.build_systems.cmake import CMakePackage
|
||||
from spack.package import run_after
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
import re
|
||||
from typing import List # novm
|
||||
|
||||
import spack.build_environment
|
||||
from llnl.util.filesystem import working_dir
|
||||
from spack.util.environment import filter_system_paths
|
||||
from spack.directives import depends_on, variant, conflicts
|
||||
from spack.package import PackageBase, InstallError, run_after
|
||||
|
||||
import spack.build_environment
|
||||
from spack.directives import conflicts, depends_on, variant
|
||||
from spack.package import InstallError, PackageBase, run_after
|
||||
|
||||
# Regex to extract the primary generator from the CMake generator
|
||||
# string.
|
||||
@@ -185,13 +185,9 @@ def _std_args(pkg):
|
||||
define('CMAKE_INSTALL_RPATH_USE_LINK_PATH', False),
|
||||
define('CMAKE_INSTALL_RPATH',
|
||||
spack.build_environment.get_rpaths(pkg)),
|
||||
define('CMAKE_PREFIX_PATH',
|
||||
spack.build_environment.get_cmake_prefix_path(pkg))
|
||||
])
|
||||
# CMake's find_package() looks in CMAKE_PREFIX_PATH first, help CMake
|
||||
# to find immediate link dependencies in right places:
|
||||
deps = [d.prefix for d in
|
||||
pkg.spec.dependencies(deptype=('build', 'link'))]
|
||||
deps = filter_system_paths(deps)
|
||||
args.append(define('CMAKE_PREFIX_PATH', deps))
|
||||
return args
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
from spack.package import PackageBase
|
||||
from spack.directives import depends_on, variant, conflicts
|
||||
|
||||
import spack.variant
|
||||
from spack.directives import conflicts, depends_on, variant
|
||||
from spack.package import PackageBase
|
||||
|
||||
|
||||
class CudaPackage(PackageBase):
|
||||
@@ -79,47 +78,46 @@ def cuda_flags(arch_list):
|
||||
depends_on('cuda@11.0:', when='cuda_arch=80')
|
||||
depends_on('cuda@11.1:', when='cuda_arch=86')
|
||||
|
||||
# There are at least three cases to be aware of for compiler conflicts
|
||||
# 1. Linux x86_64
|
||||
# 2. Linux ppc64le
|
||||
# 3. Mac OS X
|
||||
# CUDA-compiler conflicts are version-to-version specific and are
|
||||
# difficult to express with the current Spack conflict syntax
|
||||
# From the NVIDIA install guide we know of conflicts for particular
|
||||
# platforms (linux, darwin), architectures (x86, powerpc) and compilers
|
||||
# (gcc, clang). We don't restrict %gcc and %clang conflicts to
|
||||
# platform=linux, since they should also apply to platform=cray, and may
|
||||
# apply to platform=darwin. We currently do not provide conflicts for
|
||||
# platform=darwin with %apple-clang.
|
||||
|
||||
# Linux x86_64 compiler conflicts from here:
|
||||
# https://gist.github.com/ax3l/9489132
|
||||
arch_platform = ' target=x86_64: platform=linux'
|
||||
conflicts('%gcc@5:', when='+cuda ^cuda@:7.5' + arch_platform)
|
||||
conflicts('%gcc@6:', when='+cuda ^cuda@:8' + arch_platform)
|
||||
conflicts('%gcc@7:', when='+cuda ^cuda@:9.1' + arch_platform)
|
||||
conflicts('%gcc@8:', when='+cuda ^cuda@:10.0.130' + arch_platform)
|
||||
conflicts('%gcc@9:', when='+cuda ^cuda@:10.2.89' + arch_platform)
|
||||
conflicts('%gcc@:4', when='+cuda ^cuda@11.0.2:' + arch_platform)
|
||||
conflicts('%gcc@10:', when='+cuda ^cuda@:11.0.2' + arch_platform)
|
||||
conflicts('%gcc@11:', when='+cuda ^cuda@:11.1.0' + arch_platform)
|
||||
conflicts('%pgi@:14.8', when='+cuda ^cuda@:7.0.27' + arch_platform)
|
||||
conflicts('%pgi@:15.3,15.5:', when='+cuda ^cuda@7.5' + arch_platform)
|
||||
conflicts('%pgi@:16.2,16.0:16.3', when='+cuda ^cuda@8' + arch_platform)
|
||||
conflicts('%pgi@:15,18:', when='+cuda ^cuda@9.0:9.1' + arch_platform)
|
||||
conflicts('%pgi@:16,19:', when='+cuda ^cuda@9.2.88:10' + arch_platform)
|
||||
conflicts('%gcc@5:', when='+cuda ^cuda@:7.5 target=x86_64:')
|
||||
conflicts('%gcc@6:', when='+cuda ^cuda@:8 target=x86_64:')
|
||||
conflicts('%gcc@7:', when='+cuda ^cuda@:9.1 target=x86_64:')
|
||||
conflicts('%gcc@8:', when='+cuda ^cuda@:10.0.130 target=x86_64:')
|
||||
conflicts('%gcc@9:', when='+cuda ^cuda@:10.2.89 target=x86_64:')
|
||||
conflicts('%gcc@:4', when='+cuda ^cuda@11.0.2: target=x86_64:')
|
||||
conflicts('%gcc@10:', when='+cuda ^cuda@:11.0.3 target=x86_64:')
|
||||
conflicts('%gcc@11:', when='+cuda ^cuda@:11.1.0 target=x86_64:')
|
||||
conflicts('%pgi@:14.8', when='+cuda ^cuda@:7.0.27 target=x86_64:')
|
||||
conflicts('%pgi@:15.3,15.5:', when='+cuda ^cuda@7.5 target=x86_64:')
|
||||
conflicts('%pgi@:16.2,16.0:16.3', when='+cuda ^cuda@8 target=x86_64:')
|
||||
conflicts('%pgi@:15,18:', when='+cuda ^cuda@9.0:9.1 target=x86_64:')
|
||||
conflicts('%pgi@:16,19:', when='+cuda ^cuda@9.2.88:10 target=x86_64:')
|
||||
conflicts('%pgi@:17,20:',
|
||||
when='+cuda ^cuda@10.1.105:10.2.89' + arch_platform)
|
||||
when='+cuda ^cuda@10.1.105:10.2.89 target=x86_64:')
|
||||
conflicts('%pgi@:17,21:',
|
||||
when='+cuda ^cuda@11.0.2:11.1.0' + arch_platform)
|
||||
conflicts('%clang@:3.4', when='+cuda ^cuda@:7.5' + arch_platform)
|
||||
when='+cuda ^cuda@11.0.2:11.1.0 target=x86_64:')
|
||||
conflicts('%clang@:3.4', when='+cuda ^cuda@:7.5 target=x86_64:')
|
||||
conflicts('%clang@:3.7,4:',
|
||||
when='+cuda ^cuda@8.0:9.0' + arch_platform)
|
||||
when='+cuda ^cuda@8.0:9.0 target=x86_64:')
|
||||
conflicts('%clang@:3.7,4.1:',
|
||||
when='+cuda ^cuda@9.1' + arch_platform)
|
||||
conflicts('%clang@:3.7,5.1:', when='+cuda ^cuda@9.2' + arch_platform)
|
||||
conflicts('%clang@:3.7,6.1:', when='+cuda ^cuda@10.0.130' + arch_platform)
|
||||
conflicts('%clang@:3.7,7.1:', when='+cuda ^cuda@10.1.105' + arch_platform)
|
||||
when='+cuda ^cuda@9.1 target=x86_64:')
|
||||
conflicts('%clang@:3.7,5.1:', when='+cuda ^cuda@9.2 target=x86_64:')
|
||||
conflicts('%clang@:3.7,6.1:', when='+cuda ^cuda@10.0.130 target=x86_64:')
|
||||
conflicts('%clang@:3.7,7.1:', when='+cuda ^cuda@10.1.105 target=x86_64:')
|
||||
conflicts('%clang@:3.7,8.1:',
|
||||
when='+cuda ^cuda@10.1.105:10.1.243' + arch_platform)
|
||||
conflicts('%clang@:3.2,9:', when='+cuda ^cuda@10.2.89' + arch_platform)
|
||||
conflicts('%clang@:5', when='+cuda ^cuda@11.0.2:' + arch_platform)
|
||||
conflicts('%clang@10:', when='+cuda ^cuda@:11.0.2' + arch_platform)
|
||||
conflicts('%clang@11:', when='+cuda ^cuda@:11.1.0' + arch_platform)
|
||||
when='+cuda ^cuda@10.1.105:10.1.243 target=x86_64:')
|
||||
conflicts('%clang@:3.2,9:', when='+cuda ^cuda@10.2.89 target=x86_64:')
|
||||
conflicts('%clang@:5', when='+cuda ^cuda@11.0.2: target=x86_64:')
|
||||
conflicts('%clang@10:', when='+cuda ^cuda@:11.0.3 target=x86_64:')
|
||||
conflicts('%clang@11:', when='+cuda ^cuda@:11.1.0 target=x86_64:')
|
||||
|
||||
# x86_64 vs. ppc64le differ according to NVidia docs
|
||||
# Linux ppc64le compiler conflicts from Table from the docs below:
|
||||
@@ -129,27 +127,26 @@ def cuda_flags(arch_list):
|
||||
# https://docs.nvidia.com/cuda/archive/9.0/cuda-installation-guide-linux/index.html
|
||||
# https://docs.nvidia.com/cuda/archive/8.0/cuda-installation-guide-linux/index.html
|
||||
|
||||
arch_platform = ' target=ppc64le: platform=linux'
|
||||
# information prior to CUDA 9 difficult to find
|
||||
conflicts('%gcc@6:', when='+cuda ^cuda@:9' + arch_platform)
|
||||
conflicts('%gcc@8:', when='+cuda ^cuda@:10.0.130' + arch_platform)
|
||||
conflicts('%gcc@9:', when='+cuda ^cuda@:10.1.243' + arch_platform)
|
||||
conflicts('%gcc@6:', when='+cuda ^cuda@:9 target=ppc64le:')
|
||||
conflicts('%gcc@8:', when='+cuda ^cuda@:10.0.130 target=ppc64le:')
|
||||
conflicts('%gcc@9:', when='+cuda ^cuda@:10.1.243 target=ppc64le:')
|
||||
# officially, CUDA 11.0.2 only supports the system GCC 8.3 on ppc64le
|
||||
conflicts('%gcc@:4', when='+cuda ^cuda@11.0.2:' + arch_platform)
|
||||
conflicts('%gcc@10:', when='+cuda ^cuda@:11.0.2' + arch_platform)
|
||||
conflicts('%gcc@11:', when='+cuda ^cuda@:11.1.0' + arch_platform)
|
||||
conflicts('%pgi', when='+cuda ^cuda@:8' + arch_platform)
|
||||
conflicts('%pgi@:16', when='+cuda ^cuda@:9.1.185' + arch_platform)
|
||||
conflicts('%pgi@:17', when='+cuda ^cuda@:10' + arch_platform)
|
||||
conflicts('%clang@4:', when='+cuda ^cuda@:9.0.176' + arch_platform)
|
||||
conflicts('%clang@5:', when='+cuda ^cuda@:9.1' + arch_platform)
|
||||
conflicts('%clang@6:', when='+cuda ^cuda@:9.2' + arch_platform)
|
||||
conflicts('%clang@7:', when='+cuda ^cuda@10.0.130' + arch_platform)
|
||||
conflicts('%clang@7.1:', when='+cuda ^cuda@:10.1.105' + arch_platform)
|
||||
conflicts('%clang@8.1:', when='+cuda ^cuda@:10.2.89' + arch_platform)
|
||||
conflicts('%clang@:5', when='+cuda ^cuda@11.0.2:' + arch_platform)
|
||||
conflicts('%clang@10:', when='+cuda ^cuda@:11.0.2' + arch_platform)
|
||||
conflicts('%clang@11:', when='+cuda ^cuda@:11.1.0' + arch_platform)
|
||||
conflicts('%gcc@:4', when='+cuda ^cuda@11.0.2: target=ppc64le:')
|
||||
conflicts('%gcc@10:', when='+cuda ^cuda@:11.0.3 target=ppc64le:')
|
||||
conflicts('%gcc@11:', when='+cuda ^cuda@:11.1.0 target=ppc64le:')
|
||||
conflicts('%pgi', when='+cuda ^cuda@:8 target=ppc64le:')
|
||||
conflicts('%pgi@:16', when='+cuda ^cuda@:9.1.185 target=ppc64le:')
|
||||
conflicts('%pgi@:17', when='+cuda ^cuda@:10 target=ppc64le:')
|
||||
conflicts('%clang@4:', when='+cuda ^cuda@:9.0.176 target=ppc64le:')
|
||||
conflicts('%clang@5:', when='+cuda ^cuda@:9.1 target=ppc64le:')
|
||||
conflicts('%clang@6:', when='+cuda ^cuda@:9.2 target=ppc64le:')
|
||||
conflicts('%clang@7:', when='+cuda ^cuda@10.0.130 target=ppc64le:')
|
||||
conflicts('%clang@7.1:', when='+cuda ^cuda@:10.1.105 target=ppc64le:')
|
||||
conflicts('%clang@8.1:', when='+cuda ^cuda@:10.2.89 target=ppc64le:')
|
||||
conflicts('%clang@:5', when='+cuda ^cuda@11.0.2: target=ppc64le:')
|
||||
conflicts('%clang@10:', when='+cuda ^cuda@:11.0.3 target=ppc64le:')
|
||||
conflicts('%clang@11:', when='+cuda ^cuda@:11.1.0 target=ppc64le:')
|
||||
|
||||
# Intel is mostly relevant for x86_64 Linux, even though it also
|
||||
# exists for Mac OS X. No information prior to CUDA 3.2 or Intel 11.1
|
||||
@@ -171,15 +168,8 @@ def cuda_flags(arch_list):
|
||||
conflicts('%xl@:12,14:15,17:', when='+cuda ^cuda@9.2')
|
||||
conflicts('%xl@:12,17:', when='+cuda ^cuda@:11.1.0')
|
||||
|
||||
# Mac OS X
|
||||
# platform = ' platform=darwin'
|
||||
# Apple XCode clang vs. LLVM clang are difficult to specify
|
||||
# with spack syntax. Xcode clang name is `clang@x.y.z-apple`
|
||||
# which precludes ranges being specified. We have proposed
|
||||
# rename XCode clang to `clang@apple-x.y.z` or even
|
||||
# `clang-apple@x.y.z as a possible fix.
|
||||
# Compiler conflicts will be eventual taken from here:
|
||||
# https://docs.nvidia.com/cuda/cuda-installation-guide-mac-os-x/index.html#abstract
|
||||
# Darwin.
|
||||
# TODO: add missing conflicts for %apple-clang cuda@:10
|
||||
conflicts('platform=darwin', when='+cuda ^cuda@11.0.2:')
|
||||
|
||||
# Make sure cuda_arch can not be used without +cuda
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import spack.util.url
|
||||
import spack.package
|
||||
import spack.util.url
|
||||
|
||||
|
||||
class GNUMirrorPackage(spack.package.PackageBase):
|
||||
|
||||
@@ -4,26 +4,32 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
import tempfile
|
||||
import re
|
||||
import inspect
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import (
|
||||
HeaderList,
|
||||
LibraryList,
|
||||
ancestor,
|
||||
filter_file,
|
||||
find_headers,
|
||||
find_libraries,
|
||||
find_system_libraries,
|
||||
install,
|
||||
)
|
||||
|
||||
from llnl.util.filesystem import \
|
||||
install, ancestor, filter_file, \
|
||||
HeaderList, find_headers, \
|
||||
LibraryList, find_libraries, find_system_libraries
|
||||
|
||||
from spack.version import Version, ver
|
||||
from spack.package import PackageBase, run_after, InstallError
|
||||
from spack.build_environment import dso_suffix
|
||||
from spack.package import InstallError, PackageBase, run_after
|
||||
from spack.util.environment import EnvironmentModifications
|
||||
from spack.util.executable import Executable
|
||||
from spack.util.prefix import Prefix
|
||||
from spack.build_environment import dso_suffix
|
||||
from spack.version import Version, ver
|
||||
|
||||
# A couple of utility functions that might be useful in general. If so, they
|
||||
# should really be defined elsewhere, unless deemed heretical.
|
||||
@@ -1089,7 +1095,7 @@ def _setup_dependent_env_callback(
|
||||
# Intel MPI since 2019 depends on libfabric which is not in the
|
||||
# lib directory but in a directory of its own which should be
|
||||
# included in the rpath
|
||||
if self.version >= ver('2019'):
|
||||
if self.version_yearlike >= ver('2019'):
|
||||
d = ancestor(self.component_lib_dir('mpi'))
|
||||
libfabrics_path = os.path.join(d, 'libfabric', 'lib')
|
||||
env.append_path('SPACK_COMPILER_EXTRA_RPATHS',
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import working_dir
|
||||
|
||||
from spack.package import PackageBase, run_after
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
|
||||
from llnl.util.filesystem import install_tree, working_dir
|
||||
|
||||
from spack.directives import depends_on
|
||||
from spack.package import PackageBase, run_after
|
||||
from spack.util.executable import which
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
from typing import List # novm
|
||||
|
||||
from llnl.util.filesystem import working_dir
|
||||
|
||||
from spack.directives import depends_on, variant
|
||||
from spack.package import PackageBase, run_after
|
||||
|
||||
@@ -55,9 +56,8 @@ class MesonPackage(PackageBase):
|
||||
variant('buildtype', default='debugoptimized',
|
||||
description='Meson build type',
|
||||
values=('plain', 'debug', 'debugoptimized', 'release', 'minsize'))
|
||||
variant('default_library', default='shared',
|
||||
description=' Default library type',
|
||||
values=('shared', 'static', 'both'))
|
||||
variant('default_library', default='shared', values=('shared', 'static'),
|
||||
multi=True, description='Build shared libs, static libs or both')
|
||||
variant('strip', default=False, description='Strip targets on install')
|
||||
|
||||
depends_on('meson', type='build')
|
||||
@@ -102,9 +102,11 @@ def _std_args(pkg):
|
||||
|
||||
strip = 'true' if '+strip' in pkg.spec else 'false'
|
||||
|
||||
try:
|
||||
default_library = pkg.spec.variants['default_library'].value
|
||||
except KeyError:
|
||||
if 'default_library=static,shared' in pkg.spec:
|
||||
default_library = 'both'
|
||||
elif 'default_library=static' in pkg.spec:
|
||||
default_library = 'static'
|
||||
else:
|
||||
default_library = 'shared'
|
||||
|
||||
args = [
|
||||
|
||||
@@ -8,16 +8,16 @@
|
||||
"""
|
||||
|
||||
import getpass
|
||||
import platform
|
||||
import shutil
|
||||
from sys import platform
|
||||
from os.path import basename, dirname, isdir
|
||||
|
||||
from llnl.util.filesystem import find_headers, find_libraries, join_path
|
||||
|
||||
from spack.package import Package
|
||||
from spack.util.environment import EnvironmentModifications
|
||||
from spack.util.executable import Executable
|
||||
|
||||
from llnl.util.filesystem import find_headers, find_libraries, join_path
|
||||
|
||||
|
||||
class IntelOneApiPackage(Package):
|
||||
"""Base class for Intel oneAPI packages."""
|
||||
@@ -48,7 +48,7 @@ def install(self, spec, prefix, installer_path=None):
|
||||
if installer_path is None:
|
||||
installer_path = basename(self.url_for_version(spec.version))
|
||||
|
||||
if platform == 'linux':
|
||||
if platform.system() == 'Linux':
|
||||
# Intel installer assumes and enforces that all components
|
||||
# are installed into a single prefix. Spack wants to
|
||||
# install each component in a separate prefix. The
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
import inspect
|
||||
import os
|
||||
|
||||
from llnl.util.filesystem import filter_file
|
||||
|
||||
from spack.directives import extends
|
||||
from spack.package import PackageBase, run_after
|
||||
from spack.util.executable import Executable
|
||||
from llnl.util.filesystem import filter_file
|
||||
|
||||
|
||||
class PerlPackage(PackageBase):
|
||||
|
||||
@@ -6,14 +6,20 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import (
|
||||
filter_file,
|
||||
find,
|
||||
get_filetype,
|
||||
path_contains_subdirectory,
|
||||
same_path,
|
||||
working_dir,
|
||||
)
|
||||
from llnl.util.lang import match_predicate
|
||||
|
||||
from spack.directives import extends
|
||||
from spack.package import PackageBase, run_after
|
||||
|
||||
from llnl.util.filesystem import (working_dir, get_filetype, filter_file,
|
||||
path_contains_subdirectory, same_path, find)
|
||||
from llnl.util.lang import match_predicate
|
||||
import llnl.util.tty as tty
|
||||
|
||||
|
||||
class PythonPackage(PackageBase):
|
||||
"""Specialized class for packages that are built using Python
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import inspect
|
||||
|
||||
from llnl.util.filesystem import working_dir
|
||||
|
||||
from spack.directives import depends_on
|
||||
from spack.package import PackageBase, run_after
|
||||
|
||||
|
||||
@@ -75,10 +75,9 @@
|
||||
# does not like its directory structure.
|
||||
#
|
||||
|
||||
from spack.package import PackageBase
|
||||
from spack.directives import depends_on, variant, conflicts
|
||||
|
||||
import spack.variant
|
||||
from spack.directives import conflicts, depends_on, variant
|
||||
from spack.package import PackageBase
|
||||
|
||||
|
||||
class ROCmPackage(PackageBase):
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
import inspect
|
||||
import os
|
||||
|
||||
from llnl.util.filesystem import find, working_dir, join_path
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import find, join_path, working_dir
|
||||
|
||||
from spack.directives import depends_on, extends
|
||||
from spack.package import PackageBase, run_after
|
||||
import llnl.util.tty as tty
|
||||
|
||||
|
||||
class SIPPackage(PackageBase):
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import spack.util.url
|
||||
import spack.package
|
||||
import spack.util.url
|
||||
|
||||
|
||||
class SourceforgePackage(spack.package.PackageBase):
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import spack.util.url
|
||||
import spack.package
|
||||
import spack.util.url
|
||||
|
||||
|
||||
class SourcewarePackage(spack.package.PackageBase):
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
import inspect
|
||||
|
||||
from llnl.util.filesystem import working_dir
|
||||
|
||||
from spack.directives import depends_on
|
||||
from spack.package import PackageBase, run_after
|
||||
|
||||
from llnl.util.filesystem import working_dir
|
||||
|
||||
|
||||
class WafPackage(PackageBase):
|
||||
"""Specialized class for packages that are built using the
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import spack.util.url
|
||||
import spack.package
|
||||
import spack.util.url
|
||||
|
||||
|
||||
class XorgPackage(spack.package.PackageBase):
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
import llnl.util.lang
|
||||
from llnl.util.filesystem import mkdirp
|
||||
|
||||
import spack.error
|
||||
import spack.paths
|
||||
import spack.config
|
||||
import spack.error
|
||||
import spack.fetch_strategy
|
||||
import spack.paths
|
||||
import spack.util.file_cache
|
||||
import spack.util.path
|
||||
|
||||
|
||||
@@ -10,14 +10,16 @@
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import stat
|
||||
import tempfile
|
||||
import zlib
|
||||
import zipfile
|
||||
|
||||
from six import iteritems
|
||||
from six.moves.urllib.error import HTTPError, URLError
|
||||
from six.moves.urllib.parse import urlencode
|
||||
from six.moves.urllib.request import build_opener, HTTPHandler, Request
|
||||
from six.moves.urllib.request import HTTPHandler, Request, build_opener
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack
|
||||
@@ -26,16 +28,17 @@
|
||||
import spack.compilers as compilers
|
||||
import spack.config as cfg
|
||||
import spack.environment as ev
|
||||
from spack.error import SpackError
|
||||
import spack.hash_types as ht
|
||||
import spack.main
|
||||
import spack.mirror
|
||||
import spack.paths
|
||||
import spack.repo
|
||||
from spack.spec import Spec
|
||||
import spack.util.spack_yaml as syaml
|
||||
import spack.util.web as web_util
|
||||
import spack.util.executable as exe
|
||||
import spack.util.gpg as gpg_util
|
||||
import spack.util.spack_yaml as syaml
|
||||
import spack.util.url as url_util
|
||||
|
||||
import spack.util.web as web_util
|
||||
from spack.error import SpackError
|
||||
from spack.spec import Spec
|
||||
|
||||
JOB_RETRY_CONDITIONS = [
|
||||
'always',
|
||||
@@ -77,7 +80,8 @@ def _create_buildgroup(opener, headers, url, project, group_name, group_type):
|
||||
if response_code != 200 and response_code != 201:
|
||||
msg = 'Creating buildgroup failed (response code = {0}'.format(
|
||||
response_code)
|
||||
raise SpackError(msg)
|
||||
tty.warn(msg)
|
||||
return None
|
||||
|
||||
response_text = response.read()
|
||||
response_json = json.loads(response_text)
|
||||
@@ -106,7 +110,8 @@ def populate_buildgroup(job_names, group_name, project, site,
|
||||
if not parent_group_id or not group_id:
|
||||
msg = 'Failed to create or retrieve buildgroups for {0}'.format(
|
||||
group_name)
|
||||
raise SpackError(msg)
|
||||
tty.warn(msg)
|
||||
return
|
||||
|
||||
data = {
|
||||
'project': project,
|
||||
@@ -129,7 +134,7 @@ def populate_buildgroup(job_names, group_name, project, site,
|
||||
if response_code != 200:
|
||||
msg = 'Error response code ({0}) in populate_buildgroup'.format(
|
||||
response_code)
|
||||
raise SpackError(msg)
|
||||
tty.warn(msg)
|
||||
|
||||
|
||||
def is_main_phase(phase_name):
|
||||
@@ -197,10 +202,7 @@ def format_root_spec(spec, main_phase, strip_compiler):
|
||||
return '{0}@{1} arch={2}'.format(
|
||||
spec.name, spec.version, spec.architecture)
|
||||
else:
|
||||
spec_yaml = spec.to_yaml(hash=ht.build_hash).encode('utf-8')
|
||||
return str(base64.b64encode(zlib.compress(spec_yaml)).decode('utf-8'))
|
||||
# return '{0}@{1}%{2} arch={3}'.format(
|
||||
# spec.name, spec.version, spec.compiler, spec.architecture)
|
||||
return spec.build_hash()
|
||||
|
||||
|
||||
def spec_deps_key(s):
|
||||
@@ -506,35 +508,21 @@ def format_job_needs(phase_name, strip_compilers, dep_jobs,
|
||||
'job': get_job_name(phase_name,
|
||||
strip_compilers,
|
||||
dep_job,
|
||||
osname,
|
||||
dep_job.architecture,
|
||||
build_group),
|
||||
'artifacts': enable_artifacts_buildcache,
|
||||
})
|
||||
return needs_list
|
||||
|
||||
|
||||
def add_pr_mirror(url):
|
||||
cfg_scope = cfg.default_modify_scope()
|
||||
mirrors = cfg.get('mirrors', scope=cfg_scope)
|
||||
items = [(n, u) for n, u in mirrors.items()]
|
||||
items.insert(0, ('ci_pr_mirror', url))
|
||||
cfg.set('mirrors', syaml.syaml_dict(items), scope=cfg_scope)
|
||||
|
||||
|
||||
def remove_pr_mirror():
|
||||
cfg_scope = cfg.default_modify_scope()
|
||||
mirrors = cfg.get('mirrors', scope=cfg_scope)
|
||||
mirrors.pop('ci_pr_mirror')
|
||||
cfg.set('mirrors', mirrors, scope=cfg_scope)
|
||||
|
||||
|
||||
def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
check_index_only=False, run_optimizer=False,
|
||||
use_dependencies=False):
|
||||
# FIXME: What's the difference between one that opens with 'spack'
|
||||
# and one that opens with 'env'? This will only handle the former.
|
||||
def generate_gitlab_ci_yaml(env, print_summary, output_file,
|
||||
prune_dag=False, check_index_only=False,
|
||||
run_optimizer=False, use_dependencies=False,
|
||||
artifacts_root=None):
|
||||
with spack.concretize.disable_compiler_existence_check():
|
||||
env.concretize()
|
||||
with env.write_transaction():
|
||||
env.concretize()
|
||||
env.write()
|
||||
|
||||
yaml_root = ev.config_dict(env.yaml)
|
||||
|
||||
@@ -559,9 +547,11 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
tty.verbose("Using CDash auth token from environment")
|
||||
cdash_auth_token = os.environ.get('SPACK_CDASH_AUTH_TOKEN')
|
||||
|
||||
is_pr_pipeline = (
|
||||
os.environ.get('SPACK_IS_PR_PIPELINE', '').lower() == 'true'
|
||||
)
|
||||
generate_job_name = os.environ.get('CI_JOB_NAME', None)
|
||||
parent_pipeline_id = os.environ.get('CI_PIPELINE_ID', None)
|
||||
|
||||
spack_pipeline_type = os.environ.get('SPACK_PIPELINE_TYPE', None)
|
||||
is_pr_pipeline = spack_pipeline_type == 'spack_pull_request'
|
||||
|
||||
spack_pr_branch = os.environ.get('SPACK_PR_BRANCH', None)
|
||||
pr_mirror_url = None
|
||||
@@ -574,6 +564,7 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
|
||||
ci_mirrors = yaml_root['mirrors']
|
||||
mirror_urls = [url for url in ci_mirrors.values()]
|
||||
remote_mirror_url = mirror_urls[0]
|
||||
|
||||
# Check for a list of "known broken" specs that we should not bother
|
||||
# trying to build.
|
||||
@@ -624,7 +615,51 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
# Add this mirror if it's enabled, as some specs might be up to date
|
||||
# here and thus not need to be rebuilt.
|
||||
if pr_mirror_url:
|
||||
add_pr_mirror(pr_mirror_url)
|
||||
spack.mirror.add(
|
||||
'ci_pr_mirror', pr_mirror_url, cfg.default_modify_scope())
|
||||
|
||||
pipeline_artifacts_dir = artifacts_root
|
||||
if not pipeline_artifacts_dir:
|
||||
proj_dir = os.environ.get('CI_PROJECT_DIR', os.getcwd())
|
||||
pipeline_artifacts_dir = os.path.join(proj_dir, 'jobs_scratch_dir')
|
||||
|
||||
pipeline_artifacts_dir = os.path.abspath(pipeline_artifacts_dir)
|
||||
concrete_env_dir = os.path.join(
|
||||
pipeline_artifacts_dir, 'concrete_environment')
|
||||
|
||||
# Now that we've added the mirrors we know about, they should be properly
|
||||
# reflected in the environment manifest file, so copy that into the
|
||||
# concrete environment directory, along with the spack.lock file.
|
||||
if not os.path.exists(concrete_env_dir):
|
||||
os.makedirs(concrete_env_dir)
|
||||
shutil.copyfile(env.manifest_path,
|
||||
os.path.join(concrete_env_dir, 'spack.yaml'))
|
||||
shutil.copyfile(env.lock_path,
|
||||
os.path.join(concrete_env_dir, 'spack.lock'))
|
||||
|
||||
job_log_dir = os.path.join(pipeline_artifacts_dir, 'logs')
|
||||
job_repro_dir = os.path.join(pipeline_artifacts_dir, 'reproduction')
|
||||
local_mirror_dir = os.path.join(pipeline_artifacts_dir, 'mirror')
|
||||
user_artifacts_dir = os.path.join(pipeline_artifacts_dir, 'user_data')
|
||||
|
||||
# We communicate relative paths to the downstream jobs to avoid issues in
|
||||
# situations where the CI_PROJECT_DIR varies between the pipeline
|
||||
# generation job and the rebuild jobs. This can happen when gitlab
|
||||
# checks out the project into a runner-specific directory, for example,
|
||||
# and different runners are picked for generate and rebuild jobs.
|
||||
ci_project_dir = os.environ.get('CI_PROJECT_DIR')
|
||||
rel_artifacts_root = os.path.relpath(
|
||||
pipeline_artifacts_dir, ci_project_dir)
|
||||
rel_concrete_env_dir = os.path.relpath(
|
||||
concrete_env_dir, ci_project_dir)
|
||||
rel_job_log_dir = os.path.relpath(
|
||||
job_log_dir, ci_project_dir)
|
||||
rel_job_repro_dir = os.path.relpath(
|
||||
job_repro_dir, ci_project_dir)
|
||||
rel_local_mirror_dir = os.path.relpath(
|
||||
local_mirror_dir, ci_project_dir)
|
||||
rel_user_artifacts_dir = os.path.relpath(
|
||||
user_artifacts_dir, ci_project_dir)
|
||||
|
||||
# Speed up staging by first fetching binary indices from all mirrors
|
||||
# (including the per-PR mirror we may have just added above).
|
||||
@@ -641,7 +676,7 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
finally:
|
||||
# Clean up PR mirror if enabled
|
||||
if pr_mirror_url:
|
||||
remove_pr_mirror()
|
||||
spack.mirror.remove('ci_pr_mirror', cfg.default_modify_scope())
|
||||
|
||||
all_job_names = []
|
||||
output_object = {}
|
||||
@@ -671,14 +706,9 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
root_spec = spec_record['rootSpec']
|
||||
pkg_name = pkg_name_from_spec_label(spec_label)
|
||||
release_spec = root_spec[pkg_name]
|
||||
|
||||
# Check if this spec is in our list of known failures.
|
||||
if broken_specs_url:
|
||||
full_hash = release_spec.full_hash()
|
||||
broken_spec_path = url_util.join(broken_specs_url, full_hash)
|
||||
if web_util.url_exists(broken_spec_path):
|
||||
known_broken_specs_encountered.append('{0} ({1})'.format(
|
||||
release_spec, full_hash))
|
||||
release_spec_full_hash = release_spec.full_hash()
|
||||
release_spec_dag_hash = release_spec.dag_hash()
|
||||
release_spec_build_hash = release_spec.build_hash()
|
||||
|
||||
runner_attribs = find_matching_config(
|
||||
release_spec, gitlab_ci)
|
||||
@@ -705,10 +735,15 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
except AttributeError:
|
||||
image_name = build_image
|
||||
|
||||
job_script = [
|
||||
'spack env activate --without-view .',
|
||||
'spack ci rebuild',
|
||||
]
|
||||
job_script = ['spack env activate --without-view .']
|
||||
|
||||
if artifacts_root:
|
||||
job_script.insert(0, 'cd {0}'.format(concrete_env_dir))
|
||||
|
||||
job_script.extend([
|
||||
'spack ci rebuild'
|
||||
])
|
||||
|
||||
if 'script' in runner_attribs:
|
||||
job_script = [s for s in runner_attribs['script']]
|
||||
|
||||
@@ -735,9 +770,11 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
job_vars = {
|
||||
'SPACK_ROOT_SPEC': format_root_spec(
|
||||
root_spec, main_phase, strip_compilers),
|
||||
'SPACK_JOB_SPEC_DAG_HASH': release_spec_dag_hash,
|
||||
'SPACK_JOB_SPEC_BUILD_HASH': release_spec_build_hash,
|
||||
'SPACK_JOB_SPEC_FULL_HASH': release_spec_full_hash,
|
||||
'SPACK_JOB_SPEC_PKG_NAME': release_spec.name,
|
||||
'SPACK_COMPILER_ACTION': compiler_action,
|
||||
'SPACK_IS_PR_PIPELINE': str(is_pr_pipeline),
|
||||
'SPACK_COMPILER_ACTION': compiler_action
|
||||
}
|
||||
|
||||
job_dependencies = []
|
||||
@@ -836,6 +873,21 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
if prune_dag and not rebuild_spec:
|
||||
continue
|
||||
|
||||
# Check if this spec is in our list of known failures, now that
|
||||
# we know this spec needs a rebuild
|
||||
if broken_specs_url:
|
||||
broken_spec_path = url_util.join(
|
||||
broken_specs_url, release_spec_full_hash)
|
||||
if web_util.url_exists(broken_spec_path):
|
||||
known_broken_specs_encountered.append('{0} ({1})'.format(
|
||||
release_spec, release_spec_full_hash))
|
||||
|
||||
if artifacts_root:
|
||||
job_dependencies.append({
|
||||
'job': generate_job_name,
|
||||
'pipeline': '{0}'.format(parent_pipeline_id)
|
||||
})
|
||||
|
||||
job_vars['SPACK_SPEC_NEEDS_REBUILD'] = str(rebuild_spec)
|
||||
|
||||
if enable_cdash_reporting:
|
||||
@@ -856,12 +908,14 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
variables.update(job_vars)
|
||||
|
||||
artifact_paths = [
|
||||
'jobs_scratch_dir',
|
||||
'cdash_report',
|
||||
rel_job_log_dir,
|
||||
rel_job_repro_dir,
|
||||
rel_user_artifacts_dir
|
||||
]
|
||||
|
||||
if enable_artifacts_buildcache:
|
||||
bc_root = 'local_mirror/build_cache'
|
||||
bc_root = os.path.join(
|
||||
local_mirror_dir, 'build_cache')
|
||||
artifact_paths.extend([os.path.join(bc_root, p) for p in [
|
||||
bindist.tarball_name(release_spec, '.spec.yaml'),
|
||||
bindist.tarball_name(release_spec, '.cdashid'),
|
||||
@@ -987,6 +1041,11 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
]
|
||||
final_job['when'] = 'always'
|
||||
|
||||
if artifacts_root:
|
||||
final_job['variables'] = {
|
||||
'SPACK_CONCRETE_ENV_DIR': concrete_env_dir
|
||||
}
|
||||
|
||||
output_object['rebuild-index'] = final_job
|
||||
|
||||
output_object['stages'] = stage_names
|
||||
@@ -1007,8 +1066,15 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file, prune_dag=False,
|
||||
version_to_clone = spack_version
|
||||
|
||||
output_object['variables'] = {
|
||||
'SPACK_ARTIFACTS_ROOT': rel_artifacts_root,
|
||||
'SPACK_CONCRETE_ENV_DIR': rel_concrete_env_dir,
|
||||
'SPACK_VERSION': spack_version,
|
||||
'SPACK_CHECKOUT_VERSION': version_to_clone,
|
||||
'SPACK_REMOTE_MIRROR_URL': remote_mirror_url,
|
||||
'SPACK_JOB_LOG_DIR': rel_job_log_dir,
|
||||
'SPACK_JOB_REPRO_DIR': rel_job_repro_dir,
|
||||
'SPACK_LOCAL_MIRROR_DIR': rel_local_mirror_dir,
|
||||
'SPACK_PIPELINE_TYPE': str(spack_pipeline_type)
|
||||
}
|
||||
|
||||
if pr_mirror_url:
|
||||
@@ -1131,7 +1197,8 @@ def configure_compilers(compiler_action, scope=None):
|
||||
return None
|
||||
|
||||
|
||||
def get_concrete_specs(root_spec, job_name, related_builds, compiler_action):
|
||||
def get_concrete_specs(env, root_spec, job_name, related_builds,
|
||||
compiler_action):
|
||||
spec_map = {
|
||||
'root': None,
|
||||
'deps': {},
|
||||
@@ -1153,8 +1220,7 @@ def get_concrete_specs(root_spec, job_name, related_builds, compiler_action):
|
||||
# again. The reason we take this path in the first case (bootstrapped
|
||||
# compiler), is that we can't concretize a spec at this point if we're
|
||||
# going to ask spack to "install_missing_compilers".
|
||||
concrete_root = Spec.from_yaml(
|
||||
str(zlib.decompress(base64.b64decode(root_spec)).decode('utf-8')))
|
||||
concrete_root = env.specs_by_hash[root_spec]
|
||||
|
||||
spec_map['root'] = concrete_root
|
||||
spec_map[job_name] = concrete_root[job_name]
|
||||
@@ -1195,7 +1261,8 @@ def register_cdash_build(build_name, base_url, project, site, track):
|
||||
|
||||
if response_code != 200 and response_code != 201:
|
||||
msg = 'Adding build failed (response code = {0}'.format(response_code)
|
||||
raise SpackError(msg)
|
||||
tty.warn(msg)
|
||||
return (None, None)
|
||||
|
||||
response_text = response.read()
|
||||
response_json = json.loads(response_text)
|
||||
@@ -1205,7 +1272,7 @@ def register_cdash_build(build_name, base_url, project, site, track):
|
||||
|
||||
|
||||
def relate_cdash_builds(spec_map, cdash_base_url, job_build_id, cdash_project,
|
||||
cdashids_mirror_url):
|
||||
cdashids_mirror_urls):
|
||||
if not job_build_id:
|
||||
return
|
||||
|
||||
@@ -1221,7 +1288,20 @@ def relate_cdash_builds(spec_map, cdash_base_url, job_build_id, cdash_project,
|
||||
for dep_pkg_name in dep_map:
|
||||
tty.debug('Fetching cdashid file for {0}'.format(dep_pkg_name))
|
||||
dep_spec = dep_map[dep_pkg_name]
|
||||
dep_build_id = read_cdashid_from_mirror(dep_spec, cdashids_mirror_url)
|
||||
dep_build_id = None
|
||||
|
||||
for url in cdashids_mirror_urls:
|
||||
try:
|
||||
if url:
|
||||
dep_build_id = read_cdashid_from_mirror(dep_spec, url)
|
||||
break
|
||||
except web_util.SpackWebError:
|
||||
tty.debug('Did not find cdashid for {0} on {1}'.format(
|
||||
dep_pkg_name, url))
|
||||
else:
|
||||
tty.warn('Did not find cdashid for {0} anywhere'.format(
|
||||
dep_pkg_name))
|
||||
return
|
||||
|
||||
payload = {
|
||||
"project": cdash_project,
|
||||
@@ -1242,7 +1322,8 @@ def relate_cdash_builds(spec_map, cdash_base_url, job_build_id, cdash_project,
|
||||
if response_code != 200 and response_code != 201:
|
||||
msg = 'Relate builds ({0} -> {1}) failed (resp code = {2})'.format(
|
||||
job_build_id, dep_build_id, response_code)
|
||||
raise SpackError(msg)
|
||||
tty.warn(msg)
|
||||
return
|
||||
|
||||
response_text = response.read()
|
||||
tty.debug('Relate builds response: {0}'.format(response_text))
|
||||
@@ -1265,7 +1346,16 @@ def write_cdashid_to_mirror(cdashid, spec, mirror_url):
|
||||
tty.debug('pushing cdashid to url')
|
||||
tty.debug(' local file path: {0}'.format(local_cdash_path))
|
||||
tty.debug(' remote url: {0}'.format(remote_url))
|
||||
web_util.push_to_url(local_cdash_path, remote_url)
|
||||
|
||||
try:
|
||||
web_util.push_to_url(local_cdash_path, remote_url)
|
||||
except Exception as inst:
|
||||
# No matter what went wrong here, don't allow the pipeline to fail
|
||||
# just because there was an issue storing the cdashid on the mirror
|
||||
msg = 'Failed to write cdashid {0} to mirror {1}'.format(
|
||||
cdashid, mirror_url)
|
||||
tty.warn(inst)
|
||||
tty.warn(msg)
|
||||
|
||||
|
||||
def read_cdashid_from_mirror(spec, mirror_url):
|
||||
@@ -1283,40 +1373,34 @@ def read_cdashid_from_mirror(spec, mirror_url):
|
||||
return int(contents)
|
||||
|
||||
|
||||
def push_mirror_contents(env, spec, yaml_path, mirror_url, build_id,
|
||||
sign_binaries):
|
||||
if mirror_url:
|
||||
try:
|
||||
unsigned = not sign_binaries
|
||||
tty.debug('Creating buildcache ({0})'.format(
|
||||
'unsigned' if unsigned else 'signed'))
|
||||
spack.cmd.buildcache._createtarball(
|
||||
env, spec_yaml=yaml_path, add_deps=False,
|
||||
output_location=mirror_url, force=True, allow_root=True,
|
||||
unsigned=unsigned)
|
||||
if build_id:
|
||||
tty.debug('Writing cdashid ({0}) to remote mirror: {1}'.format(
|
||||
build_id, mirror_url))
|
||||
write_cdashid_to_mirror(build_id, spec, mirror_url)
|
||||
except Exception as inst:
|
||||
# If the mirror we're pushing to is on S3 and there's some
|
||||
# permissions problem, for example, we can't just target
|
||||
# that exception type here, since users of the
|
||||
# `spack ci rebuild' may not need or want any dependency
|
||||
# on boto3. So we use the first non-boto exception type
|
||||
# in the heirarchy:
|
||||
# boto3.exceptions.S3UploadFailedError
|
||||
# boto3.exceptions.Boto3Error
|
||||
# Exception
|
||||
# BaseException
|
||||
# object
|
||||
err_msg = 'Error msg: {0}'.format(inst)
|
||||
if 'Access Denied' in err_msg:
|
||||
tty.msg('Permission problem writing to {0}'.format(
|
||||
mirror_url))
|
||||
tty.msg(err_msg)
|
||||
else:
|
||||
raise inst
|
||||
def push_mirror_contents(env, spec, yaml_path, mirror_url, sign_binaries):
|
||||
try:
|
||||
unsigned = not sign_binaries
|
||||
tty.debug('Creating buildcache ({0})'.format(
|
||||
'unsigned' if unsigned else 'signed'))
|
||||
spack.cmd.buildcache._createtarball(
|
||||
env, spec_yaml=yaml_path, add_deps=False,
|
||||
output_location=mirror_url, force=True, allow_root=True,
|
||||
unsigned=unsigned)
|
||||
except Exception as inst:
|
||||
# If the mirror we're pushing to is on S3 and there's some
|
||||
# permissions problem, for example, we can't just target
|
||||
# that exception type here, since users of the
|
||||
# `spack ci rebuild' may not need or want any dependency
|
||||
# on boto3. So we use the first non-boto exception type
|
||||
# in the heirarchy:
|
||||
# boto3.exceptions.S3UploadFailedError
|
||||
# boto3.exceptions.Boto3Error
|
||||
# Exception
|
||||
# BaseException
|
||||
# object
|
||||
err_msg = 'Error msg: {0}'.format(inst)
|
||||
if 'Access Denied' in err_msg:
|
||||
tty.msg('Permission problem writing to {0}'.format(
|
||||
mirror_url))
|
||||
tty.msg(err_msg)
|
||||
else:
|
||||
raise inst
|
||||
|
||||
|
||||
def copy_stage_logs_to_artifacts(job_spec, job_log_dir):
|
||||
@@ -1335,3 +1419,307 @@ def copy_stage_logs_to_artifacts(job_spec, job_log_dir):
|
||||
msg = ('Unable to copy build logs from stage to artifacts '
|
||||
'due to exception: {0}').format(inst)
|
||||
tty.error(msg)
|
||||
|
||||
|
||||
def download_and_extract_artifacts(url, work_dir):
|
||||
tty.msg('Fetching artifacts from: {0}\n'.format(url))
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/zip',
|
||||
}
|
||||
|
||||
token = os.environ.get('GITLAB_PRIVATE_TOKEN', None)
|
||||
if token:
|
||||
headers['PRIVATE-TOKEN'] = token
|
||||
|
||||
opener = build_opener(HTTPHandler)
|
||||
|
||||
request = Request(url, headers=headers)
|
||||
request.get_method = lambda: 'GET'
|
||||
|
||||
response = opener.open(request)
|
||||
response_code = response.getcode()
|
||||
|
||||
if response_code != 200:
|
||||
msg = 'Error response code ({0}) in reproduce_ci_job'.format(
|
||||
response_code)
|
||||
raise SpackError(msg)
|
||||
|
||||
artifacts_zip_path = os.path.join(work_dir, 'artifacts.zip')
|
||||
|
||||
if not os.path.exists(work_dir):
|
||||
os.makedirs(work_dir)
|
||||
|
||||
with open(artifacts_zip_path, 'wb') as out_file:
|
||||
shutil.copyfileobj(response, out_file)
|
||||
|
||||
zip_file = zipfile.ZipFile(artifacts_zip_path)
|
||||
zip_file.extractall(work_dir)
|
||||
zip_file.close()
|
||||
|
||||
os.remove(artifacts_zip_path)
|
||||
|
||||
|
||||
def get_spack_info():
|
||||
git_path = os.path.join(spack.paths.prefix, ".git")
|
||||
if os.path.exists(git_path):
|
||||
git = exe.which("git")
|
||||
if git:
|
||||
with fs.working_dir(spack.paths.prefix):
|
||||
git_log = git("log", "-1",
|
||||
output=str, error=os.devnull,
|
||||
fail_on_error=False)
|
||||
|
||||
return git_log
|
||||
|
||||
return 'no git repo, use spack {0}'.format(spack.spack_version)
|
||||
|
||||
|
||||
def setup_spack_repro_version(repro_dir, checkout_commit, merge_commit=None):
|
||||
# figure out the path to the spack git version being used for the
|
||||
# reproduction
|
||||
print('checkout_commit: {0}'.format(checkout_commit))
|
||||
print('merge_commit: {0}'.format(merge_commit))
|
||||
|
||||
dot_git_path = os.path.join(spack.paths.prefix, ".git")
|
||||
if not os.path.exists(dot_git_path):
|
||||
tty.error('Unable to find the path to your local spack clone')
|
||||
return False
|
||||
|
||||
spack_git_path = spack.paths.prefix
|
||||
|
||||
git = exe.which("git")
|
||||
if not git:
|
||||
tty.error("reproduction of pipeline job requires git")
|
||||
return False
|
||||
|
||||
# Check if we can find the tested commits in your local spack repo
|
||||
with fs.working_dir(spack_git_path):
|
||||
git("log", "-1", checkout_commit, output=str, error=os.devnull,
|
||||
fail_on_error=False)
|
||||
|
||||
if git.returncode != 0:
|
||||
tty.error('Missing commit: {0}'.format(checkout_commit))
|
||||
return False
|
||||
|
||||
if merge_commit:
|
||||
git("log", "-1", merge_commit, output=str, error=os.devnull,
|
||||
fail_on_error=False)
|
||||
|
||||
if git.returncode != 0:
|
||||
tty.error('Missing commit: {0}'.format(merge_commit))
|
||||
return False
|
||||
|
||||
# Next attempt to clone your local spack repo into the repro dir
|
||||
with fs.working_dir(repro_dir):
|
||||
clone_out = git("clone", spack_git_path,
|
||||
output=str, error=os.devnull,
|
||||
fail_on_error=False)
|
||||
|
||||
if git.returncode != 0:
|
||||
tty.error('Unable to clone your local spac repo:')
|
||||
tty.msg(clone_out)
|
||||
return False
|
||||
|
||||
# Finally, attempt to put the cloned repo into the same state used during
|
||||
# the pipeline build job
|
||||
repro_spack_path = os.path.join(repro_dir, 'spack')
|
||||
with fs.working_dir(repro_spack_path):
|
||||
co_out = git("checkout", checkout_commit,
|
||||
output=str, error=os.devnull,
|
||||
fail_on_error=False)
|
||||
|
||||
if git.returncode != 0:
|
||||
tty.error('Unable to checkout {0}'.format(checkout_commit))
|
||||
tty.msg(co_out)
|
||||
return False
|
||||
|
||||
if merge_commit:
|
||||
merge_out = git("-c", "user.name=cirepro", "-c",
|
||||
"user.email=user@email.org", "merge",
|
||||
"--no-edit", merge_commit,
|
||||
output=str, error=os.devnull,
|
||||
fail_on_error=False)
|
||||
|
||||
if git.returncode != 0:
|
||||
tty.error('Unable to merge {0}'.format(merge_commit))
|
||||
tty.msg(merge_out)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def reproduce_ci_job(url, work_dir):
|
||||
download_and_extract_artifacts(url, work_dir)
|
||||
|
||||
lock_file = fs.find(work_dir, 'spack.lock')[0]
|
||||
concrete_env_dir = os.path.dirname(lock_file)
|
||||
|
||||
tty.debug('Concrete environment directory: {0}'.format(
|
||||
concrete_env_dir))
|
||||
|
||||
yaml_files = fs.find(work_dir, ['*.yaml', '*.yml'])
|
||||
|
||||
tty.debug('yaml files:')
|
||||
for yaml_file in yaml_files:
|
||||
tty.debug(' {0}'.format(yaml_file))
|
||||
|
||||
pipeline_yaml = None
|
||||
|
||||
# Try to find the dynamically generated pipeline yaml file in the
|
||||
# reproducer. If the user did not put it in the artifacts root,
|
||||
# but rather somewhere else and exported it as an artifact from
|
||||
# that location, we won't be able to find it.
|
||||
for yf in yaml_files:
|
||||
with open(yf) as y_fd:
|
||||
yaml_obj = syaml.load(y_fd)
|
||||
if 'variables' in yaml_obj and 'stages' in yaml_obj:
|
||||
pipeline_yaml = yaml_obj
|
||||
|
||||
if pipeline_yaml:
|
||||
tty.debug('\n{0} is likely your pipeline file'.format(yf))
|
||||
|
||||
# Find the install script in the unzipped artifacts and make it executable
|
||||
install_script = fs.find(work_dir, 'install.sh')[0]
|
||||
st = os.stat(install_script)
|
||||
os.chmod(install_script, st.st_mode | stat.S_IEXEC)
|
||||
|
||||
# Find the repro details file. This just includes some values we wrote
|
||||
# during `spack ci rebuild` to make reproduction easier. E.g. the job
|
||||
# name is written here so we can easily find the configuration of the
|
||||
# job from the generated pipeline file.
|
||||
repro_file = fs.find(work_dir, 'repro.json')[0]
|
||||
repro_details = None
|
||||
with open(repro_file) as fd:
|
||||
repro_details = json.load(fd)
|
||||
|
||||
repro_dir = os.path.dirname(repro_file)
|
||||
rel_repro_dir = repro_dir.replace(work_dir, '').lstrip(os.path.sep)
|
||||
|
||||
# Find the spack info text file that should contain the git log
|
||||
# of the HEAD commit used during the CI build
|
||||
spack_info_file = fs.find(work_dir, 'spack_info.txt')[0]
|
||||
with open(spack_info_file) as fd:
|
||||
spack_info = fd.read()
|
||||
|
||||
# Access the specific job configuration
|
||||
job_name = repro_details['job_name']
|
||||
job_yaml = None
|
||||
|
||||
if job_name in pipeline_yaml:
|
||||
job_yaml = pipeline_yaml[job_name]
|
||||
|
||||
if job_yaml:
|
||||
tty.debug('Found job:')
|
||||
tty.debug(job_yaml)
|
||||
|
||||
job_image = None
|
||||
setup_result = False
|
||||
if 'image' in job_yaml:
|
||||
job_image_elt = job_yaml['image']
|
||||
if 'name' in job_image_elt:
|
||||
job_image = job_image_elt['name']
|
||||
else:
|
||||
job_image = job_image_elt
|
||||
tty.msg('Job ran with the following image: {0}'.format(job_image))
|
||||
|
||||
# Because we found this job was run with a docker image, so we will try
|
||||
# to print a "docker run" command that bind-mounts the directory where
|
||||
# we extracted the artifacts.
|
||||
|
||||
# Destination of bind-mounted reproduction directory. It makes for a
|
||||
# more faithful reproducer if everything appears to run in the same
|
||||
# absolute path used during the CI build.
|
||||
mount_as_dir = '/work'
|
||||
if repro_details:
|
||||
mount_as_dir = repro_details['ci_project_dir']
|
||||
mounted_repro_dir = os.path.join(mount_as_dir, rel_repro_dir)
|
||||
|
||||
# We will also try to clone spack from your local checkout and
|
||||
# reproduce the state present during the CI build, and put that into
|
||||
# the bind-mounted reproducer directory.
|
||||
|
||||
# Regular expressions for parsing that HEAD commit. If the pipeline
|
||||
# was on the gitlab spack mirror, it will have been a merge commit made by
|
||||
# gitub and pushed by the sync script. If the pipeline was run on some
|
||||
# environment repo, then the tested spack commit will likely have been
|
||||
# a regular commit.
|
||||
commit_1 = None
|
||||
commit_2 = None
|
||||
commit_regex = re.compile(r"commit\s+([^\s]+)")
|
||||
merge_commit_regex = re.compile(r"Merge\s+([^\s]+)\s+into\s+([^\s]+)")
|
||||
|
||||
# Try the more specific merge commit regex first
|
||||
m = merge_commit_regex.search(spack_info)
|
||||
if m:
|
||||
# This was a merge commit and we captured the parents
|
||||
commit_1 = m.group(1)
|
||||
commit_2 = m.group(2)
|
||||
else:
|
||||
# Not a merge commit, just get the commit sha
|
||||
m = commit_regex.search(spack_info)
|
||||
if m:
|
||||
commit_1 = m.group(1)
|
||||
|
||||
setup_result = False
|
||||
if commit_1:
|
||||
if commit_2:
|
||||
setup_result = setup_spack_repro_version(
|
||||
work_dir, commit_2, merge_commit=commit_1)
|
||||
else:
|
||||
setup_result = setup_spack_repro_version(work_dir, commit_1)
|
||||
|
||||
if not setup_result:
|
||||
setup_msg = """
|
||||
This can happen if the spack you are using to run this command is not a git
|
||||
repo, or if it is a git repo, but it does not have the commits needed to
|
||||
recreate the tested merge commit. If you are trying to reproduce a spack
|
||||
PR pipeline job failure, try fetching the latest develop commits from
|
||||
mainline spack and make sure you have the most recent commit of the PR
|
||||
branch in your local spack repo. Then run this command again.
|
||||
Alternatively, you can also manually clone spack if you know the version
|
||||
you want to test.
|
||||
"""
|
||||
tty.error('Failed to automatically setup the tested version of spack '
|
||||
'in your local reproduction directory.')
|
||||
print(setup_msg)
|
||||
|
||||
# In cases where CI build was run on a shell runner, it might be useful
|
||||
# to see what tags were applied to the job so the user knows what shell
|
||||
# runner was used. But in that case in general, we cannot do nearly as
|
||||
# much to set up the reproducer.
|
||||
job_tags = None
|
||||
if 'tags' in job_yaml:
|
||||
job_tags = job_yaml['tags']
|
||||
tty.msg('Job ran with the following tags: {0}'.format(job_tags))
|
||||
|
||||
inst_list = []
|
||||
|
||||
# Finally, print out some instructions to reproduce the build
|
||||
if job_image:
|
||||
inst_list.append('\nRun the following command:\n\n')
|
||||
inst_list.append(' $ docker run --rm -v {0}:{1} -ti {2}\n'.format(
|
||||
work_dir, mount_as_dir, job_image))
|
||||
inst_list.append('\nOnce inside the container:\n\n')
|
||||
else:
|
||||
inst_list.append('\nOnce on the tagged runner:\n\n')
|
||||
|
||||
if not setup_result:
|
||||
inst_list.append(' - Clone spack and acquire tested commit\n')
|
||||
inst_list.append('{0}'.format(spack_info))
|
||||
spack_root = '<spack-clone-path>'
|
||||
else:
|
||||
spack_root = '{0}/spack'.format(mount_as_dir)
|
||||
|
||||
inst_list.append(' - Activate the environment\n\n')
|
||||
inst_list.append(' $ source {0}/share/spack/setup-env.sh\n'.format(
|
||||
spack_root))
|
||||
inst_list.append(
|
||||
' $ spack env activate --without-view {0}\n\n'.format(
|
||||
mounted_repro_dir if job_image else repro_dir))
|
||||
inst_list.append(' - Run the install script\n\n')
|
||||
inst_list.append(' $ {0}\n'.format(
|
||||
os.path.join(mounted_repro_dir, 'install.sh')
|
||||
if job_image else install_script))
|
||||
|
||||
print(''.join(inst_list))
|
||||
|
||||
@@ -5,19 +5,20 @@
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import argparse
|
||||
import ruamel.yaml as yaml
|
||||
|
||||
import ruamel.yaml as yaml
|
||||
import six
|
||||
from ruamel.yaml.error import MarkedYAMLError
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import join_path
|
||||
from llnl.util.lang import attr_setdefault, index_by
|
||||
from llnl.util.tty.colify import colify
|
||||
from llnl.util.tty.color import colorize
|
||||
from llnl.util.filesystem import join_path
|
||||
|
||||
import spack.config
|
||||
import spack.error
|
||||
@@ -27,8 +28,6 @@
|
||||
import spack.store
|
||||
import spack.util.spack_json as sjson
|
||||
import spack.util.string
|
||||
from ruamel.yaml.error import MarkedYAMLError
|
||||
|
||||
|
||||
# cmd has a submodule called "list" so preserve the python list module
|
||||
python_list = list
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.environment as ev
|
||||
|
||||
|
||||
description = 'add a spec to an environment'
|
||||
section = "environments"
|
||||
level = "long"
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import spack.paths
|
||||
import spack.report
|
||||
|
||||
|
||||
description = "run analyzers on installed packages"
|
||||
section = "analysis"
|
||||
level = "long"
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
import collections
|
||||
|
||||
import archspec.cpu
|
||||
|
||||
import llnl.util.tty.colify as colify
|
||||
import llnl.util.tty.color as color
|
||||
|
||||
import spack.architecture as architecture
|
||||
|
||||
description = "print architecture information about this machine"
|
||||
|
||||
80
lib/spack/spack/cmd/audit.py
Normal file
80
lib/spack/spack/cmd/audit.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# Copyright 2013-2021 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)
|
||||
import llnl.util.tty.color as cl
|
||||
|
||||
import spack.audit
|
||||
import spack.repo
|
||||
|
||||
description = "audit configuration files, packages, etc."
|
||||
section = "system"
|
||||
level = "short"
|
||||
|
||||
|
||||
def setup_parser(subparser):
|
||||
# Top level flags, valid for every audit class
|
||||
sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='subcommand')
|
||||
|
||||
# Audit configuration files
|
||||
sp.add_parser('configs', help='audit configuration files')
|
||||
|
||||
# Audit package recipes
|
||||
pkg_parser = sp.add_parser('packages', help='audit package recipes')
|
||||
pkg_parser.add_argument(
|
||||
'name', metavar='PKG', nargs='*',
|
||||
help='package to be analyzed (if none all packages will be processed)',
|
||||
)
|
||||
|
||||
# List all checks
|
||||
sp.add_parser('list', help='list available checks and exits')
|
||||
|
||||
|
||||
def configs(parser, args):
|
||||
reports = spack.audit.run_group(args.subcommand)
|
||||
_process_reports(reports)
|
||||
|
||||
|
||||
def packages(parser, args):
|
||||
pkgs = args.name or spack.repo.path.all_package_names()
|
||||
reports = spack.audit.run_group(args.subcommand, pkgs=pkgs)
|
||||
_process_reports(reports)
|
||||
|
||||
|
||||
def list(parser, args):
|
||||
for subcommand, check_tags in spack.audit.GROUPS.items():
|
||||
print(cl.colorize('@*b{' + subcommand + '}:'))
|
||||
for tag in check_tags:
|
||||
audit_obj = spack.audit.CALLBACKS[tag]
|
||||
print(' ' + audit_obj.description)
|
||||
if args.verbose:
|
||||
for idx, fn in enumerate(audit_obj.callbacks):
|
||||
print(' {0}. '.format(idx + 1) + fn.__doc__)
|
||||
print()
|
||||
print()
|
||||
|
||||
|
||||
def audit(parser, args):
|
||||
subcommands = {
|
||||
'configs': configs,
|
||||
'packages': packages,
|
||||
'list': list
|
||||
}
|
||||
subcommands[args.subcommand](parser, args)
|
||||
|
||||
|
||||
def _process_reports(reports):
|
||||
for check, errors in reports:
|
||||
if errors:
|
||||
msg = '{0}: {1} issue{2} found'.format(
|
||||
check, len(errors), '' if len(errors) == 1 else 's'
|
||||
)
|
||||
header = '@*b{' + msg + '}'
|
||||
print(cl.colorize(header))
|
||||
for idx, error in enumerate(errors):
|
||||
print(str(idx + 1) + '. ' + str(error))
|
||||
raise SystemExit(1)
|
||||
else:
|
||||
msg = '{0}: 0 issues found.'.format(check)
|
||||
header = '@*b{' + msg + '}'
|
||||
print(cl.colorize(header))
|
||||
@@ -5,17 +5,18 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.lang import pretty_date
|
||||
from llnl.util.filesystem import working_dir
|
||||
from llnl.util.lang import pretty_date
|
||||
from llnl.util.tty.colify import colify_table
|
||||
|
||||
import spack.paths
|
||||
import spack.repo
|
||||
from spack.util.executable import which
|
||||
import spack.util.spack_json as sjson
|
||||
from spack.cmd import spack_is_git_repo
|
||||
|
||||
from spack.util.executable import which
|
||||
|
||||
description = "show contributors to packages"
|
||||
section = "developer"
|
||||
@@ -33,12 +34,57 @@ def setup_parser(subparser):
|
||||
view_group.add_argument(
|
||||
'-g', '--git', dest='view', action='store_const', const='git',
|
||||
help='show git blame output instead of summary')
|
||||
subparser.add_argument(
|
||||
"--json", action="store_true", default=False,
|
||||
help="output blame as machine-readable json records")
|
||||
|
||||
subparser.add_argument(
|
||||
'package_or_file', help='name of package to show contributions for, '
|
||||
'or path to a file in the spack repo')
|
||||
|
||||
|
||||
def print_table(rows, last_mod, total_lines, emails):
|
||||
"""
|
||||
Given a set of rows with authors and lines, print a table.
|
||||
"""
|
||||
table = [['LAST_COMMIT', 'LINES', '%', 'AUTHOR', 'EMAIL']]
|
||||
for author, nlines in rows:
|
||||
table += [[
|
||||
pretty_date(last_mod[author]),
|
||||
nlines,
|
||||
round(nlines / float(total_lines) * 100, 1),
|
||||
author,
|
||||
emails[author]]]
|
||||
|
||||
table += [[''] * 5]
|
||||
table += [[pretty_date(max(last_mod.values())), total_lines, '100.0'] +
|
||||
[''] * 3]
|
||||
|
||||
colify_table(table)
|
||||
|
||||
|
||||
def dump_json(rows, last_mod, total_lines, emails):
|
||||
"""
|
||||
Dump the blame as a json object to the terminal.
|
||||
"""
|
||||
result = {}
|
||||
authors = []
|
||||
for author, nlines in rows:
|
||||
authors.append({
|
||||
"last_commit": pretty_date(last_mod[author]),
|
||||
"lines": nlines,
|
||||
"percentage": round(nlines / float(total_lines) * 100, 1),
|
||||
"author": author,
|
||||
"email": emails[author]
|
||||
})
|
||||
|
||||
result['authors'] = authors
|
||||
result["totals"] = {"last_commit": pretty_date(max(last_mod.values())),
|
||||
"lines": total_lines, "percentage": "100.0"}
|
||||
|
||||
sjson.dump(result, sys.stdout)
|
||||
|
||||
|
||||
def blame(parser, args):
|
||||
# make sure this is a git repo
|
||||
if not spack_is_git_repo():
|
||||
@@ -96,18 +142,10 @@ def blame(parser, args):
|
||||
else: # args.view == 'percent'
|
||||
rows = sorted(counts.items(), key=lambda t: t[1], reverse=True)
|
||||
|
||||
# Dump as json
|
||||
if args.json:
|
||||
dump_json(rows, last_mod, total_lines, emails)
|
||||
|
||||
# Print a nice table with authors and emails
|
||||
table = [['LAST_COMMIT', 'LINES', '%', 'AUTHOR', 'EMAIL']]
|
||||
for author, nlines in rows:
|
||||
table += [[
|
||||
pretty_date(last_mod[author]),
|
||||
nlines,
|
||||
round(nlines / float(total_lines) * 100, 1),
|
||||
author,
|
||||
emails[author]]]
|
||||
|
||||
table += [[''] * 5]
|
||||
table += [[pretty_date(max(last_mod.values())), total_lines, '100.0'] +
|
||||
[''] * 3]
|
||||
|
||||
colify_table(table)
|
||||
else:
|
||||
print_table(rows, last_mod, total_lines, emails)
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
import sys
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.architecture
|
||||
import spack.binary_distribution as bindist
|
||||
import spack.cmd
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.config
|
||||
import spack.environment as ev
|
||||
import spack.hash_types as ht
|
||||
import spack.mirror
|
||||
@@ -19,17 +21,12 @@
|
||||
import spack.repo
|
||||
import spack.spec
|
||||
import spack.store
|
||||
import spack.config
|
||||
import spack.repo
|
||||
import spack.store
|
||||
import spack.util.url as url_util
|
||||
|
||||
from spack.cmd import display_specs
|
||||
from spack.error import SpecError
|
||||
from spack.spec import Spec, save_dependency_spec_yamls
|
||||
from spack.util.string import plural
|
||||
|
||||
from spack.cmd import display_specs
|
||||
|
||||
description = "create, download and install binary packages"
|
||||
section = "packaging"
|
||||
level = "long"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import spack.stage
|
||||
import spack.util.crypto
|
||||
from spack.util.naming import valid_fully_qualified_module_name
|
||||
from spack.version import ver, Version
|
||||
from spack.version import Version, ver
|
||||
|
||||
description = "checksum available versions of a package"
|
||||
section = "packaging"
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
@@ -14,16 +18,19 @@
|
||||
import spack.binary_distribution as bindist
|
||||
import spack.ci as spack_ci
|
||||
import spack.cmd.buildcache as buildcache
|
||||
import spack.config as cfg
|
||||
import spack.environment as ev
|
||||
import spack.hash_types as ht
|
||||
import spack.util.executable as exe
|
||||
import spack.mirror
|
||||
import spack.util.url as url_util
|
||||
|
||||
import spack.util.web as web_util
|
||||
|
||||
description = "manage continuous integration pipelines"
|
||||
section = "build"
|
||||
level = "long"
|
||||
|
||||
CI_REBUILD_INSTALL_BASE_ARGS = ['spack', '-d', '-v']
|
||||
|
||||
|
||||
def get_env_var(variable_name):
|
||||
if variable_name in os.environ:
|
||||
@@ -75,18 +82,32 @@ def setup_parser(subparser):
|
||||
to determine whether a given spec is up to date on mirrors. In the latter
|
||||
case, specs might be needlessly rebuilt if remote buildcache indices are out
|
||||
of date.""")
|
||||
generate.add_argument(
|
||||
'--artifacts-root', default=None,
|
||||
help="""Path to root of artifacts directory. If provided, concrete
|
||||
environment files (spack.yaml, spack.lock) will be generated under this
|
||||
path and their location sent to generated child jobs via the custom job
|
||||
variable SPACK_CONCRETE_ENVIRONMENT_PATH.""")
|
||||
generate.set_defaults(func=ci_generate)
|
||||
|
||||
# Check a spec against mirror. Rebuild, create buildcache and push to
|
||||
# mirror (if necessary).
|
||||
rebuild = subparsers.add_parser('rebuild', help=ci_rebuild.__doc__)
|
||||
rebuild.set_defaults(func=ci_rebuild)
|
||||
|
||||
# Rebuild the buildcache index associated with the mirror in the
|
||||
# active, gitlab-enabled environment.
|
||||
index = subparsers.add_parser('rebuild-index', help=ci_reindex.__doc__)
|
||||
index.set_defaults(func=ci_reindex)
|
||||
|
||||
# Handle steps of a ci build/rebuild
|
||||
rebuild = subparsers.add_parser('rebuild', help=ci_rebuild.__doc__)
|
||||
rebuild.set_defaults(func=ci_rebuild)
|
||||
|
||||
# Facilitate reproduction of a failed CI build job
|
||||
reproduce = subparsers.add_parser('reproduce-build',
|
||||
help=ci_reproduce.__doc__)
|
||||
reproduce.add_argument('job_url', help='Url of job artifacts bundle')
|
||||
reproduce.add_argument('--working-dir', help="Where to unpack artifacts",
|
||||
default=os.path.join(os.getcwd(), 'ci_reproduction'))
|
||||
|
||||
reproduce.set_defaults(func=ci_reproduce)
|
||||
|
||||
|
||||
def ci_generate(args):
|
||||
"""Generate jobs file from a spack environment file containing CI info.
|
||||
@@ -103,6 +124,7 @@ def ci_generate(args):
|
||||
use_dependencies = args.dependencies
|
||||
prune_dag = args.prune_dag
|
||||
index_only = args.index_only
|
||||
artifacts_root = args.artifacts_root
|
||||
|
||||
if not output_file:
|
||||
output_file = os.path.abspath(".gitlab-ci.yml")
|
||||
@@ -116,7 +138,7 @@ def ci_generate(args):
|
||||
spack_ci.generate_gitlab_ci_yaml(
|
||||
env, True, output_file, prune_dag=prune_dag,
|
||||
check_index_only=index_only, run_optimizer=run_optimizer,
|
||||
use_dependencies=use_dependencies)
|
||||
use_dependencies=use_dependencies, artifacts_root=artifacts_root)
|
||||
|
||||
if copy_yaml_to:
|
||||
copy_to_dir = os.path.dirname(copy_yaml_to)
|
||||
@@ -125,51 +147,31 @@ def ci_generate(args):
|
||||
shutil.copyfile(output_file, copy_yaml_to)
|
||||
|
||||
|
||||
def ci_rebuild(args):
|
||||
"""This command represents a gitlab-ci job, corresponding to a single
|
||||
release spec. As such it must first decide whether or not the spec it
|
||||
has been assigned to build is up to date on the remote binary mirror.
|
||||
If it is not (i.e. the full_hash of the spec as computed locally does
|
||||
not match the one stored in the metadata on the mirror), this script
|
||||
will build the package, create a binary cache for it, and then push all
|
||||
related files to the remote binary mirror. This script also
|
||||
communicates with a remote CDash instance to share status on the package
|
||||
build process.
|
||||
|
||||
The spec to be built by this job is represented by essentially two
|
||||
pieces of information: 1) a root spec (possibly already concrete, but
|
||||
maybe still needing to be concretized) and 2) a package name used to
|
||||
index that root spec (once the root is, for certain, concrete)."""
|
||||
env = ev.get_env(args, 'ci rebuild', required=True)
|
||||
def ci_reindex(args):
|
||||
"""Rebuild the buildcache index associated with the mirror in the
|
||||
active, gitlab-enabled environment. """
|
||||
env = ev.get_env(args, 'ci rebuild-index', required=True)
|
||||
yaml_root = ev.config_dict(env.yaml)
|
||||
|
||||
# The following environment variables should defined in the CI
|
||||
# infrastructre (or some other external source) in the case that the
|
||||
# remote mirror is an S3 bucket. The AWS keys are used to upload
|
||||
# buildcache entries to S3 using the boto3 api.
|
||||
#
|
||||
# AWS_ACCESS_KEY_ID
|
||||
# AWS_SECRET_ACCESS_KEY
|
||||
# S3_ENDPOINT_URL (only needed for non-AWS S3 implementations)
|
||||
#
|
||||
# If present, we will import the SPACK_SIGNING_KEY using the
|
||||
# "spack gpg trust" command, so it can be used both for verifying
|
||||
# dependency buildcache entries and signing the buildcache entry we create
|
||||
# for our target pkg.
|
||||
#
|
||||
# SPACK_SIGNING_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')
|
||||
|
||||
ci_artifact_dir = get_env_var('CI_PROJECT_DIR')
|
||||
ci_pipeline_id = get_env_var('CI_PIPELINE_ID')
|
||||
signing_key = get_env_var('SPACK_SIGNING_KEY')
|
||||
root_spec = get_env_var('SPACK_ROOT_SPEC')
|
||||
job_spec_pkg_name = get_env_var('SPACK_JOB_SPEC_PKG_NAME')
|
||||
compiler_action = get_env_var('SPACK_COMPILER_ACTION')
|
||||
cdash_build_name = get_env_var('SPACK_CDASH_BUILD_NAME')
|
||||
related_builds = get_env_var('SPACK_RELATED_BUILDS_CDASH')
|
||||
pr_env_var = get_env_var('SPACK_IS_PR_PIPELINE')
|
||||
pr_mirror_url = get_env_var('SPACK_PR_MIRROR_URL')
|
||||
ci_mirrors = yaml_root['mirrors']
|
||||
mirror_urls = [url for url in ci_mirrors.values()]
|
||||
remote_mirror_url = mirror_urls[0]
|
||||
|
||||
buildcache.update_index(remote_mirror_url, update_keys=True)
|
||||
|
||||
|
||||
def ci_rebuild(args):
|
||||
"""Check a single spec against the remote mirror, and rebuild it from
|
||||
source if the mirror does not contain the full hash match of the spec
|
||||
as computed locally. """
|
||||
env = ev.get_env(args, 'ci rebuild', required=True)
|
||||
|
||||
# Make sure the environment is "gitlab-enabled", or else there's nothing
|
||||
# to do.
|
||||
yaml_root = ev.config_dict(env.yaml)
|
||||
gitlab_ci = None
|
||||
if 'gitlab-ci' in yaml_root:
|
||||
gitlab_ci = yaml_root['gitlab-ci']
|
||||
@@ -177,6 +179,45 @@ def ci_rebuild(args):
|
||||
if not gitlab_ci:
|
||||
tty.die('spack ci rebuild requires an env containing gitlab-ci cfg')
|
||||
|
||||
# Grab the environment variables we need. These either come from the
|
||||
# pipeline generation step ("spack ci generate"), where they were written
|
||||
# out as variables, or else provided by GitLab itself.
|
||||
pipeline_artifacts_dir = get_env_var('SPACK_ARTIFACTS_ROOT')
|
||||
job_log_dir = get_env_var('SPACK_JOB_LOG_DIR')
|
||||
repro_dir = get_env_var('SPACK_JOB_REPRO_DIR')
|
||||
local_mirror_dir = get_env_var('SPACK_LOCAL_MIRROR_DIR')
|
||||
concrete_env_dir = get_env_var('SPACK_CONCRETE_ENV_DIR')
|
||||
ci_pipeline_id = get_env_var('CI_PIPELINE_ID')
|
||||
ci_job_name = get_env_var('CI_JOB_NAME')
|
||||
signing_key = get_env_var('SPACK_SIGNING_KEY')
|
||||
root_spec = get_env_var('SPACK_ROOT_SPEC')
|
||||
job_spec_pkg_name = get_env_var('SPACK_JOB_SPEC_PKG_NAME')
|
||||
compiler_action = get_env_var('SPACK_COMPILER_ACTION')
|
||||
cdash_build_name = get_env_var('SPACK_CDASH_BUILD_NAME')
|
||||
related_builds = get_env_var('SPACK_RELATED_BUILDS_CDASH')
|
||||
spack_pipeline_type = get_env_var('SPACK_PIPELINE_TYPE')
|
||||
pr_mirror_url = get_env_var('SPACK_PR_MIRROR_URL')
|
||||
remote_mirror_url = get_env_var('SPACK_REMOTE_MIRROR_URL')
|
||||
|
||||
# Construct absolute paths relative to current $CI_PROJECT_DIR
|
||||
ci_project_dir = get_env_var('CI_PROJECT_DIR')
|
||||
pipeline_artifacts_dir = os.path.join(
|
||||
ci_project_dir, pipeline_artifacts_dir)
|
||||
job_log_dir = os.path.join(ci_project_dir, job_log_dir)
|
||||
repro_dir = os.path.join(ci_project_dir, repro_dir)
|
||||
local_mirror_dir = os.path.join(ci_project_dir, local_mirror_dir)
|
||||
concrete_env_dir = os.path.join(ci_project_dir, concrete_env_dir)
|
||||
|
||||
# Debug print some of the key environment variables we should have received
|
||||
tty.debug('pipeline_artifacts_dir = {0}'.format(pipeline_artifacts_dir))
|
||||
tty.debug('root_spec = {0}'.format(root_spec))
|
||||
tty.debug('remote_mirror_url = {0}'.format(remote_mirror_url))
|
||||
tty.debug('job_spec_pkg_name = {0}'.format(job_spec_pkg_name))
|
||||
tty.debug('compiler_action = {0}'.format(compiler_action))
|
||||
|
||||
# Query the environment manifest to find out whether we're reporting to a
|
||||
# CDash instance, and if so, gather some information from the manifest to
|
||||
# support that task.
|
||||
enable_cdash = False
|
||||
if 'cdash' in yaml_root:
|
||||
enable_cdash = True
|
||||
@@ -196,32 +237,20 @@ def ci_rebuild(args):
|
||||
tty.debug('related_builds = {0}'.format(related_builds))
|
||||
tty.debug('job_spec_buildgroup = {0}'.format(job_spec_buildgroup))
|
||||
|
||||
remote_mirror_url = None
|
||||
if 'mirrors' in yaml_root:
|
||||
ci_mirrors = yaml_root['mirrors']
|
||||
mirror_urls = [url for url in ci_mirrors.values()]
|
||||
remote_mirror_url = mirror_urls[0]
|
||||
# Is this a pipeline run on a spack PR or a merge to develop? It might
|
||||
# be neither, e.g. a pipeline run on some environment repository.
|
||||
spack_is_pr_pipeline = spack_pipeline_type == 'spack_pull_request'
|
||||
spack_is_develop_pipeline = spack_pipeline_type == 'spack_protected_branch'
|
||||
|
||||
if not remote_mirror_url:
|
||||
tty.die('spack ci rebuild requires an env containing a mirror')
|
||||
|
||||
tty.debug('ci_artifact_dir = {0}'.format(ci_artifact_dir))
|
||||
tty.debug('root_spec = {0}'.format(root_spec))
|
||||
tty.debug('remote_mirror_url = {0}'.format(remote_mirror_url))
|
||||
tty.debug('job_spec_pkg_name = {0}'.format(job_spec_pkg_name))
|
||||
tty.debug('compiler_action = {0}'.format(compiler_action))
|
||||
|
||||
cdash_report_dir = os.path.join(ci_artifact_dir, 'cdash_report')
|
||||
temp_dir = os.path.join(ci_artifact_dir, 'jobs_scratch_dir')
|
||||
job_log_dir = os.path.join(temp_dir, 'logs')
|
||||
spec_dir = os.path.join(temp_dir, 'specs')
|
||||
|
||||
local_mirror_dir = os.path.join(ci_artifact_dir, 'local_mirror')
|
||||
build_cache_dir = os.path.join(local_mirror_dir, 'build_cache')
|
||||
|
||||
spack_is_pr_pipeline = True if pr_env_var == 'True' else False
|
||||
tty.debug('Pipeline type - PR: {0}, develop: {1}'.format(
|
||||
spack_is_pr_pipeline, spack_is_develop_pipeline))
|
||||
|
||||
# Figure out what is our temporary storage mirror: Is it artifacts
|
||||
# buildcache? Or temporary-storage-url-prefix? In some cases we need to
|
||||
# force something or pipelines might not have a way to propagate build
|
||||
# artifacts from upstream to downstream jobs.
|
||||
pipeline_mirror_url = None
|
||||
|
||||
temp_storage_url_prefix = None
|
||||
if 'temporary-storage-url-prefix' in gitlab_ci:
|
||||
temp_storage_url_prefix = gitlab_ci['temporary-storage-url-prefix']
|
||||
@@ -245,210 +274,336 @@ def ci_rebuild(args):
|
||||
pipeline_mirror_url)
|
||||
tty.debug(mirror_msg)
|
||||
|
||||
# Clean out scratch directory from last stage
|
||||
if os.path.exists(temp_dir):
|
||||
shutil.rmtree(temp_dir)
|
||||
# Whatever form of root_spec we got, use it to get a map giving us concrete
|
||||
# specs for this job and all of its dependencies.
|
||||
spec_map = spack_ci.get_concrete_specs(
|
||||
env, root_spec, job_spec_pkg_name, related_builds, compiler_action)
|
||||
job_spec = spec_map[job_spec_pkg_name]
|
||||
|
||||
job_spec_yaml_file = '{0}.yaml'.format(job_spec_pkg_name)
|
||||
job_spec_yaml_path = os.path.join(repro_dir, job_spec_yaml_file)
|
||||
|
||||
# To provide logs, cdash reports, etc for developer download/perusal,
|
||||
# these things have to be put into artifacts. This means downstream
|
||||
# jobs that "need" this job will get those artifacts too. So here we
|
||||
# need to clean out the artifacts we may have got from upstream jobs.
|
||||
|
||||
cdash_report_dir = os.path.join(pipeline_artifacts_dir, 'cdash_report')
|
||||
if os.path.exists(cdash_report_dir):
|
||||
shutil.rmtree(cdash_report_dir)
|
||||
|
||||
os.makedirs(job_log_dir)
|
||||
os.makedirs(spec_dir)
|
||||
if os.path.exists(job_log_dir):
|
||||
shutil.rmtree(job_log_dir)
|
||||
|
||||
job_spec_yaml_path = os.path.join(
|
||||
spec_dir, '{0}.yaml'.format(job_spec_pkg_name))
|
||||
job_log_file = os.path.join(job_log_dir, 'pipeline_log.txt')
|
||||
if os.path.exists(repro_dir):
|
||||
shutil.rmtree(repro_dir)
|
||||
|
||||
# Now that we removed them if they existed, create the directories we
|
||||
# need for storing artifacts. The cdash_report directory will be
|
||||
# created internally if needed.
|
||||
os.makedirs(job_log_dir)
|
||||
os.makedirs(repro_dir)
|
||||
|
||||
# Copy the concrete environment files to the repro directory so we can
|
||||
# expose them as artifacts and not conflict with the concrete environment
|
||||
# files we got as artifacts from the upstream pipeline generation job.
|
||||
# Try to cast a slightly wider net too, and hopefully get the generated
|
||||
# pipeline yaml. If we miss it, the user will still be able to go to the
|
||||
# pipeline generation job and get it from there.
|
||||
target_dirs = [
|
||||
concrete_env_dir,
|
||||
pipeline_artifacts_dir
|
||||
]
|
||||
|
||||
for dir_to_list in target_dirs:
|
||||
for file_name in os.listdir(dir_to_list):
|
||||
src_file = os.path.join(dir_to_list, file_name)
|
||||
if os.path.isfile(src_file):
|
||||
dst_file = os.path.join(repro_dir, file_name)
|
||||
shutil.copyfile(src_file, dst_file)
|
||||
|
||||
# If signing key was provided via "SPACK_SIGNING_KEY", then try to
|
||||
# import it.
|
||||
if signing_key:
|
||||
spack_ci.import_signing_key(signing_key)
|
||||
|
||||
# Depending on the specifics of this job, we might need to turn on the
|
||||
# "config:install_missing compilers" option (to build this job spec
|
||||
# with a bootstrapped compiler), or possibly run "spack compiler find"
|
||||
# (to build a bootstrap compiler or one of its deps in a
|
||||
# compiler-agnostic way), or maybe do nothing at all (to build a spec
|
||||
# using a compiler already installed on the target system).
|
||||
spack_ci.configure_compilers(compiler_action)
|
||||
|
||||
# Write this job's spec yaml into the reproduction directory, and it will
|
||||
# also be used in the generated "spack install" command to install the spec
|
||||
tty.debug('job concrete spec path: {0}'.format(job_spec_yaml_path))
|
||||
with open(job_spec_yaml_path, 'w') as fd:
|
||||
fd.write(job_spec.to_yaml(hash=ht.build_hash))
|
||||
|
||||
# Write the concrete root spec yaml into the reproduction directory
|
||||
root_spec_yaml_path = os.path.join(repro_dir, 'root.yaml')
|
||||
with open(root_spec_yaml_path, 'w') as fd:
|
||||
fd.write(spec_map['root'].to_yaml(hash=ht.build_hash))
|
||||
|
||||
# Write some other details to aid in reproduction into an artifact
|
||||
repro_file = os.path.join(repro_dir, 'repro.json')
|
||||
repro_details = {
|
||||
'job_name': ci_job_name,
|
||||
'job_spec_yaml': job_spec_yaml_file,
|
||||
'root_spec_yaml': 'root.yaml',
|
||||
'ci_project_dir': ci_project_dir
|
||||
}
|
||||
with open(repro_file, 'w') as fd:
|
||||
fd.write(json.dumps(repro_details))
|
||||
|
||||
# Write information about spack into an artifact in the repro dir
|
||||
spack_info = spack_ci.get_spack_info()
|
||||
spack_info_file = os.path.join(repro_dir, 'spack_info.txt')
|
||||
with open(spack_info_file, 'w') as fd:
|
||||
fd.write('\n{0}\n'.format(spack_info))
|
||||
|
||||
# If we decided there should be a temporary storage mechanism, add that
|
||||
# mirror now so it's used when we check for a full hash match already
|
||||
# built for this spec.
|
||||
if pipeline_mirror_url:
|
||||
spack.mirror.add(spack_ci.TEMP_STORAGE_MIRROR_NAME,
|
||||
pipeline_mirror_url,
|
||||
cfg.default_modify_scope())
|
||||
|
||||
cdash_build_id = None
|
||||
cdash_build_stamp = None
|
||||
|
||||
with open(job_log_file, 'w') as log_fd:
|
||||
os.dup2(log_fd.fileno(), sys.stdout.fileno())
|
||||
os.dup2(log_fd.fileno(), sys.stderr.fileno())
|
||||
# Check configured mirrors for a built spec with a matching full hash
|
||||
matches = bindist.get_mirrors_for_spec(
|
||||
job_spec, full_hash_match=True, index_only=False)
|
||||
|
||||
current_directory = os.getcwd()
|
||||
tty.debug('Current working directory: {0}, Contents:'.format(
|
||||
current_directory))
|
||||
directory_list = os.listdir(current_directory)
|
||||
for next_entry in directory_list:
|
||||
tty.debug(' {0}'.format(next_entry))
|
||||
if matches:
|
||||
# Got a full hash match on at least one configured mirror. All
|
||||
# matches represent the fully up-to-date spec, so should all be
|
||||
# equivalent. If artifacts mirror is enabled, we just pick one
|
||||
# of the matches and download the buildcache files from there to
|
||||
# the artifacts, so they're available to be used by dependent
|
||||
# jobs in subsequent stages.
|
||||
tty.msg('No need to rebuild {0}, found full hash match at: '.format(
|
||||
job_spec_pkg_name))
|
||||
for match in matches:
|
||||
tty.msg(' {0}'.format(match['mirror_url']))
|
||||
if enable_artifacts_mirror:
|
||||
matching_mirror = matches[0]['mirror_url']
|
||||
build_cache_dir = os.path.join(local_mirror_dir, 'build_cache')
|
||||
tty.debug('Getting {0} buildcache from {1}'.format(
|
||||
job_spec_pkg_name, matching_mirror))
|
||||
tty.debug('Downloading to {0}'.format(build_cache_dir))
|
||||
buildcache.download_buildcache_files(
|
||||
job_spec, build_cache_dir, False, matching_mirror)
|
||||
|
||||
tty.debug('job concrete spec path: {0}'.format(job_spec_yaml_path))
|
||||
# Now we are done and successful
|
||||
sys.exit(0)
|
||||
|
||||
if signing_key:
|
||||
spack_ci.import_signing_key(signing_key)
|
||||
# No full hash match anywhere means we need to rebuild spec
|
||||
|
||||
# Start with spack arguments
|
||||
install_args = [base_arg for base_arg in CI_REBUILD_INSTALL_BASE_ARGS]
|
||||
|
||||
config = cfg.get('config')
|
||||
if not config['verify_ssl']:
|
||||
install_args.append('-k')
|
||||
|
||||
install_args.extend([
|
||||
'install',
|
||||
'--keep-stage',
|
||||
'--require-full-hash-match',
|
||||
])
|
||||
|
||||
can_verify = spack_ci.can_verify_binaries()
|
||||
verify_binaries = can_verify and spack_is_pr_pipeline is False
|
||||
if not verify_binaries:
|
||||
install_args.append('--no-check-signature')
|
||||
|
||||
# If CDash reporting is enabled, we first register this build with
|
||||
# the specified CDash instance, then relate the build to those of
|
||||
# its dependencies.
|
||||
if enable_cdash:
|
||||
tty.debug('CDash: Registering build')
|
||||
(cdash_build_id,
|
||||
cdash_build_stamp) = spack_ci.register_cdash_build(
|
||||
cdash_build_name, cdash_base_url, cdash_project,
|
||||
cdash_site, job_spec_buildgroup)
|
||||
|
||||
if cdash_build_id is not None:
|
||||
cdash_upload_url = '{0}/submit.php?project={1}'.format(
|
||||
cdash_base_url, cdash_project_enc)
|
||||
|
||||
install_args.extend([
|
||||
'--cdash-upload-url', cdash_upload_url,
|
||||
'--cdash-build', cdash_build_name,
|
||||
'--cdash-site', cdash_site,
|
||||
'--cdash-buildstamp', cdash_build_stamp,
|
||||
])
|
||||
|
||||
tty.debug('CDash: Relating build with dependency builds')
|
||||
spack_ci.relate_cdash_builds(
|
||||
spec_map, cdash_base_url, cdash_build_id, cdash_project,
|
||||
[pipeline_mirror_url, pr_mirror_url, remote_mirror_url])
|
||||
|
||||
# A compiler action of 'FIND_ANY' means we are building a bootstrap
|
||||
# compiler or one of its deps.
|
||||
# TODO: when compilers are dependencies, we should include --no-add
|
||||
if compiler_action != 'FIND_ANY':
|
||||
install_args.append('--no-add')
|
||||
|
||||
# TODO: once we have the concrete spec registry, use the DAG hash
|
||||
# to identify the spec to install, rather than the concrete spec
|
||||
# yaml file.
|
||||
install_args.extend(['-f', job_spec_yaml_path])
|
||||
|
||||
tty.debug('Installing {0} from source'.format(job_spec.name))
|
||||
tty.debug('spack install arguments: {0}'.format(
|
||||
install_args))
|
||||
|
||||
# Write the install command to a shell script
|
||||
with open('install.sh', 'w') as fd:
|
||||
fd.write('#!/bin/bash\n\n')
|
||||
fd.write('\n# spack install command\n')
|
||||
fd.write(' '.join(['"{0}"'.format(i) for i in install_args]))
|
||||
fd.write('\n')
|
||||
|
||||
st = os.stat('install.sh')
|
||||
os.chmod('install.sh', st.st_mode | stat.S_IEXEC)
|
||||
|
||||
install_copy_path = os.path.join(repro_dir, 'install.sh')
|
||||
shutil.copyfile('install.sh', install_copy_path)
|
||||
|
||||
# Run the generated install.sh shell script as if it were being run in
|
||||
# a login shell.
|
||||
try:
|
||||
install_process = subprocess.Popen(['bash', '-l', './install.sh'])
|
||||
install_process.wait()
|
||||
install_exit_code = install_process.returncode
|
||||
except (ValueError, subprocess.CalledProcessError, OSError) as inst:
|
||||
tty.error('Encountered error running install script')
|
||||
tty.error(inst)
|
||||
|
||||
# Now do the post-install tasks
|
||||
tty.debug('spack install exited {0}'.format(install_exit_code))
|
||||
|
||||
# If a spec fails to build in a spack develop pipeline, we add it to a
|
||||
# list of known broken full hashes. This allows spack PR pipelines to
|
||||
# avoid wasting compute cycles attempting to build those hashes.
|
||||
if install_exit_code == 1 and spack_is_develop_pipeline:
|
||||
tty.debug('Install failed on develop')
|
||||
if 'broken-specs-url' in gitlab_ci:
|
||||
broken_specs_url = gitlab_ci['broken-specs-url']
|
||||
dev_fail_hash = job_spec.full_hash()
|
||||
broken_spec_path = url_util.join(broken_specs_url, dev_fail_hash)
|
||||
tty.msg('Reporting broken develop build as: {0}'.format(
|
||||
broken_spec_path))
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
empty_file_path = os.path.join(tmpdir, 'empty.txt')
|
||||
|
||||
try:
|
||||
with open(empty_file_path, 'w') as efd:
|
||||
efd.write('')
|
||||
web_util.push_to_url(
|
||||
empty_file_path,
|
||||
broken_spec_path,
|
||||
keep_original=False,
|
||||
extra_args={'ContentType': 'text/plain'})
|
||||
except Exception as err:
|
||||
# If we got some kind of S3 (access denied or other connection
|
||||
# error), the first non boto-specific class in the exception
|
||||
# hierarchy is Exception. Just print a warning and return
|
||||
msg = 'Error writing to broken specs list {0}: {1}'.format(
|
||||
broken_spec_path, err)
|
||||
tty.warn(msg)
|
||||
finally:
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
# We generated the "spack install ..." command to "--keep-stage", copy
|
||||
# any logs from the staging directory to artifacts now
|
||||
spack_ci.copy_stage_logs_to_artifacts(job_spec, job_log_dir)
|
||||
|
||||
# Create buildcache on remote mirror, either on pr-specific mirror or
|
||||
# on the main mirror defined in the gitlab-enabled spack environment
|
||||
if spack_is_pr_pipeline:
|
||||
buildcache_mirror_url = pr_mirror_url
|
||||
else:
|
||||
buildcache_mirror_url = remote_mirror_url
|
||||
|
||||
# If the install succeeded, create a buildcache entry for this job spec
|
||||
# and push it to one or more mirrors. If the install did not succeed,
|
||||
# print out some instructions on how to reproduce this build failure
|
||||
# outside of the pipeline environment.
|
||||
if install_exit_code == 0:
|
||||
can_sign = spack_ci.can_sign_binaries()
|
||||
sign_binaries = can_sign and spack_is_pr_pipeline is False
|
||||
|
||||
can_verify = spack_ci.can_verify_binaries()
|
||||
verify_binaries = can_verify and spack_is_pr_pipeline is False
|
||||
|
||||
spack_ci.configure_compilers(compiler_action)
|
||||
|
||||
spec_map = spack_ci.get_concrete_specs(
|
||||
root_spec, job_spec_pkg_name, related_builds, compiler_action)
|
||||
|
||||
job_spec = spec_map[job_spec_pkg_name]
|
||||
|
||||
tty.debug('Here is the concrete spec: {0}'.format(job_spec))
|
||||
|
||||
with open(job_spec_yaml_path, 'w') as fd:
|
||||
fd.write(job_spec.to_yaml(hash=ht.build_hash))
|
||||
|
||||
tty.debug('Done writing concrete spec')
|
||||
|
||||
# DEBUG
|
||||
with open(job_spec_yaml_path) as fd:
|
||||
tty.debug('Wrote spec file, read it back. Contents:')
|
||||
tty.debug(fd.read())
|
||||
|
||||
# DEBUG the root spec
|
||||
root_spec_yaml_path = os.path.join(spec_dir, 'root.yaml')
|
||||
with open(root_spec_yaml_path, 'w') as fd:
|
||||
fd.write(spec_map['root'].to_yaml(hash=ht.build_hash))
|
||||
|
||||
# TODO: Refactor the spack install command so it's easier to use from
|
||||
# python modules. Currently we use "exe.which('spack')" to make it
|
||||
# easier to install packages from here, but it introduces some
|
||||
# problems, e.g. if we want the spack command to have access to the
|
||||
# mirrors we're configuring, then we have to use the "spack" command
|
||||
# to add the mirrors too, which in turn means that any code here *not*
|
||||
# using the spack command does *not* have access to the mirrors.
|
||||
spack_cmd = exe.which('spack')
|
||||
mirrors_to_check = {
|
||||
'ci_remote_mirror': remote_mirror_url,
|
||||
}
|
||||
|
||||
def add_mirror(mirror_name, mirror_url):
|
||||
m_args = ['mirror', 'add', mirror_name, mirror_url]
|
||||
tty.debug('Adding mirror: spack {0}'.format(m_args))
|
||||
mirror_add_output = spack_cmd(*m_args)
|
||||
# Workaround: Adding the mirrors above, using "spack_cmd" makes
|
||||
# sure they're available later when we use "spack_cmd" to install
|
||||
# the package. But then we also need to add them to this dict
|
||||
# below, so they're available in this process (we end up having to
|
||||
# pass them to "bindist.get_mirrors_for_spec()")
|
||||
mirrors_to_check[mirror_name] = mirror_url
|
||||
tty.debug('spack mirror add output: {0}'.format(mirror_add_output))
|
||||
|
||||
# Configure mirrors
|
||||
if pr_mirror_url:
|
||||
add_mirror('ci_pr_mirror', pr_mirror_url)
|
||||
|
||||
if pipeline_mirror_url:
|
||||
add_mirror(spack_ci.TEMP_STORAGE_MIRROR_NAME, pipeline_mirror_url)
|
||||
|
||||
tty.debug('listing spack mirrors:')
|
||||
spack_cmd('mirror', 'list')
|
||||
spack_cmd('config', 'blame', 'mirrors')
|
||||
|
||||
# Checks all mirrors for a built spec with a matching full hash
|
||||
matches = bindist.get_mirrors_for_spec(
|
||||
job_spec, full_hash_match=True, mirrors_to_check=mirrors_to_check,
|
||||
index_only=False)
|
||||
|
||||
if matches:
|
||||
# Got at full hash match on at least one configured mirror. All
|
||||
# matches represent the fully up-to-date spec, so should all be
|
||||
# equivalent. If artifacts mirror is enabled, we just pick one
|
||||
# of the matches and download the buildcache files from there to
|
||||
# the artifacts, so they're available to be used by dependent
|
||||
# jobs in subsequent stages.
|
||||
tty.debug('No need to rebuild {0}'.format(job_spec_pkg_name))
|
||||
if enable_artifacts_mirror:
|
||||
matching_mirror = matches[0]['mirror_url']
|
||||
tty.debug('Getting {0} buildcache from {1}'.format(
|
||||
job_spec_pkg_name, matching_mirror))
|
||||
tty.debug('Downloading to {0}'.format(build_cache_dir))
|
||||
buildcache.download_buildcache_files(
|
||||
job_spec, build_cache_dir, True, matching_mirror)
|
||||
else:
|
||||
# No full hash match anywhere means we need to rebuild spec
|
||||
|
||||
# Build up common install arguments
|
||||
install_args = [
|
||||
'-d', '-v', '-k', 'install',
|
||||
'--keep-stage',
|
||||
'--require-full-hash-match',
|
||||
]
|
||||
|
||||
if not verify_binaries:
|
||||
install_args.append('--no-check-signature')
|
||||
|
||||
# Add arguments to create + register a new build on CDash (if
|
||||
# enabled)
|
||||
if enable_cdash:
|
||||
tty.debug('Registering build with CDash')
|
||||
(cdash_build_id,
|
||||
cdash_build_stamp) = spack_ci.register_cdash_build(
|
||||
cdash_build_name, cdash_base_url, cdash_project,
|
||||
cdash_site, job_spec_buildgroup)
|
||||
|
||||
cdash_upload_url = '{0}/submit.php?project={1}'.format(
|
||||
cdash_base_url, cdash_project_enc)
|
||||
|
||||
install_args.extend([
|
||||
'--cdash-upload-url', cdash_upload_url,
|
||||
'--cdash-build', cdash_build_name,
|
||||
'--cdash-site', cdash_site,
|
||||
'--cdash-buildstamp', cdash_build_stamp,
|
||||
])
|
||||
|
||||
install_args.append(job_spec_yaml_path)
|
||||
|
||||
tty.debug('Installing {0} from source'.format(job_spec.name))
|
||||
|
||||
try:
|
||||
tty.debug('spack install arguments: {0}'.format(
|
||||
install_args))
|
||||
spack_cmd(*install_args)
|
||||
finally:
|
||||
spack_ci.copy_stage_logs_to_artifacts(job_spec, job_log_dir)
|
||||
|
||||
# Create buildcache on remote mirror, either on pr-specific
|
||||
# mirror or on mirror defined in spack environment
|
||||
if spack_is_pr_pipeline:
|
||||
buildcache_mirror_url = pr_mirror_url
|
||||
else:
|
||||
buildcache_mirror_url = remote_mirror_url
|
||||
|
||||
# Create buildcache in either the main remote mirror, or in the
|
||||
# per-PR mirror, if this is a PR pipeline
|
||||
# Create buildcache in either the main remote mirror, or in the
|
||||
# per-PR mirror, if this is a PR pipeline
|
||||
if buildcache_mirror_url:
|
||||
spack_ci.push_mirror_contents(
|
||||
env, job_spec, job_spec_yaml_path, buildcache_mirror_url,
|
||||
cdash_build_id, sign_binaries)
|
||||
sign_binaries)
|
||||
|
||||
# Create another copy of that buildcache in the per-pipeline
|
||||
# temporary storage mirror (this is only done if either artifacts
|
||||
# buildcache is enabled or a temporary storage url prefix is set)
|
||||
if cdash_build_id:
|
||||
tty.debug('Writing cdashid ({0}) to remote mirror: {1}'.format(
|
||||
cdash_build_id, buildcache_mirror_url))
|
||||
spack_ci.write_cdashid_to_mirror(
|
||||
cdash_build_id, job_spec, buildcache_mirror_url)
|
||||
|
||||
# Create another copy of that buildcache in the per-pipeline
|
||||
# temporary storage mirror (this is only done if either
|
||||
# artifacts buildcache is enabled or a temporary storage url
|
||||
# prefix is set)
|
||||
if pipeline_mirror_url:
|
||||
spack_ci.push_mirror_contents(
|
||||
env, job_spec, job_spec_yaml_path, pipeline_mirror_url,
|
||||
cdash_build_id, sign_binaries)
|
||||
sign_binaries)
|
||||
|
||||
# Relate this build to its dependencies on CDash (if enabled)
|
||||
if enable_cdash:
|
||||
spack_ci.relate_cdash_builds(
|
||||
spec_map, cdash_base_url, cdash_build_id, cdash_project,
|
||||
pipeline_mirror_url or pr_mirror_url or remote_mirror_url)
|
||||
if cdash_build_id:
|
||||
tty.debug('Writing cdashid ({0}) to remote mirror: {1}'.format(
|
||||
cdash_build_id, pipeline_mirror_url))
|
||||
spack_ci.write_cdashid_to_mirror(
|
||||
cdash_build_id, job_spec, pipeline_mirror_url)
|
||||
else:
|
||||
tty.debug('spack install exited non-zero, will not create buildcache')
|
||||
|
||||
api_root_url = get_env_var('CI_API_V4_URL')
|
||||
ci_project_id = get_env_var('CI_PROJECT_ID')
|
||||
ci_job_id = get_env_var('CI_JOB_ID')
|
||||
|
||||
repro_job_url = '{0}/projects/{1}/jobs/{2}/artifacts'.format(
|
||||
api_root_url, ci_project_id, ci_job_id)
|
||||
|
||||
# Control characters cause this to be printed in blue so it stands out
|
||||
reproduce_msg = """
|
||||
|
||||
\033[34mTo reproduce this build locally, run:
|
||||
|
||||
spack ci reproduce-build {0} [--working-dir <dir>]
|
||||
|
||||
If this project does not have public pipelines, you will need to first:
|
||||
|
||||
export GITLAB_PRIVATE_TOKEN=<generated_token>
|
||||
|
||||
... then follow the printed instructions.\033[0;0m
|
||||
|
||||
""".format(repro_job_url)
|
||||
|
||||
print(reproduce_msg)
|
||||
|
||||
# Tie job success/failure to the success/failure of building the spec
|
||||
return install_exit_code
|
||||
|
||||
|
||||
def ci_reindex(args):
|
||||
"""Rebuild the buildcache index associated with the mirror in the
|
||||
active, gitlab-enabled environment. """
|
||||
env = ev.get_env(args, 'ci rebuild-index', required=True)
|
||||
yaml_root = ev.config_dict(env.yaml)
|
||||
def ci_reproduce(args):
|
||||
job_url = args.job_url
|
||||
work_dir = args.working_dir
|
||||
|
||||
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')
|
||||
|
||||
ci_mirrors = yaml_root['mirrors']
|
||||
mirror_urls = [url for url in ci_mirrors.values()]
|
||||
remote_mirror_url = mirror_urls[0]
|
||||
|
||||
buildcache.update_index(remote_mirror_url, update_keys=True)
|
||||
return spack_ci.reproduce_ci_job(job_url, work_dir)
|
||||
|
||||
|
||||
def ci(parser, args):
|
||||
if args.func:
|
||||
args.func(args)
|
||||
return args.func(args)
|
||||
|
||||
@@ -10,15 +10,14 @@
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.caches
|
||||
import spack.config
|
||||
import spack.cmd.test
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.cmd.test
|
||||
import spack.config
|
||||
import spack.main
|
||||
import spack.repo
|
||||
import spack.stage
|
||||
from spack.paths import lib_path, var_path
|
||||
|
||||
|
||||
description = "remove temporary build files and/or downloaded archives"
|
||||
section = "build"
|
||||
level = "long"
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
import llnl.util.filesystem as fs
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.argparsewriter import (
|
||||
ArgparseWriter, ArgparseRstWriter, ArgparseCompletionWriter
|
||||
ArgparseCompletionWriter,
|
||||
ArgparseRstWriter,
|
||||
ArgparseWriter,
|
||||
)
|
||||
from llnl.util.tty.colify import colify
|
||||
|
||||
@@ -23,7 +25,6 @@
|
||||
import spack.paths
|
||||
from spack.main import section_descriptions
|
||||
|
||||
|
||||
description = "list available spack commands"
|
||||
section = "developer"
|
||||
level = "long"
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
import os
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.build_environment as build_environment
|
||||
import spack.paths
|
||||
import spack.cmd
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.paths
|
||||
from spack.util.environment import dump_environment, pickle_environment
|
||||
|
||||
|
||||
|
||||
@@ -7,16 +7,18 @@
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from six import iteritems
|
||||
|
||||
import llnl.util.tty as tty
|
||||
import spack.compilers
|
||||
import spack.config
|
||||
import spack.spec
|
||||
from llnl.util.lang import index_by
|
||||
from llnl.util.tty.colify import colify
|
||||
from llnl.util.tty.color import colorize
|
||||
from spack.spec import CompilerSpec, ArchSpec
|
||||
|
||||
import spack.compilers
|
||||
import spack.config
|
||||
import spack.spec
|
||||
from spack.spec import ArchSpec, CompilerSpec
|
||||
|
||||
description = "manage compilers"
|
||||
section = "system"
|
||||
|
||||
@@ -10,15 +10,16 @@
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
import llnl.util.tty as tty
|
||||
import spack.config
|
||||
|
||||
import spack.cmd.common.arguments
|
||||
import spack.schema.env
|
||||
import spack.config
|
||||
import spack.environment as ev
|
||||
import spack.repo
|
||||
import spack.schema.env
|
||||
import spack.schema.packages
|
||||
import spack.store
|
||||
import spack.util.spack_yaml as syaml
|
||||
from spack.util.editor import editor
|
||||
import spack.store
|
||||
import spack.repo
|
||||
|
||||
description = "get and set configuration options"
|
||||
section = "config"
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import spack.container
|
||||
import spack.monitor
|
||||
|
||||
description = ("creates recipes to build images for different"
|
||||
" container runtimes")
|
||||
@@ -12,6 +14,10 @@
|
||||
level = "long"
|
||||
|
||||
|
||||
def setup_parser(subparser):
|
||||
monitor_group = spack.monitor.get_monitor_group(subparser) # noqa
|
||||
|
||||
|
||||
def containerize(parser, args):
|
||||
config_dir = args.env_dir or os.getcwd()
|
||||
config_file = os.path.abspath(os.path.join(config_dir, 'spack.yaml'))
|
||||
@@ -21,5 +27,12 @@ def containerize(parser, args):
|
||||
|
||||
config = spack.container.validate(config_file)
|
||||
|
||||
# If we have a monitor request, add monitor metadata to config
|
||||
if args.use_monitor:
|
||||
config['spack']['monitor'] = {"disable_auth": args.monitor_disable_auth,
|
||||
"host": args.monitor_host,
|
||||
"keep_going": args.monitor_keep_going,
|
||||
"prefix": args.monitor_prefix,
|
||||
"tags": args.monitor_tags}
|
||||
recipe = spack.container.recipe(config)
|
||||
print(recipe)
|
||||
|
||||
@@ -11,16 +11,23 @@
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import mkdirp
|
||||
|
||||
import spack.util.web
|
||||
import spack.repo
|
||||
import spack.stage
|
||||
import spack.util.web
|
||||
from spack.spec import Spec
|
||||
from spack.url import (
|
||||
UndetectableNameError,
|
||||
UndetectableVersionError,
|
||||
parse_name,
|
||||
parse_version,
|
||||
)
|
||||
from spack.util.editor import editor
|
||||
from spack.util.executable import which, ProcessError
|
||||
from spack.util.naming import mod_to_class
|
||||
from spack.util.naming import simplify_name, valid_fully_qualified_module_name
|
||||
from spack.url import UndetectableNameError, UndetectableVersionError
|
||||
from spack.url import parse_name, parse_version
|
||||
from spack.util.executable import ProcessError, which
|
||||
from spack.util.naming import (
|
||||
mod_to_class,
|
||||
simplify_name,
|
||||
valid_fully_qualified_module_name,
|
||||
)
|
||||
|
||||
description = "create a new package file"
|
||||
section = "packaging"
|
||||
|
||||
@@ -14,18 +14,18 @@
|
||||
installation and its deprecator.
|
||||
'''
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.cmd
|
||||
import spack.store
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.environment as ev
|
||||
|
||||
from spack.error import SpackError
|
||||
import spack.store
|
||||
from spack.database import InstallStatuses
|
||||
from spack.error import SpackError
|
||||
|
||||
description = "Replace one package with another via symlinks"
|
||||
section = "admin"
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import sys
|
||||
import os
|
||||
import sys
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.config
|
||||
import spack.cmd
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.config
|
||||
import spack.repo
|
||||
|
||||
description = "developer build: build from code in current working directory"
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
import spack.cmd
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.environment as ev
|
||||
|
||||
from spack.error import SpackError
|
||||
|
||||
description = "add a spec to an environment's dev-build information"
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import os
|
||||
import glob
|
||||
import os
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
|
||||
@@ -8,22 +8,21 @@
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
|
||||
import llnl.util.tty as tty
|
||||
import llnl.util.filesystem as fs
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.tty.colify import colify
|
||||
from llnl.util.tty.color import colorize
|
||||
|
||||
import spack.config
|
||||
import spack.schema.env
|
||||
import spack.cmd.common.arguments
|
||||
import spack.cmd.install
|
||||
import spack.cmd.uninstall
|
||||
import spack.cmd.modules
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.cmd.install
|
||||
import spack.cmd.modules
|
||||
import spack.cmd.uninstall
|
||||
import spack.config
|
||||
import spack.environment as ev
|
||||
import spack.schema.env
|
||||
import spack.util.string as string
|
||||
|
||||
|
||||
description = "manage virtual environments"
|
||||
section = "environments"
|
||||
level = "short"
|
||||
@@ -363,6 +362,9 @@ def env_loads_setup_parser(subparser):
|
||||
"""list modules for an installed environment '(see spack module loads)'"""
|
||||
subparser.add_argument(
|
||||
'env', nargs='?', help='name of env to generate loads file for')
|
||||
subparser.add_argument(
|
||||
'-n', '--module-set-name', default='default',
|
||||
help='module set for which to generate load operations')
|
||||
subparser.add_argument(
|
||||
'-m', '--module-type', choices=('tcl', 'lmod'),
|
||||
help='type of module system to generate loads for')
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.tty.colify import colify
|
||||
|
||||
import spack.environment as ev
|
||||
import spack.cmd as cmd
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.environment as ev
|
||||
import spack.repo
|
||||
import spack.store
|
||||
from spack.filesystem_view import YamlFilesystemView
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
import sys
|
||||
from collections import defaultdict, namedtuple
|
||||
|
||||
import six
|
||||
|
||||
import llnl.util.filesystem
|
||||
import llnl.util.tty as tty
|
||||
import llnl.util.tty.colify as colify
|
||||
import six
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
import spack.cmd.common.arguments
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
import llnl.util.lang
|
||||
import llnl.util.tty as tty
|
||||
import llnl.util.tty.color as color
|
||||
import llnl.util.lang
|
||||
|
||||
import spack.environment as ev
|
||||
import spack.repo
|
||||
import spack.cmd as cmd
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.environment as ev
|
||||
import spack.repo
|
||||
import spack.user_environment as uenv
|
||||
from spack.util.string import plural
|
||||
from spack.database import InstallStatuses
|
||||
from spack.util.string import plural
|
||||
|
||||
description = "list and search installed packages"
|
||||
section = "basic"
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
import spack.cmd.style
|
||||
|
||||
|
||||
description = "alias for spack style (deprecated)"
|
||||
section = spack.cmd.style.section
|
||||
level = spack.cmd.style.level
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user