Compare commits
1761 Commits
green-3.3.
...
laverne
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d3591db9c | ||
|
|
753f79806b | ||
|
|
50ece536ae | ||
|
|
fdcda41c5e | ||
|
|
6ceab2c76d | ||
|
|
0b8fcb95dd | ||
|
|
45526f5ecf | ||
|
|
d1fd60f69d | ||
|
|
7fa2b1c154 | ||
|
|
fd7a07b3a2 | ||
|
|
01bc47f4d4 | ||
|
|
12a3d41a24 | ||
|
|
ce4f835679 | ||
|
|
54f08d23cd | ||
|
|
8a3d0f375c | ||
|
|
0c2003f134 | ||
|
|
6e71b0a012 | ||
|
|
4b5c1c0530 | ||
|
|
171e709ae6 | ||
|
|
a8b8557e4c | ||
|
|
399e6b8008 | ||
|
|
290280b332 | ||
|
|
9e11fbf904 | ||
|
|
0f8244faba | ||
|
|
0cc23a8656 | ||
|
|
30c39cc97c | ||
|
|
261ca88596 | ||
|
|
72ddd5c202 | ||
|
|
6026999e81 | ||
|
|
c5ab4d56f9 | ||
|
|
b9d6950732 | ||
|
|
95b64df744 | ||
|
|
941855f0c0 | ||
|
|
17641a7ead | ||
|
|
c6e842d9f5 | ||
|
|
372186ff62 | ||
|
|
c718ef5b60 | ||
|
|
e160e68136 | ||
|
|
c42340603f | ||
|
|
1a0cf646cf | ||
|
|
3ed9ba33a3 | ||
|
|
88ff0a4470 | ||
|
|
7b6db199fa | ||
|
|
a28bc0d0b6 | ||
|
|
47cfaec4ea | ||
|
|
59df74164d | ||
|
|
b5419d931e | ||
|
|
1ddda942bd | ||
|
|
c115f07678 | ||
|
|
73be41e475 | ||
|
|
b96412845d | ||
|
|
f0c88f220e | ||
|
|
1a3140eaf6 | ||
|
|
e34401720d | ||
|
|
72aadcf274 | ||
|
|
411910bb98 | ||
|
|
23bae7e299 | ||
|
|
13642c439c | ||
|
|
784f9b3369 | ||
|
|
0826752c04 | ||
|
|
a168d77ea9 | ||
|
|
297c60afd8 | ||
|
|
0f49a2c359 | ||
|
|
37eec34886 | ||
|
|
2e793fe2bf | ||
|
|
2bf160150f | ||
|
|
c3a5bee36f | ||
|
|
4a5a659674 | ||
|
|
ce18dde858 | ||
|
|
e51e4870f0 | ||
|
|
440a4cfffb | ||
|
|
779288f438 | ||
|
|
c3fa1a6677 | ||
|
|
e8ea66f5ff | ||
|
|
476242adc4 | ||
|
|
e9ef9424a3 | ||
|
|
fc9c11de28 | ||
|
|
4ae9c0785e | ||
|
|
ef670167cd | ||
|
|
daca4c7469 | ||
|
|
644e54fef9 | ||
|
|
f8c6335e95 | ||
|
|
3d91a51a8e | ||
|
|
64bb014ea6 | ||
|
|
1dc2a4c17b | ||
|
|
77176d56fd | ||
|
|
2c40e13634 | ||
|
|
8fc871a814 | ||
|
|
fd59449f5b | ||
|
|
d3099f8f5c | ||
|
|
20b4aa30c9 | ||
|
|
80eba26fb1 | ||
|
|
0be66f0e88 | ||
|
|
879ac8fb9f | ||
|
|
95cf36fbd1 | ||
|
|
37eb4e2b93 | ||
|
|
94c2a3c0ab | ||
|
|
2208328791 | ||
|
|
13a702e9e5 | ||
|
|
485839d873 | ||
|
|
d036f97b62 | ||
|
|
ce8932d28d | ||
|
|
f0500bc699 | ||
|
|
03ecd2a3f4 | ||
|
|
3a8d109c85 | ||
|
|
12477ad2b2 | ||
|
|
95fb69bb24 | ||
|
|
9a2ae44380 | ||
|
|
7d7d35f369 | ||
|
|
af404b1372 | ||
|
|
65954baaa3 | ||
|
|
deba7adc4b | ||
|
|
cb34a1496a | ||
|
|
229b6630af | ||
|
|
fa91404055 | ||
|
|
462aef73fa | ||
|
|
9eb2de9163 | ||
|
|
a2337a3435 | ||
|
|
cbeb72b90d | ||
|
|
48755c4bc6 | ||
|
|
5e558a17f2 | ||
|
|
d3fbeb9833 | ||
|
|
41ad94640b | ||
|
|
e1f257af7b | ||
|
|
b2c3ce6d17 | ||
|
|
271bd9d8f9 | ||
|
|
d393edda26 | ||
|
|
99c0cbd6d6 | ||
|
|
1958497f00 | ||
|
|
27e785cb28 | ||
|
|
c6a6eb18c2 | ||
|
|
812f8835d2 | ||
|
|
35f36bac42 | ||
|
|
04ace8380c | ||
|
|
c9b6051f2c | ||
|
|
5ae1e2c9e8 | ||
|
|
149f226213 | ||
|
|
b5f744c5d6 | ||
|
|
6b53fbcc20 | ||
|
|
364aaa6dfa | ||
|
|
cecd1bdf6f | ||
|
|
75732f5443 | ||
|
|
daa21c1e0a | ||
|
|
fa647b9176 | ||
|
|
b2f2590e6c | ||
|
|
5783e717ee | ||
|
|
86b30f722e | ||
|
|
d4c86791aa | ||
|
|
56be122d35 | ||
|
|
d14f9bf6c4 | ||
|
|
ff539b11ac | ||
|
|
efe55d749a | ||
|
|
771fb55d6b | ||
|
|
ded2919f19 | ||
|
|
df41bd46dd | ||
|
|
e9af61e9c2 | ||
|
|
b9728f63c6 | ||
|
|
7836c45267 | ||
|
|
115514b5eb | ||
|
|
a743e823bc | ||
|
|
b8ce8c72d1 | ||
|
|
b825febaeb | ||
|
|
2f55ec4a52 | ||
|
|
b8d75d2a50 | ||
|
|
627fb75407 | ||
|
|
ee1c802ae2 | ||
|
|
fe9c556f56 | ||
|
|
6f66fc15c7 | ||
|
|
d7a1ebc81e | ||
|
|
1bc382586a | ||
|
|
ca664ee35d | ||
|
|
144e7b461d | ||
|
|
939e2fe270 | ||
|
|
530fb7fdea | ||
|
|
30f77f6182 | ||
|
|
1d7c9a9828 | ||
|
|
c805a6ed28 | ||
|
|
7cd824a538 | ||
|
|
e72e7b2fdc | ||
|
|
0ae7e9e2cb | ||
|
|
c449c78c25 | ||
|
|
5f17c07331 | ||
|
|
7d42965565 | ||
|
|
c47132ae66 | ||
|
|
45e05c1316 | ||
|
|
ad042da703 | ||
|
|
93c19abbc2 | ||
|
|
2f19e2a1e6 | ||
|
|
2e04061897 | ||
|
|
7b079e1d08 | ||
|
|
bda24caa5c | ||
|
|
ddb5d4c9af | ||
|
|
519b7c0dd3 | ||
|
|
02445fca7b | ||
|
|
0f973ed665 | ||
|
|
e70c8981f2 | ||
|
|
8532405c1d | ||
|
|
62625d0ca0 | ||
|
|
fcbd67c047 | ||
|
|
c8a181e847 | ||
|
|
fb24302125 | ||
|
|
bf1a37e40c | ||
|
|
f938a4199b | ||
|
|
50ba9c4d40 | ||
|
|
8a4298c71c | ||
|
|
7160dce02e | ||
|
|
bee7c21f6e | ||
|
|
240b6636f9 | ||
|
|
24ad63979f | ||
|
|
0e0fadb400 | ||
|
|
fafb40364d | ||
|
|
11ebcec445 | ||
|
|
0a20caf090 | ||
|
|
e12c57e877 | ||
|
|
60beb398cc | ||
|
|
5eee854f53 | ||
|
|
35d095c282 | ||
|
|
2d93cb0a0d | ||
|
|
425435f403 | ||
|
|
904ae4a753 | ||
|
|
0ee7a9e6bd | ||
|
|
8e5c0841ea | ||
|
|
a4f2e2af1b | ||
|
|
12b0f4903a | ||
|
|
1225cc4486 | ||
|
|
2fac07aa98 | ||
|
|
546ffc5fa5 | ||
|
|
ce7101b1f0 | ||
|
|
8223e50582 | ||
|
|
31bd1412e5 | ||
|
|
ce25e933a9 | ||
|
|
0cab41aac3 | ||
|
|
4163767c00 | ||
|
|
dd81d5882b | ||
|
|
8e429accb8 | ||
|
|
df07008f56 | ||
|
|
ce5e891d51 | ||
|
|
b9369741db | ||
|
|
8fdc5ff4c1 | ||
|
|
7cdddd1887 | ||
|
|
c112368e6f | ||
|
|
4a19330709 | ||
|
|
23f522e7a5 | ||
|
|
9a1d4d0c8d | ||
|
|
ca5fff3806 | ||
|
|
c0c657bd92 | ||
|
|
e71a306f9c | ||
|
|
c09cae578e | ||
|
|
a51df11c15 | ||
|
|
e3d7890cac | ||
|
|
c0281fa49b | ||
|
|
008c59cf83 | ||
|
|
96235897e6 | ||
|
|
27b68f9f4c | ||
|
|
7f17d12cfd | ||
|
|
9c9c8eb835 | ||
|
|
bf1747b4e5 | ||
|
|
a4762f928a | ||
|
|
84a4ef2df8 | ||
|
|
4ec740dded | ||
|
|
d4feb66a75 | ||
|
|
d8915153e2 | ||
|
|
c649698d90 | ||
|
|
a00a840fb7 | ||
|
|
784f0cfee7 | ||
|
|
8c7dfe89e1 | ||
|
|
3e5cf5f884 | ||
|
|
fe64be2fac | ||
|
|
6b1c260fa3 | ||
|
|
2a066e7ca9 | ||
|
|
b07cc5a74a | ||
|
|
aca435f238 | ||
|
|
1526b9d4d9 | ||
|
|
5848cc4db6 | ||
|
|
8d5b2224bd | ||
|
|
06c19f0cd0 | ||
|
|
4c9f98b4c7 | ||
|
|
41f19342f1 | ||
|
|
ce373c7cc3 | ||
|
|
fad896d4ea | ||
|
|
c9e6f53a11 | ||
|
|
82a42c6457 | ||
|
|
66bb71a25a | ||
|
|
041fe173cc | ||
|
|
ced8cb0809 | ||
|
|
bb1b3cfd53 | ||
|
|
69c650c277 | ||
|
|
1d52fa5269 | ||
|
|
1c91f32f5e | ||
|
|
adcb01d091 | ||
|
|
7f7c185cf1 | ||
|
|
62fe6dc755 | ||
|
|
e88a8951be | ||
|
|
b797a842ba | ||
|
|
2b18117820 | ||
|
|
22cbcd964f | ||
|
|
5f289ac80f | ||
|
|
53bfbe6b06 | ||
|
|
a598c15636 | ||
|
|
2624b61814 | ||
|
|
1e0e6f1185 | ||
|
|
624924bdcd | ||
|
|
97dec8410b | ||
|
|
dd28a9c516 | ||
|
|
7087fb788a | ||
|
|
9747616600 | ||
|
|
8976fa69d0 | ||
|
|
65ace927bd | ||
|
|
d6c4088f10 | ||
|
|
8860ef2449 | ||
|
|
a1d1e4e47d | ||
|
|
ec4d6b989a | ||
|
|
15ceaaaaf7 | ||
|
|
d85dc37b73 | ||
|
|
cf09c7a1e3 | ||
|
|
dd5ad1840d | ||
|
|
aa8dea4829 | ||
|
|
2cb33a983a | ||
|
|
928e6ca664 | ||
|
|
661e864a03 | ||
|
|
3b7110b519 | ||
|
|
5c46570185 | ||
|
|
62432db79d | ||
|
|
63ec0c2632 | ||
|
|
055a720359 | ||
|
|
7531480bbb | ||
|
|
59646974ab | ||
|
|
998a8316a2 | ||
|
|
0f55d28a4d | ||
|
|
5c8fad6544 | ||
|
|
ce456306da | ||
|
|
b3ef7f59e2 | ||
|
|
239a368d57 | ||
|
|
c5b9525263 | ||
|
|
09f1f6939e | ||
|
|
233af81e77 | ||
|
|
460954b1b3 | ||
|
|
b80483094f | ||
|
|
c9e52b05d5 | ||
|
|
efd25901aa | ||
|
|
23bfe02542 | ||
|
|
3c5984a5ba | ||
|
|
4a10634a88 | ||
|
|
1cf456611d | ||
|
|
f342f3ba68 | ||
|
|
8c33bfc84a | ||
|
|
11a92051e7 | ||
|
|
73049a3431 | ||
|
|
c0317494aa | ||
|
|
7450c1a2db | ||
|
|
68772b9103 | ||
|
|
eede7208aa | ||
|
|
d8137c014f | ||
|
|
d08f922083 | ||
|
|
79a4501a2e | ||
|
|
03d9669cbc | ||
|
|
0ff070bbf1 | ||
|
|
8e9caafd0b | ||
|
|
a50dd612ad | ||
|
|
87cac1db8c | ||
|
|
0be92981b3 | ||
|
|
a67d9dcaa9 | ||
|
|
089b1860c7 | ||
|
|
ad972a787c | ||
|
|
3a0b3da57b | ||
|
|
7c99ba8470 | ||
|
|
6295c9add5 | ||
|
|
83c005da5a | ||
|
|
3197bcfcbc | ||
|
|
d1ff9aa4f3 | ||
|
|
5b02bbcc32 | ||
|
|
f47ae202af | ||
|
|
fe0f86e15c | ||
|
|
474c2a2817 | ||
|
|
e888596636 | ||
|
|
19d9435a32 | ||
|
|
89c7260931 | ||
|
|
d94f0f74c1 | ||
|
|
4aec2155a5 | ||
|
|
c01e8760ba | ||
|
|
dc4d33cf0f | ||
|
|
919ae74811 | ||
|
|
6a16ff4c92 | ||
|
|
6cbc2c3b56 | ||
|
|
c541b598c8 | ||
|
|
9619df0969 | ||
|
|
be11510e21 | ||
|
|
2e9d981d76 | ||
|
|
c3269e20bf | ||
|
|
27dd7f82c9 | ||
|
|
d6e8013a8c | ||
|
|
b273ca2be0 | ||
|
|
b4c5b953c8 | ||
|
|
d87034e41a | ||
|
|
75bffcd47a | ||
|
|
ad30f2cc4e | ||
|
|
0a217cd18f | ||
|
|
8627258ac3 | ||
|
|
8c7e1aced8 | ||
|
|
2beaecb351 | ||
|
|
276abb19ce | ||
|
|
a6e7652944 | ||
|
|
3c6e1d7c62 | ||
|
|
7ef8658402 | ||
|
|
1ea9ad4df2 | ||
|
|
30c2b0bb84 | ||
|
|
566de26cf5 | ||
|
|
3a530fb3a3 | ||
|
|
c4fb6982c0 | ||
|
|
f7f044c220 | ||
|
|
c4ff5f3038 | ||
|
|
8e43883f97 | ||
|
|
3dd36ababd | ||
|
|
3d4089ca5e | ||
|
|
082976c05f | ||
|
|
9402f934b6 | ||
|
|
8fe347a851 | ||
|
|
be74657ced | ||
|
|
f7b1c1056e | ||
|
|
1e65495801 | ||
|
|
5b803e65d3 | ||
|
|
102e24d31a | ||
|
|
1f65837e78 | ||
|
|
7400ece674 | ||
|
|
ef8d4dc7d5 | ||
|
|
3f71edc3ef | ||
|
|
e3f492603e | ||
|
|
b98154a851 | ||
|
|
cdbbc68d08 | ||
|
|
75b90f1d6d | ||
|
|
3e7db72216 | ||
|
|
8be5593777 | ||
|
|
fac3ca94a2 | ||
|
|
04b8511614 | ||
|
|
3341e47b52 | ||
|
|
3010c96a3f | ||
|
|
c519aec68c | ||
|
|
7892add2de | ||
|
|
7117a4458b | ||
|
|
7b580b488c | ||
|
|
7ef65593aa | ||
|
|
51dd0269bc | ||
|
|
e8518d4b2e | ||
|
|
fb617bed6e | ||
|
|
8ee9aff079 | ||
|
|
b49bfb2244 | ||
|
|
b86a5977e1 | ||
|
|
e8fdc98779 | ||
|
|
7e46fc81d4 | ||
|
|
647713050b | ||
|
|
1c24729697 | ||
|
|
85cf6f3e97 | ||
|
|
9b800fe261 | ||
|
|
c97f3a5df4 | ||
|
|
13ef707ab1 | ||
|
|
f57a3d9508 | ||
|
|
d17a09376d | ||
|
|
fea28c22f4 | ||
|
|
e359e25dc7 | ||
|
|
95b2d9395e | ||
|
|
b78d5368cc | ||
|
|
aa3d81f67c | ||
|
|
e013185ac1 | ||
|
|
18ea4d2a30 | ||
|
|
d970584799 | ||
|
|
c849ec75e7 | ||
|
|
a9b715736f | ||
|
|
7b017195a3 | ||
|
|
162c652a2c | ||
|
|
1fb94b77f8 | ||
|
|
079b70a76c | ||
|
|
63f7b0a703 | ||
|
|
0843607a2b | ||
|
|
3e38d633c9 | ||
|
|
41d02d40ed | ||
|
|
e5fe433b14 | ||
|
|
02c122cb5e | ||
|
|
ee3e622999 | ||
|
|
33e2b4a8a7 | ||
|
|
8d764de25f | ||
|
|
43595fabbe | ||
|
|
453d8f49ac | ||
|
|
e8ed1454ae | ||
|
|
a6ce10e83e | ||
|
|
7e36135a7e | ||
|
|
a2116860eb | ||
|
|
1f1aac7a84 | ||
|
|
cd9379c390 | ||
|
|
7f286e28ec | ||
|
|
f5389267b0 | ||
|
|
d2febcce2b | ||
|
|
d6c45f0f11 | ||
|
|
2f68de1e88 | ||
|
|
84e1f5a689 | ||
|
|
9f60a6fbfb | ||
|
|
3d7431b71b | ||
|
|
7e80c6e446 | ||
|
|
5c1638ced3 | ||
|
|
9bf90ab9dd | ||
|
|
893713352a | ||
|
|
c840412b69 | ||
|
|
3be379dea3 | ||
|
|
47423b530f | ||
|
|
dea8d65f3c | ||
|
|
c398c16aa5 | ||
|
|
883b09fefe | ||
|
|
2eeb0943ac | ||
|
|
558ef57097 | ||
|
|
a6c83e0620 | ||
|
|
1ff9c93e49 | ||
|
|
80993c4e1b | ||
|
|
4b611b6674 | ||
|
|
379ba0e9d7 | ||
|
|
84f7f70308 | ||
|
|
431c97533b | ||
|
|
0d7bcdf9fd | ||
|
|
36aa00b6f7 | ||
|
|
a7e14518ee | ||
|
|
7b3f400a36 | ||
|
|
561d875404 | ||
|
|
436d590c4a | ||
|
|
a206fce2ba | ||
|
|
a8339e56e1 | ||
|
|
d3fd98efd5 | ||
|
|
748b7da6ab | ||
|
|
429015a47f | ||
|
|
0bd7fc55a1 | ||
|
|
3f7f13da8c | ||
|
|
c4ecd356d1 | ||
|
|
8232e01437 | ||
|
|
c56bab6b25 | ||
|
|
2c54c5574e | ||
|
|
e384d62afa | ||
|
|
ff9f1021c8 | ||
|
|
118c36466c | ||
|
|
dd5509458f | ||
|
|
33ed325337 | ||
|
|
6c098ebe42 | ||
|
|
f2011318ec | ||
|
|
df894c658d | ||
|
|
8cbf96aeaf | ||
|
|
45c8f613cf | ||
|
|
2426f14285 | ||
|
|
8289cd4170 | ||
|
|
93914e120c | ||
|
|
094d5d7891 | ||
|
|
131d268752 | ||
|
|
65a490585e | ||
|
|
a4141e1c11 | ||
|
|
68385456af | ||
|
|
444e448065 | ||
|
|
d59456563e | ||
|
|
c52fcafe55 | ||
|
|
d62ee7eaf2 | ||
|
|
caab7fc509 | ||
|
|
232ef8430e | ||
|
|
5c229f921f | ||
|
|
b54e95fd06 | ||
|
|
94f2946679 | ||
|
|
d5bc20830d | ||
|
|
dc5f45c4e1 | ||
|
|
b36e98043e | ||
|
|
8a13529172 | ||
|
|
43938f11af | ||
|
|
9c1d256783 | ||
|
|
1a326e97c0 | ||
|
|
be291999de | ||
|
|
a0b72c2971 | ||
|
|
adfd0e0434 | ||
|
|
d1f7c3f9cc | ||
|
|
09bffb70de | ||
|
|
1f0ba7c2b0 | ||
|
|
4c00be1ecb | ||
|
|
c595743e3f | ||
|
|
e055544ce1 | ||
|
|
03983e9647 | ||
|
|
3aa6e464aa | ||
|
|
9897b81e56 | ||
|
|
332c33af18 | ||
|
|
3492bff64a | ||
|
|
13fdd4ae5d | ||
|
|
f7627e4f67 | ||
|
|
e6566322bd | ||
|
|
e300aa0485 | ||
|
|
4a65458eba | ||
|
|
ca4a58a4eb | ||
|
|
f6917ad47b | ||
|
|
29d6678fd5 | ||
|
|
da49de6885 | ||
|
|
923f920a7c | ||
|
|
43e62c4493 | ||
|
|
46bdf066a4 | ||
|
|
51e05bbe6c | ||
|
|
7aa5f112b8 | ||
|
|
dd30a64fc1 | ||
|
|
119b69dd26 | ||
|
|
4c86c99be8 | ||
|
|
98bd03a508 | ||
|
|
cc0a7034c2 | ||
|
|
5bb55610f3 | ||
|
|
6bfeb80d57 | ||
|
|
8927e93ccd | ||
|
|
7c301b9640 | ||
|
|
e08ae7ea65 | ||
|
|
9a60cbcf48 | ||
|
|
6b039d0bb7 | ||
|
|
c3232ed2da | ||
|
|
63f33efdb9 | ||
|
|
cb73e943aa | ||
|
|
37f914dd72 | ||
|
|
084eb5a04d | ||
|
|
9f03fdd5c7 | ||
|
|
03df313715 | ||
|
|
7303807ef1 | ||
|
|
192d6994cb | ||
|
|
e76f76a37d | ||
|
|
70cd1ff43f | ||
|
|
4b2a355a31 | ||
|
|
5c7531f78c | ||
|
|
4a310f203d | ||
|
|
18c0da3c17 | ||
|
|
dd0fb80917 | ||
|
|
e10703aa5b | ||
|
|
8ea7fa6d4c | ||
|
|
d46c362a46 | ||
|
|
b66dc67c62 | ||
|
|
66790ecb4a | ||
|
|
196f6f2d20 | ||
|
|
1d0757f16b | ||
|
|
53ff069611 | ||
|
|
9a8b6447c6 | ||
|
|
59a3e98b04 | ||
|
|
55a046bd4c | ||
|
|
f29f9364a3 | ||
|
|
e37ee51157 | ||
|
|
f0f911a10d | ||
|
|
0741c3b8cb | ||
|
|
ca95d02ce0 | ||
|
|
203bf3f772 | ||
|
|
47f704ea74 | ||
|
|
b9f4ff1386 | ||
|
|
5977534d5f | ||
|
|
71a46a44a2 | ||
|
|
86c2b56705 | ||
|
|
ac9e6822f1 | ||
|
|
87dba4254b | ||
|
|
54e3a82d9c | ||
|
|
b4bef9ad8e | ||
|
|
5d2e88c3c2 | ||
|
|
6c12afd57d | ||
|
|
179e056519 | ||
|
|
e7e01e7831 | ||
|
|
a33579dc71 | ||
|
|
2cf104f7e0 | ||
|
|
15543017ec | ||
|
|
91818ff699 | ||
|
|
e8231e0950 | ||
|
|
9cb1b87640 | ||
|
|
ce2e0a027b | ||
|
|
d7d803fa1c | ||
|
|
3a0eeb8155 | ||
|
|
89ae21775c | ||
|
|
070096ec70 | ||
|
|
313bda1d87 | ||
|
|
c23da3d37e | ||
|
|
f203df83a5 | ||
|
|
81ff1ee237 | ||
|
|
4df9f11171 | ||
|
|
6ea1ed5f7b | ||
|
|
f35a8d4079 | ||
|
|
e4bc3e36e4 | ||
|
|
d9aa25a337 | ||
|
|
c791544bb0 | ||
|
|
b5b3825ce6 | ||
|
|
735210556d | ||
|
|
7e8f14d2d8 | ||
|
|
4cdaa1789a | ||
|
|
75b57d573c | ||
|
|
ac3452c431 | ||
|
|
616e75523b | ||
|
|
9708f9cba7 | ||
|
|
ca09a6f08c | ||
|
|
fac06aaf2a | ||
|
|
604f12722a | ||
|
|
9b8ae6ba45 | ||
|
|
4a8fe7fc99 | ||
|
|
6e3a3816d5 | ||
|
|
f070ee959c | ||
|
|
657188bfef | ||
|
|
084ec86402 | ||
|
|
7a0f6ceb81 | ||
|
|
3c539be84c | ||
|
|
6739a629e9 | ||
|
|
b6bfe14205 | ||
|
|
a45e1d54e1 | ||
|
|
369920107e | ||
|
|
29ca893649 | ||
|
|
c28973c160 | ||
|
|
0769e847cb | ||
|
|
14801197f9 | ||
|
|
c7a8029570 | ||
|
|
787c1cf811 | ||
|
|
41a364f59f | ||
|
|
84d96bac33 | ||
|
|
f5dcdf9181 | ||
|
|
26f34098c8 | ||
|
|
f626b8fc55 | ||
|
|
6752cdfbf8 | ||
|
|
86af749b5b | ||
|
|
23552a40fc | ||
|
|
90e8bc75e3 | ||
|
|
372f2f40c0 | ||
|
|
ec22c6287c | ||
|
|
a57add5307 | ||
|
|
8cfecea699 | ||
|
|
75c781ad95 | ||
|
|
e6743f8416 | ||
|
|
30b01f94c3 | ||
|
|
3ce480de27 | ||
|
|
65b068a5f8 | ||
|
|
96ec9f8a60 | ||
|
|
1db9ee5e8d | ||
|
|
d39434bcfc | ||
|
|
efadb43d67 | ||
|
|
84d31b8970 | ||
|
|
22bf3344b5 | ||
|
|
418cce9ee9 | ||
|
|
9ba6043530 | ||
|
|
5d9f37873d | ||
|
|
d7bc9b8ece | ||
|
|
26350bbd22 | ||
|
|
912480a3f6 | ||
|
|
72ccda630e | ||
|
|
54d6d75445 | ||
|
|
7025e6496e | ||
|
|
db5c145af1 | ||
|
|
07adcbaf97 | ||
|
|
94f63fa564 | ||
|
|
514d768673 | ||
|
|
67239d4251 | ||
|
|
cb5d51a485 | ||
|
|
e624b2700a | ||
|
|
2225e12142 | ||
|
|
a4aaaee39d | ||
|
|
8e8316c8f0 | ||
|
|
bfaeda03be | ||
|
|
8c498e5338 | ||
|
|
6fc5bdd1bb | ||
|
|
03ee90660e | ||
|
|
cedd774ced | ||
|
|
b8f64fe44c | ||
|
|
26db53b91f | ||
|
|
f53504d28c | ||
|
|
2d394b224a | ||
|
|
675259c82c | ||
|
|
512d3b713c | ||
|
|
2c11926528 | ||
|
|
e8ac5a76d9 | ||
|
|
a2e6b265ed | ||
|
|
aeb73bdf20 | ||
|
|
1c4cc60e28 | ||
|
|
2e0d6df6c1 | ||
|
|
bdb9da4847 | ||
|
|
ed5194052e | ||
|
|
bb75c18104 | ||
|
|
5abb132fec | ||
|
|
1766b2bc22 | ||
|
|
cca5090408 | ||
|
|
7b6700f5b8 | ||
|
|
295e142488 | ||
|
|
56c5f2a679 | ||
|
|
80ec77731b | ||
|
|
5f199e8b51 | ||
|
|
0eb96abfc9 | ||
|
|
3a7c857064 | ||
|
|
304f88f408 | ||
|
|
22ae6b193d | ||
|
|
6ffc4f2e04 | ||
|
|
199177bc29 | ||
|
|
f6535ea12a | ||
|
|
44d7c5678f | ||
|
|
46771a85b0 | ||
|
|
59e30ad05f | ||
|
|
72aa55b762 | ||
|
|
4f90c0c8c8 | ||
|
|
ab902e0d68 | ||
|
|
eaf2a94e11 | ||
|
|
e5052c493b | ||
|
|
1280503a59 | ||
|
|
858c0d930f | ||
|
|
a1a35a3668 | ||
|
|
a44754d9d6 | ||
|
|
806cc3d049 | ||
|
|
070f8f5fd8 | ||
|
|
4897393c05 | ||
|
|
0e60d04436 | ||
|
|
6cbd557cf5 | ||
|
|
f3292fa117 | ||
|
|
a18e9b4f93 | ||
|
|
0ea4b89649 | ||
|
|
76a17c1b5e | ||
|
|
2e0e656a15 | ||
|
|
07582c7761 | ||
|
|
28d70bcddb | ||
|
|
6c7bc9e2eb | ||
|
|
268b8cf263 | ||
|
|
d428c9f9e1 | ||
|
|
1c9f061d1f | ||
|
|
e101642a61 | ||
|
|
cf1e754b3f | ||
|
|
bb175ec208 | ||
|
|
9ef9b5e1a7 | ||
|
|
36e81a844b | ||
|
|
e4c1c8c92e | ||
|
|
19be6b407c | ||
|
|
a5884df90d | ||
|
|
dfd7e1f76b | ||
|
|
a525b27d00 | ||
|
|
9e9d45124a | ||
|
|
889c8ed31a | ||
|
|
6124cccddf | ||
|
|
9e2600b6b9 | ||
|
|
53f22c9b8b | ||
|
|
f05fd8dc5c | ||
|
|
69ac39b90e | ||
|
|
cb67b6d236 | ||
|
|
15bf2d5d31 | ||
|
|
a0dd61eb2b | ||
|
|
c33529794a | ||
|
|
650319cd74 | ||
|
|
6ef17f4b31 | ||
|
|
1842635ee8 | ||
|
|
8fd7cc38b5 | ||
|
|
d3630f8174 | ||
|
|
708db1ef52 | ||
|
|
f25d26de77 | ||
|
|
15ecd98c54 | ||
|
|
a52dc8a26a | ||
|
|
e710b42a00 | ||
|
|
7994c9a00e | ||
|
|
a924ea57ff | ||
|
|
55011c1f4b | ||
|
|
eaacd258d8 | ||
|
|
601464b497 | ||
|
|
bca283671f | ||
|
|
0025bbb903 | ||
|
|
607709f78d | ||
|
|
f4cb0870ac | ||
|
|
45d237b3bf | ||
|
|
8f284e4c05 | ||
|
|
0cc9ac7b72 | ||
|
|
a9d468c98d | ||
|
|
bdcf666d5b | ||
|
|
662f136795 | ||
|
|
0bb1016de1 | ||
|
|
680f8bf8ae | ||
|
|
28d52a2f7a | ||
|
|
56bbb27bb0 | ||
|
|
2c2e5dc146 | ||
|
|
4e2c84f6b4 | ||
|
|
aed7ee04fd | ||
|
|
f4322c6adb | ||
|
|
16d299c6ce | ||
|
|
8105d4381f | ||
|
|
9383074deb | ||
|
|
1fbcd2ca17 | ||
|
|
7b74364120 | ||
|
|
12f88767bc | ||
|
|
0f516fe9a0 | ||
|
|
b83179c87e | ||
|
|
f6ae8a4b3e | ||
|
|
ec8f5299d9 | ||
|
|
b3e41b5d1e | ||
|
|
ad8c5b61a4 | ||
|
|
0e3fc6dff2 | ||
|
|
191a288349 | ||
|
|
e6b6767369 | ||
|
|
29b4c2945f | ||
|
|
fa8c028fd0 | ||
|
|
d9b1d4312c | ||
|
|
a235e4195e | ||
|
|
983b094ed0 | ||
|
|
fe69012c2c | ||
|
|
24132e4cf1 | ||
|
|
4460087b83 | ||
|
|
40f50303c5 | ||
|
|
54bb4b4abd | ||
|
|
ba6a07b76c | ||
|
|
e4d743e0da | ||
|
|
71bf22d9db | ||
|
|
8f756a7bfd | ||
|
|
b8589c9fde | ||
|
|
754c54818d | ||
|
|
8362a98b8e | ||
|
|
cdece36231 | ||
|
|
5fba534b15 | ||
|
|
1acae1c500 | ||
|
|
620aece563 | ||
|
|
7325781e35 | ||
|
|
067863d38d | ||
|
|
8658f478b7 | ||
|
|
16877ce14b | ||
|
|
ae035f151f | ||
|
|
d9f22d4024 | ||
|
|
da1332a7dd | ||
|
|
7f8c1bfb08 | ||
|
|
049aaa0233 | ||
|
|
ab37f53c7b | ||
|
|
9d4a4295db | ||
|
|
637ad7ef8c | ||
|
|
218e441dd5 | ||
|
|
ea3cfbaf26 | ||
|
|
106de1f41c | ||
|
|
90e80aafbd | ||
|
|
c62be5367c | ||
|
|
fb10983b99 | ||
|
|
752435eb3b | ||
|
|
4a51ea5508 | ||
|
|
95e40d33f1 | ||
|
|
b01f7d73aa | ||
|
|
faf6b2d33e | ||
|
|
2685863618 | ||
|
|
78292128a6 | ||
|
|
7a18558925 | ||
|
|
43b8e66467 | ||
|
|
7edde59de4 | ||
|
|
36cfff8ed5 | ||
|
|
0babe2c507 | ||
|
|
0b60744a00 | ||
|
|
42df9e99a4 | ||
|
|
3a526152d9 | ||
|
|
ae2836692f | ||
|
|
ff0e858780 | ||
|
|
2e5df820ce | ||
|
|
53b11611e1 | ||
|
|
bcba4515e5 | ||
|
|
c28cbe7fed | ||
|
|
17326346ff | ||
|
|
c7c5c34188 | ||
|
|
722e27e448 | ||
|
|
4f19548bfb | ||
|
|
5e3da1b94e | ||
|
|
33ee4079a2 | ||
|
|
8b3f94e27d | ||
|
|
7069fb8542 | ||
|
|
62540b2a15 | ||
|
|
d668b80e86 | ||
|
|
8760cde94a | ||
|
|
60fa21d157 | ||
|
|
9fcba301fe | ||
|
|
a4fb2c9666 | ||
|
|
7de5081857 | ||
|
|
ac5a021032 | ||
|
|
80986444aa | ||
|
|
d6ba72ac34 | ||
|
|
cbea4ae33f | ||
|
|
3a1c456172 | ||
|
|
b0b3468b95 | ||
|
|
0d333290a5 | ||
|
|
6da4a6688c | ||
|
|
18b33a2ce5 | ||
|
|
36186e8dd6 | ||
|
|
0ff62b0462 | ||
|
|
f23b594087 | ||
|
|
d91b4f5c36 | ||
|
|
d007137a04 | ||
|
|
95bb97aeb6 | ||
|
|
00a42b73b6 | ||
|
|
ec6705a488 | ||
|
|
8bad275174 | ||
|
|
63d5652355 | ||
|
|
74388f763a | ||
|
|
6b1dae9a03 | ||
|
|
623017e9bb | ||
|
|
e1a6b7394f | ||
|
|
cf3f5debc0 | ||
|
|
e7dc96abd5 | ||
|
|
4129415ef7 | ||
|
|
e4f98097bc | ||
|
|
39d8556e04 | ||
|
|
a167678d14 | ||
|
|
c0a63c58cd | ||
|
|
95454d710d | ||
|
|
4c373043e4 | ||
|
|
066535608e | ||
|
|
28f8e3034c | ||
|
|
66d7b58f22 | ||
|
|
bf8023237c | ||
|
|
ab82312433 | ||
|
|
23f94ad59d | ||
|
|
989d2f794f | ||
|
|
3f5d3d7b99 | ||
|
|
b98e3e9c3f | ||
|
|
fbf2022c9a | ||
|
|
2efba78f9b | ||
|
|
f887d02527 | ||
|
|
dbc8892b09 | ||
|
|
833390e533 | ||
|
|
b18f1216b0 | ||
|
|
7459068915 | ||
|
|
0d18597ae7 | ||
|
|
c017d0eeb9 | ||
|
|
b4cc2b7829 | ||
|
|
1808105808 | ||
|
|
b7be3bab5b | ||
|
|
5eb1eece2f | ||
|
|
671f05a07f | ||
|
|
23707b04a4 | ||
|
|
33911454d2 | ||
|
|
408f124c86 | ||
|
|
410fc8dde8 | ||
|
|
c9602c5feb | ||
|
|
e35762d971 | ||
|
|
90ac746dcd | ||
|
|
dc54b7787f | ||
|
|
83cc54944e | ||
|
|
9832fd3e22 | ||
|
|
c2f71a86f5 | ||
|
|
2b84008bc9 | ||
|
|
7af8cb9d02 | ||
|
|
6d3a5ac679 | ||
|
|
ade4c8a3b2 | ||
|
|
7219087e6a | ||
|
|
d977cb25e5 | ||
|
|
3073a73214 | ||
|
|
c9076342fc | ||
|
|
897a8b5abc | ||
|
|
dc807f54f8 | ||
|
|
5c63f8a249 | ||
|
|
d9babfed3c | ||
|
|
ba8fad4058 | ||
|
|
b02be74889 | ||
|
|
c358150799 | ||
|
|
595bdde07c | ||
|
|
bbdc79881f | ||
|
|
e8e3ac9b1e | ||
|
|
0c3b1aa0a5 | ||
|
|
1df4e34d14 | ||
|
|
d8db718b89 | ||
|
|
b376a803ca | ||
|
|
8a251accbf | ||
|
|
d86e127ea0 | ||
|
|
856769b001 | ||
|
|
98cdb30558 | ||
|
|
afdebdb0c7 | ||
|
|
75fff51661 | ||
|
|
cb249ed2f0 | ||
|
|
0e0830109c | ||
|
|
314fbb1c05 | ||
|
|
1d0d3e4462 | ||
|
|
929169be0f | ||
|
|
12c929683f | ||
|
|
f193588428 | ||
|
|
6cb27d8b5b | ||
|
|
9f5e302741 | ||
|
|
cb1a0a46c9 | ||
|
|
36bc4592f4 | ||
|
|
21fae7e2ec | ||
|
|
7dcb5a2ea6 | ||
|
|
3668c10acb | ||
|
|
4c2bb35fe1 | ||
|
|
9618d56c29 | ||
|
|
2601e6d383 | ||
|
|
1763f004bb | ||
|
|
3deb487daa | ||
|
|
6b2eec3657 | ||
|
|
31c0972265 | ||
|
|
fcabff2f2f | ||
|
|
912a5c9c6a | ||
|
|
61d808bf4a | ||
|
|
e2fa1ec4e9 | ||
|
|
47a60ccef0 | ||
|
|
fb92046d99 | ||
|
|
ce8cb734a0 | ||
|
|
b8b678f010 | ||
|
|
37eb35995f | ||
|
|
2d63185175 | ||
|
|
dc5bcf7f94 | ||
|
|
521edcf978 | ||
|
|
5f3e66d5c2 | ||
|
|
c7c3b48486 | ||
|
|
69c907d39e | ||
|
|
ad0ac0ecd3 | ||
|
|
971907567c | ||
|
|
50629b3746 | ||
|
|
df563f0d28 | ||
|
|
f5495cf973 | ||
|
|
4dc54a274d | ||
|
|
d39ae18df2 | ||
|
|
ae6c323a0b | ||
|
|
9ee1fbb720 | ||
|
|
f0af0ba94a | ||
|
|
15624d13d0 | ||
|
|
3e86c5e644 | ||
|
|
68974e8e9f | ||
|
|
6915c7e8be | ||
|
|
a30162bac9 | ||
|
|
549a171917 | ||
|
|
dd05d05044 | ||
|
|
e17f8f7e40 | ||
|
|
46039a37ab | ||
|
|
231f58590e | ||
|
|
aff51932d1 | ||
|
|
b3e901c78c | ||
|
|
5e53061c13 | ||
|
|
8078a305aa | ||
|
|
84efdfb16a | ||
|
|
e4f0d88caf | ||
|
|
397793a0a4 | ||
|
|
d47fc7a107 | ||
|
|
a6ba63c70e | ||
|
|
0ba8e6f951 | ||
|
|
2df46a3609 | ||
|
|
648d76bda3 | ||
|
|
41e668e781 | ||
|
|
227fd49276 | ||
|
|
4661367660 | ||
|
|
77dff5267b | ||
|
|
1d1a559aa1 | ||
|
|
1564ef9c7a | ||
|
|
692065dc7d | ||
|
|
9710898615 | ||
|
|
97e7eed13a | ||
|
|
f828c0f290 | ||
|
|
29d5edffb0 | ||
|
|
1b6535dc2e | ||
|
|
f23aa92f08 | ||
|
|
63e6ba8567 | ||
|
|
c4fde248b1 | ||
|
|
2fc283c52d | ||
|
|
5e34400d57 | ||
|
|
6598f98ba8 | ||
|
|
8c23850453 | ||
|
|
009343b2a2 | ||
|
|
2d263840b0 | ||
|
|
3cd042f505 | ||
|
|
5c44f9a78d | ||
|
|
8a5b5080a2 | ||
|
|
90db9f3074 | ||
|
|
2fa0c30375 | ||
|
|
23363c990c | ||
|
|
2295705918 | ||
|
|
fd1d661b39 | ||
|
|
bd19169a60 | ||
|
|
21949128eb | ||
|
|
88dd324d41 | ||
|
|
868617258a | ||
|
|
0f19ae1b00 | ||
|
|
baf69e6a92 | ||
|
|
c50e585588 | ||
|
|
ab4ee45ba4 | ||
|
|
cc86905780 | ||
|
|
3b154ffbb6 | ||
|
|
04472ecf9d | ||
|
|
8fe2bb0123 | ||
|
|
f9262fabad | ||
|
|
f60aa088b3 | ||
|
|
abf39a181a | ||
|
|
3b25e33054 | ||
|
|
f0ebbd2158 | ||
|
|
d673ad0299 | ||
|
|
e1ed3900fa | ||
|
|
e388cb142a | ||
|
|
9522930256 | ||
|
|
2592f1c215 | ||
|
|
8994ce33d8 | ||
|
|
bdcecea903 | ||
|
|
78f2a2c406 | ||
|
|
168bf73c8e | ||
|
|
41acb50c3b | ||
|
|
67eeb71308 | ||
|
|
85d83ab01b | ||
|
|
be1279fdc8 | ||
|
|
0e7e3ae68a | ||
|
|
b64111f53b | ||
|
|
7a5eeeb58e | ||
|
|
b4a1dc580b | ||
|
|
bb2c55765b | ||
|
|
73914a8190 | ||
|
|
c66a05ac05 | ||
|
|
4cbef85afe | ||
|
|
de590e0e74 | ||
|
|
718510f541 | ||
|
|
7a92d3208c | ||
|
|
14e900213c | ||
|
|
13a8dc5903 | ||
|
|
608909d026 | ||
|
|
92bc5616ee | ||
|
|
689eecf577 | ||
|
|
da28607833 | ||
|
|
fb02061ece | ||
|
|
40421c1024 | ||
|
|
cd890ce6b4 | ||
|
|
119b8bf270 | ||
|
|
9b7907fae2 | ||
|
|
4e80041a4f | ||
|
|
b34271293a | ||
|
|
d42466ea43 | ||
|
|
f516cfcac0 | ||
|
|
e18aba581c | ||
|
|
936a73eae5 | ||
|
|
da46e7f705 | ||
|
|
24ea9ad1f7 | ||
|
|
c0a3d22076 | ||
|
|
f7a98901d9 | ||
|
|
3e9592e9da | ||
|
|
d1993fab7c | ||
|
|
7b46397e3a | ||
|
|
3451dc8187 | ||
|
|
5bd2ba7e23 | ||
|
|
8f033f5d29 | ||
|
|
bbd9ebf321 | ||
|
|
23dd7251a8 | ||
|
|
a604cb78cc | ||
|
|
424278c7bc | ||
|
|
8a556a8ca5 | ||
|
|
72210f8a6a | ||
|
|
62136a869a | ||
|
|
90ceeff258 | ||
|
|
43bd793679 | ||
|
|
59df5a4b2d | ||
|
|
5dcefd18d6 | ||
|
|
cf3796f663 | ||
|
|
fae8d5e985 | ||
|
|
ee4fc42908 | ||
|
|
4e3cb2adf5 | ||
|
|
da9f079481 | ||
|
|
b44d32ef41 | ||
|
|
2e04ea8754 | ||
|
|
7fa2815605 | ||
|
|
69a86f98a3 | ||
|
|
fd8cf68a01 | ||
|
|
37e6594c7c | ||
|
|
f481c5dd39 | ||
|
|
21d586b47c | ||
|
|
71466ea8b3 | ||
|
|
9e8ffdcda9 | ||
|
|
0976252a53 | ||
|
|
01af31aec2 | ||
|
|
0f8810e6be | ||
|
|
47b2545009 | ||
|
|
b56df3f573 | ||
|
|
330e32da12 | ||
|
|
4d4b7922b1 | ||
|
|
1497af07fa | ||
|
|
a644cd15eb | ||
|
|
d0eabcb633 | ||
|
|
053e64e14a | ||
|
|
e5520e20ab | ||
|
|
34e45d5e28 | ||
|
|
d42035d226 | ||
|
|
a367934c68 | ||
|
|
f594a1145e | ||
|
|
1d22846b48 | ||
|
|
912e9d234e | ||
|
|
d4a6c9ef8b | ||
|
|
52759ea577 | ||
|
|
8f88fd5483 | ||
|
|
cd7a91e968 | ||
|
|
45684232a5 | ||
|
|
669491b423 | ||
|
|
7ccf7af572 | ||
|
|
020022ad41 | ||
|
|
6a5a351c7d | ||
|
|
a60863a0a6 | ||
|
|
763be1f0f5 | ||
|
|
614b28d52b | ||
|
|
9bd229b8d3 | ||
|
|
128a2f7f51 | ||
|
|
15c9e54368 | ||
|
|
819a34a452 | ||
|
|
82597d379c | ||
|
|
322b26ae11 | ||
|
|
ee97395865 | ||
|
|
2836e04d60 | ||
|
|
e02887802f | ||
|
|
efdb82b4b5 | ||
|
|
95bc479d92 | ||
|
|
d6615c2940 | ||
|
|
d1b1378e9d | ||
|
|
f76cd262c3 | ||
|
|
5d1a64a298 | ||
|
|
c3a20314c2 | ||
|
|
788ffb75e7 | ||
|
|
f0c66927ae | ||
|
|
ffa0f7973b | ||
|
|
471892e200 | ||
|
|
dfe9854f48 | ||
|
|
715e03329b | ||
|
|
d65c8276e7 | ||
|
|
4e71fc76ad | ||
|
|
06ecb32bf3 | ||
|
|
5061f7be7d | ||
|
|
912f5b12de | ||
|
|
4d160902f8 | ||
|
|
64e5dd1aac | ||
|
|
2cfe0ca27f | ||
|
|
bbd41f4b96 | ||
|
|
47cc37d2d5 | ||
|
|
1478977ac3 | ||
|
|
9bb0fa9c1e | ||
|
|
b649f5c971 | ||
|
|
54f41e239e | ||
|
|
bd6b465ab9 | ||
|
|
0f321c8027 | ||
|
|
9f2b765e4f | ||
|
|
bac29db14c | ||
|
|
adcfc07f13 | ||
|
|
dd0760a38f | ||
|
|
a234ac09c1 | ||
|
|
b1c741031d | ||
|
|
5d4ab79e81 | ||
|
|
22e877d882 | ||
|
|
46140e8c01 | ||
|
|
c19e4d220e | ||
|
|
31180a56d1 | ||
|
|
6b81c6dbb5 | ||
|
|
14df571486 | ||
|
|
04b2a78837 | ||
|
|
ecbd5ca720 | ||
|
|
ef1de9ecaf | ||
|
|
20dc452614 | ||
|
|
b9f8af16f4 | ||
|
|
aa538a405e | ||
|
|
fe9172ed55 | ||
|
|
526837e1c1 | ||
|
|
2f0a485bd4 | ||
|
|
56f083ad13 | ||
|
|
6be4fa575a | ||
|
|
ce42c24d70 | ||
|
|
6c338660e8 | ||
|
|
39f6ec5f63 | ||
|
|
ef835bf33a | ||
|
|
562fd5f2a7 | ||
|
|
6092312acc | ||
|
|
8a9a4748c9 | ||
|
|
dabe4a3943 | ||
|
|
e886ec2a2b | ||
|
|
8f9bdd68de | ||
|
|
0c5b5b21f7 | ||
|
|
77a6052e39 | ||
|
|
40d7de8f06 | ||
|
|
88a257634a | ||
|
|
c63278bf34 | ||
|
|
3beecc66e9 | ||
|
|
7e53a3b5cf | ||
|
|
75d49840cf | ||
|
|
1b6af2787e | ||
|
|
4fac507dfb | ||
|
|
186f857466 | ||
|
|
0405011734 | ||
|
|
6ab1dbbb7c | ||
|
|
16553b8826 | ||
|
|
726802b980 | ||
|
|
30216c65e5 | ||
|
|
cf79cf127b | ||
|
|
81d13cbebe | ||
|
|
9d32ff0c87 | ||
|
|
85ca18f60a | ||
|
|
6c37c32773 | ||
|
|
a7ad7cfb2f | ||
|
|
f7e6c5ad2b | ||
|
|
50006b49fc | ||
|
|
d217bedd32 | ||
|
|
d00b54b948 | ||
|
|
e07a5b1909 | ||
|
|
66d66cb487 | ||
|
|
4802a9d07a | ||
|
|
8bc7ebb4ae | ||
|
|
1e7a03cb58 | ||
|
|
15248f3e7d | ||
|
|
9d3f301423 | ||
|
|
6f52061844 | ||
|
|
c3eae29efa | ||
|
|
214d1f7433 | ||
|
|
231d3a534c | ||
|
|
bdbeaf4760 | ||
|
|
51864054da | ||
|
|
c04cee7ce8 | ||
|
|
3238125138 | ||
|
|
dc39ebe91e | ||
|
|
22a2179905 | ||
|
|
1180bab54e | ||
|
|
5b216c8000 | ||
|
|
d5927a70bb | ||
|
|
ba6df176e3 | ||
|
|
bcd9c57a96 | ||
|
|
c770c62fdc | ||
|
|
ad543e2e41 | ||
|
|
978b5c9466 | ||
|
|
cbc8140c77 | ||
|
|
cf58d41af8 | ||
|
|
0b4ad7062b | ||
|
|
266f416446 | ||
|
|
bbc565e825 | ||
|
|
51f5346f29 | ||
|
|
1c74fd768f | ||
|
|
7acc132cac | ||
|
|
bbf83fd988 | ||
|
|
8306ba50db | ||
|
|
6623d79ada | ||
|
|
1569c1ac85 | ||
|
|
c8498f59ec | ||
|
|
316ab4bb2b | ||
|
|
350c3126e1 | ||
|
|
943ece8610 | ||
|
|
9f2d7d816c | ||
|
|
a91d123ef4 | ||
|
|
146046bcda | ||
|
|
21a9692c7d | ||
|
|
8c5108fa21 | ||
|
|
87f62d7c8d | ||
|
|
ac170b0c34 | ||
|
|
0d25a516b4 | ||
|
|
c9c230b14a | ||
|
|
00e3915ca6 | ||
|
|
a21841fb75 | ||
|
|
ca9a956abc | ||
|
|
a7f05ea4af | ||
|
|
2cd161171a | ||
|
|
c926e87f47 | ||
|
|
3995546222 | ||
|
|
94b60d1247 | ||
|
|
eb16773704 | ||
|
|
d8c8612d92 | ||
|
|
f8a8ec5ceb | ||
|
|
4d5ad73238 | ||
|
|
63ca9079c3 | ||
|
|
c927c50d9b | ||
|
|
610f5609dc | ||
|
|
2b533d04bd | ||
|
|
b82851ad38 | ||
|
|
057d630962 | ||
|
|
4cf7528910 | ||
|
|
61326bf8ff | ||
|
|
680f615991 | ||
|
|
ea1f53d2f3 | ||
|
|
b2a2e197e8 | ||
|
|
0768dffa27 | ||
|
|
ab6fd579c7 | ||
|
|
437fb07240 | ||
|
|
c2ba02cff9 | ||
|
|
6db5edd0d0 | ||
|
|
c9e06594ed | ||
|
|
00844cd065 | ||
|
|
8a48d66950 | ||
|
|
bc41e6596c | ||
|
|
60bb010355 | ||
|
|
ad0f64583c | ||
|
|
8a2b4e2a5e | ||
|
|
5f1f17f076 | ||
|
|
d29f2cceaf | ||
|
|
17b2ce5bc2 | ||
|
|
061df5abaf | ||
|
|
4e0ee648b4 | ||
|
|
e0a1238b22 | ||
|
|
e96dc90ba4 | ||
|
|
968d00de15 | ||
|
|
8a02043265 | ||
|
|
3abe7a0624 | ||
|
|
934bb71c9d | ||
|
|
fc663f9c63 | ||
|
|
d92a3c09f3 | ||
|
|
64b82f8acd | ||
|
|
87381753d4 | ||
|
|
7e01b2f759 | ||
|
|
ea7fbed643 | ||
|
|
31c0e3df13 | ||
|
|
3881d4ce5c | ||
|
|
d5903339a1 | ||
|
|
38bf4fc828 | ||
|
|
c2289c5471 | ||
|
|
03837afa10 | ||
|
|
5cfe04d572 | ||
|
|
d74cf86d1e | ||
|
|
f2f0e69ede | ||
|
|
2422400c19 | ||
|
|
391e6d6ec8 | ||
|
|
81a16e51dc | ||
|
|
e957ffe972 | ||
|
|
2136f753eb | ||
|
|
0093d520c9 | ||
|
|
2bed076889 | ||
|
|
ed252e7f8b | ||
|
|
6aa746cc0b | ||
|
|
9f3e0c10ac | ||
|
|
bb860ee98d | ||
|
|
a5b6355100 | ||
|
|
372f7f10ac | ||
|
|
dbfc18fa3c | ||
|
|
b51a4a605b | ||
|
|
c648850285 | ||
|
|
f04f7f8ebc | ||
|
|
c4f3c3e68a | ||
|
|
e114928419 | ||
|
|
84664ef8a1 | ||
|
|
903097f2e7 | ||
|
|
a683a28097 | ||
|
|
3536e9912e | ||
|
|
743d7e126e | ||
|
|
9a77ba2fe0 | ||
|
|
68e66b838f | ||
|
|
ba45b0614f | ||
|
|
e3d0810474 | ||
|
|
7383d319bb | ||
|
|
11f2a1227d | ||
|
|
6704e49289 | ||
|
|
e125dd087b | ||
|
|
aa7c1959dd | ||
|
|
c858c1f73f | ||
|
|
f902292305 | ||
|
|
5c2e6fa2dd | ||
|
|
0012b7c117 | ||
|
|
fa9c8a0fdc | ||
|
|
3cbc9dee6b | ||
|
|
50dbbec5b2 | ||
|
|
6f5ebf13ac | ||
|
|
76a6828622 | ||
|
|
fa23bdfca8 | ||
|
|
b007125dc3 | ||
|
|
d480304694 | ||
|
|
17a0eba886 | ||
|
|
4057e1a811 | ||
|
|
3b78d2e0a2 | ||
|
|
47c3dd441e | ||
|
|
c4713d040a | ||
|
|
7ec15f4775 | ||
|
|
d6b8b66d5c | ||
|
|
e1cac2f249 | ||
|
|
10cce8e1f7 | ||
|
|
60255c8d28 | ||
|
|
e7bcb1210e | ||
|
|
6d275f7667 | ||
|
|
90747bcf00 | ||
|
|
afe4dec809 | ||
|
|
86171831d6 | ||
|
|
12c692d9fe | ||
|
|
2478c71757 | ||
|
|
5304abed42 | ||
|
|
2848e5ebef | ||
|
|
546926ac06 | ||
|
|
0bcc994c95 | ||
|
|
6daa344f8c | ||
|
|
f7ae2c8381 | ||
|
|
258974ca89 | ||
|
|
7f1d42b044 | ||
|
|
74221a4987 | ||
|
|
a5af9cfb4c | ||
|
|
342c016356 | ||
|
|
384be68897 | ||
|
|
fcb88ea659 | ||
|
|
d7d147b98d | ||
|
|
3bd948b1bc | ||
|
|
833366fc0e | ||
|
|
b5077b1146 | ||
|
|
eb3cff6ff7 | ||
|
|
33087803d9 | ||
|
|
037cc59722 | ||
|
|
2c2b1e5d3a | ||
|
|
52f5ad8ec7 | ||
|
|
6b58719a8c | ||
|
|
1407c7dfe3 | ||
|
|
408008ac09 | ||
|
|
9f3641cc00 | ||
|
|
0411d6786e | ||
|
|
6dc309fbed | ||
|
|
eda72fba0f | ||
|
|
923f141efe | ||
|
|
b639d303de | ||
|
|
71ba0a8536 | ||
|
|
a1fb73e588 | ||
|
|
01c5b29bf8 | ||
|
|
98155951d1 | ||
|
|
db444206ca | ||
|
|
c25e992763 | ||
|
|
75bd3e60cc | ||
|
|
fd32855dda | ||
|
|
53556dd293 | ||
|
|
99d883f81a | ||
|
|
9a543b75ca | ||
|
|
b180d7f488 | ||
|
|
7510eb1061 | ||
|
|
3dc7be6746 | ||
|
|
779c58db9f | ||
|
|
15da3d0702 | ||
|
|
58d1a6efcd | ||
|
|
0b4a869d16 | ||
|
|
43cec004f5 | ||
|
|
4bf6605924 | ||
|
|
1f8a50fb1c | ||
|
|
eb25db6892 | ||
|
|
486d52c624 | ||
|
|
3f7790dae8 | ||
|
|
4f95e0b443 | ||
|
|
1633f680e3 | ||
|
|
2038319df1 | ||
|
|
8ff65f31e3 | ||
|
|
53afb95be3 | ||
|
|
15bb70550b | ||
|
|
14767a3987 | ||
|
|
3627ee3d7f | ||
|
|
f91911a0e0 | ||
|
|
b20f72598f | ||
|
|
7189a0f5d2 | ||
|
|
6abf79dbf6 | ||
|
|
d0fcdab99b | ||
|
|
10f2beba8e | ||
|
|
876c8df1da | ||
|
|
1572a23705 | ||
|
|
ec68b8ac04 | ||
|
|
dccc9dddb7 | ||
|
|
34ba2c6486 | ||
|
|
5e2162039e | ||
|
|
663fddca98 | ||
|
|
2987e508ac | ||
|
|
74c5ebf239 | ||
|
|
5b74118447 | ||
|
|
6ca31b0522 | ||
|
|
b6fcd71cb5 | ||
|
|
5dab2c9aa7 | ||
|
|
6418d0492a | ||
|
|
f9d7e9e3be | ||
|
|
132122e313 | ||
|
|
0f806dfec8 | ||
|
|
9207cd4015 | ||
|
|
bb3e4dda5d | ||
|
|
43f0d63237 | ||
|
|
4f14e0a240 | ||
|
|
c27b951109 | ||
|
|
b8e16403fa | ||
|
|
0d62b8d9b7 | ||
|
|
824895f14e | ||
|
|
01e54ffb42 | ||
|
|
698dab0109 | ||
|
|
c9e77c18aa | ||
|
|
8ce85086f6 | ||
|
|
a1d913a7fc | ||
|
|
3ceb99937d | ||
|
|
3939b9c02b | ||
|
|
d2920a042a | ||
|
|
181455c2f7 | ||
|
|
2233d2e389 | ||
|
|
14bb154571 | ||
|
|
86568bcf5a | ||
|
|
bb1c803c31 | ||
|
|
2e82436244 | ||
|
|
f4ceddf6d9 | ||
|
|
4c9946bca7 | ||
|
|
8decbce383 | ||
|
|
0ff5ca89bf | ||
|
|
db74847423 | ||
|
|
1e04b2d9eb | ||
|
|
eb5ed41f9e | ||
|
|
d0ebebd664 | ||
|
|
6c6ae8db0a | ||
|
|
dac5590fa8 | ||
|
|
3d4e130e85 | ||
|
|
4bf8a29f75 | ||
|
|
c848d6d803 | ||
|
|
e66624a69b | ||
|
|
3f12612d90 | ||
|
|
b57e551ec1 | ||
|
|
50b99d9e1b | ||
|
|
f419cbbba3 | ||
|
|
630fd09808 | ||
|
|
81f5a4148b | ||
|
|
139b4f2d58 | ||
|
|
b9c5f24072 | ||
|
|
5c215587e9 | ||
|
|
0db46a31af | ||
|
|
b82e9a3746 | ||
|
|
6aa28180c4 | ||
|
|
3e83969482 | ||
|
|
239cf34d59 | ||
|
|
7c4501824c | ||
|
|
7704eab884 | ||
|
|
f8f89f2dd0 | ||
|
|
731c4a71dd | ||
|
|
37d11224ba | ||
|
|
30bbb590aa | ||
|
|
23a4a96f34 | ||
|
|
1173f6b665 | ||
|
|
2f340b0a74 | ||
|
|
12903e40c5 | ||
|
|
0815a691a5 | ||
|
|
ab12524199 | ||
|
|
94a9669492 | ||
|
|
65a8a578ae | ||
|
|
d1564ab556 | ||
|
|
6ae9b353df | ||
|
|
0fae559a9b | ||
|
|
f5e0b36c1e | ||
|
|
1a1d6e6b62 | ||
|
|
8fe708e2a6 | ||
|
|
e4c3b7e5ce | ||
|
|
f02f19dcb5 | ||
|
|
2b8d3756b4 | ||
|
|
e7e5947210 | ||
|
|
47da7e78ad | ||
|
|
45df656b8a | ||
|
|
aee6d6df11 | ||
|
|
03f52897be | ||
|
|
dc98b21dcc | ||
|
|
7132e90e93 | ||
|
|
52e12bd760 | ||
|
|
f0c12ae751 | ||
|
|
6f80a528c3 | ||
|
|
54bf2b7a78 | ||
|
|
2fab4c6180 | ||
|
|
ed1d07d058 | ||
|
|
5ada684e03 | ||
|
|
f3bc4cb826 | ||
|
|
31bc90f71f | ||
|
|
f879d7df27 | ||
|
|
cea3fe7d6e | ||
|
|
30e98b4a0d | ||
|
|
c87bf0cfc6 | ||
|
|
5101076eab | ||
|
|
c350927b22 | ||
|
|
5735f03d18 | ||
|
|
45a26b92e3 | ||
|
|
85982ab6cd | ||
|
|
c3e09804e5 | ||
|
|
71d24f5d1a | ||
|
|
d9062199b4 | ||
|
|
da8139499d | ||
|
|
c7f6eab8b1 | ||
|
|
fc2e5e0807 | ||
|
|
10a23e8618 | ||
|
|
c18e886380 | ||
|
|
b43fd541d3 | ||
|
|
1d64687d13 | ||
|
|
046ed7e775 | ||
|
|
177a69639c | ||
|
|
04b3026451 | ||
|
|
31e522c582 | ||
|
|
9a50a58591 | ||
|
|
172944c3dd | ||
|
|
a40c5e7cae | ||
|
|
6f4ef9d3d9 | ||
|
|
ecfeed0476 | ||
|
|
e3e37fdc1c | ||
|
|
1d8873df39 | ||
|
|
c655e048eb | ||
|
|
ab26892544 | ||
|
|
f2cab62f0c | ||
|
|
68de40addd | ||
|
|
42881b8921 | ||
|
|
5c92b1050f | ||
|
|
e24d833c66 | ||
|
|
db28428efe | ||
|
|
94a06edc56 | ||
|
|
df1127390f | ||
|
|
f8acca9ade | ||
|
|
3d5e9f0a04 | ||
|
|
2dcd8612c0 | ||
|
|
7c9ec39bb9 | ||
|
|
75ea847862 | ||
|
|
3421414377 | ||
|
|
cf01e506ed | ||
|
|
50d8843757 |
27
.gitignore
vendored
@@ -3,33 +3,24 @@
|
|||||||
build/conf/local.conf
|
build/conf/local.conf
|
||||||
build/conf/bblayers.conf
|
build/conf/bblayers.conf
|
||||||
build/tmp/
|
build/tmp/
|
||||||
|
build/sstate-cache
|
||||||
|
build/pyshtables.py
|
||||||
pstage/
|
pstage/
|
||||||
scripts/poky-git-proxy-socks
|
scripts/poky-git-proxy-socks
|
||||||
sources/
|
sources/
|
||||||
meta-darwin
|
meta-darwin
|
||||||
meta-maemo
|
meta-maemo
|
||||||
|
meta-extras
|
||||||
|
meta-m2
|
||||||
meta-prvt*
|
meta-prvt*
|
||||||
poky-autobuilder*
|
poky-autobuilder*
|
||||||
*.swp
|
*.swp
|
||||||
*.orig
|
*.orig
|
||||||
*.rej
|
*.rej
|
||||||
*~
|
*~
|
||||||
handbook/poky-doc-tools/Makefile
|
documentation/poky-ref-manual/poky-ref-manual.html
|
||||||
handbook/poky-doc-tools/Makefile.in
|
documentation/poky-ref-manual/poky-ref-manual.pdf
|
||||||
handbook/poky-doc-tools/aclocal.m4
|
documentation/poky-ref-manual/poky-ref-manual.tgz
|
||||||
handbook/poky-doc-tools/autom4te.cache/
|
documentation/poky-ref-manual/bsp-guide.html
|
||||||
handbook/poky-doc-tools/common/Makefile
|
documentation/poky-ref-manual/bsp-guide.pdf
|
||||||
handbook/poky-doc-tools/common/Makefile.in
|
|
||||||
handbook/poky-doc-tools/common/fop-config.xml
|
|
||||||
handbook/poky-doc-tools/config.log
|
|
||||||
handbook/poky-doc-tools/config.status
|
|
||||||
handbook/poky-doc-tools/configure
|
|
||||||
handbook/poky-doc-tools/install-sh
|
|
||||||
handbook/poky-doc-tools/missing
|
|
||||||
handbook/poky-doc-tools/poky-docbook-to-pdf
|
|
||||||
handbook/poky-handbook.html
|
|
||||||
handbook/poky-handbook.pdf
|
|
||||||
handbook/poky-handbook.tgz
|
|
||||||
handbook/bsp-guide.html
|
|
||||||
handbook/bsp-guide.pdf
|
|
||||||
|
|
||||||
|
|||||||
220
CHANGELOG
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
commit fd7a07b3a2153826bedda2ef76b9a33ab2791680
|
||||||
|
Author: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
Date: Fri Jan 21 14:15:05 2011 -0800
|
||||||
|
|
||||||
|
poky-extract-sdk: allow relative paths for extract-dir
|
||||||
|
|
||||||
|
psuedo needs a full path to its pid file, so convert
|
||||||
|
relative extract-dir paths to full ones.
|
||||||
|
|
||||||
|
The symptom of this bug is receiving the following error:
|
||||||
|
|
||||||
|
pseudo: Couldn't open relative/path/to/var/pseudo/pseudo.pid: No such file or directory
|
||||||
|
|
||||||
|
This fixes [BUGID #670]
|
||||||
|
|
||||||
|
Signed-off-by: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
|
||||||
|
commit 01bc47f4d47df3276b4b6c2583bcddd834fd5050
|
||||||
|
Author: Beth Flanagan <elizabeth.flanagan@intel.com>
|
||||||
|
Date: Wed Nov 3 17:20:00 2010 -0700
|
||||||
|
|
||||||
|
quilt: Fixed configure test for patch --version.
|
||||||
|
|
||||||
|
OpenSuSE 11.3 uses GNU patch 2.6.1.81-5b68 which breaks quilt's
|
||||||
|
configure test for patch version.
|
||||||
|
|
||||||
|
Signed-off-by: Beth Flanagan <elizabeth.flanagan@intel.com>
|
||||||
|
|
||||||
|
commit 12a3d41a24db79ae6c0491defffcf4f4753001cf
|
||||||
|
Author: Richard Purdie <richard.purdie@linuxfoundation.org>
|
||||||
|
Date: Fri Jan 14 11:57:18 2011 +0000
|
||||||
|
|
||||||
|
image.bbclass: Use the dedicated BB_WORKERCONTEXT, not bitbake internals to detect context
|
||||||
|
|
||||||
|
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
|
||||||
|
|
||||||
|
commit ce4f8356796bc797d9156ed252a4ed638a2150d5
|
||||||
|
Author: Richard Purdie <rpurdie@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 23:22:16 2010 +0000
|
||||||
|
|
||||||
|
scripts/poky-qemu: Improve tmp layout assumption
|
||||||
|
|
||||||
|
If someone has changed TMPDIR in local.conf to a non-standard location, the
|
||||||
|
poky-qemu script currently doesn't handle this and assumes if BUILDDIR is set,
|
||||||
|
$BUILDDIR/tmp will exist.
|
||||||
|
|
||||||
|
Its simple to check if this exists and if not, to ask bitbake where the
|
||||||
|
directory is so this patch changes the code to do that.
|
||||||
|
|
||||||
|
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
|
||||||
|
|
||||||
|
commit 54f08d23cd7d0de6aec31f4764389ff4dab2990d
|
||||||
|
Author: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
Date: Tue Dec 7 20:59:06 2010 -0800
|
||||||
|
|
||||||
|
Make poky-qemu and related scripts work with arbitrary SDK locations
|
||||||
|
|
||||||
|
* No longer assume SDK toolchains are installed in /opt/poky
|
||||||
|
* [BUGFIX #568] where specifying paths to both the kernel and fs
|
||||||
|
image caused an error due to POKY_NATIVE_SYSROOT never being
|
||||||
|
set, triggering failure of poky-qemu-ifup/ifdown
|
||||||
|
* Cosmetic improvements to usage() functions by using basename
|
||||||
|
|
||||||
|
Signed-off-by: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
|
||||||
|
commit 8a3d0f375ce416ada1a5443e4a8e467504001beb
|
||||||
|
Author: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
Date: Fri Nov 12 16:31:13 2010 -0800
|
||||||
|
|
||||||
|
poky-qemu: Fix issues when running Yocto 0.9 release images
|
||||||
|
|
||||||
|
This fixes two bugs with poky-qemu when it is run from a
|
||||||
|
standalone meta-toolchain setup.
|
||||||
|
|
||||||
|
[BUGFIX #535] and [BUGFIX #536]
|
||||||
|
|
||||||
|
Signed-off-by: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
|
||||||
|
commit 0c2003f13434c77f901a976523478d37d8aadb48
|
||||||
|
Author: Paul Eggleton <paul.eggleton@linux.intel.com>
|
||||||
|
Date: Thu Dec 16 10:29:50 2010 +0000
|
||||||
|
|
||||||
|
openssl: restore -Wall flag
|
||||||
|
|
||||||
|
The -Wall flag was unintentionally removed from the end of the CFLAG var in
|
||||||
|
089612794d4d8d9c79bd2a4365d6df78371f7f40 by me. This patch puts it back in.
|
||||||
|
|
||||||
|
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
|
||||||
|
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
|
||||||
|
|
||||||
|
commit 6e71b0a012f0676c06b7b4788d932f320fca0b74
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 14:31:21 2010 +0000
|
||||||
|
|
||||||
|
web-webkit: fix for make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 4b5c1c053000d297956f08949ffde7454ee33c5d
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 13:42:15 2010 +0000
|
||||||
|
|
||||||
|
contacts: fix for make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 171e709ae6f4b1a7640bf393f57aa787648cdc0f
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 12:58:09 2010 +0000
|
||||||
|
|
||||||
|
dates: fix for Make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit a8b8557e4cb34b594bb620eb276bcaf7a8e0a8e3
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 12:27:52 2010 +0000
|
||||||
|
|
||||||
|
owl-video-widget: fix Makefile for super strict make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 399e6b8008cb0b8cc0b75efd48dd821a6cf5a8a8
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 18:29:43 2010 +0000
|
||||||
|
|
||||||
|
libowl-av: fix for Make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 290280b332570ec73301f76765b1c5f2de20a9fd
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 17:56:53 2010 +0000
|
||||||
|
|
||||||
|
gst-plugins: fix for make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 9e11fbf9048b17526ca8160d82b69f386595c9a7
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 15:39:42 2010 +0000
|
||||||
|
|
||||||
|
gstreamer: fix to comply with make 3.82's stricter parser
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 0f8244faba5c36c0580081c112ea27ce683af99b
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 12:49:13 2010 +0000
|
||||||
|
|
||||||
|
linux-libc-headers: fix for Make 3.82
|
||||||
|
|
||||||
|
Fix the kernel Makefile for use with Make 3.82 by splitting mixed implicit and
|
||||||
|
normal rules into separate rules.
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 0cc23a86562d0ce1e236ceb4a56a8f19d400192f
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 12:21:33 2010 +0000
|
||||||
|
|
||||||
|
busybox: additional fixes for Make 3.82
|
||||||
|
|
||||||
|
There where still some mixed implicit and normal rules in the Busybox Makefile,
|
||||||
|
Update our existing make-382.patch to split these into separate rules.
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 30c39cc97c384134661300e107d7a81f257f8034
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Fri Nov 12 16:36:54 2010 +0000
|
||||||
|
|
||||||
|
procps: fix for build against make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 261ca885962ba9606bcad4c5415927a79fdd7b96
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Nov 9 12:18:14 2010 +0000
|
||||||
|
|
||||||
|
busybox: import upstream patch for make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 72ddd5c20246a5d5b1752b58a61ef75b4c39cc40
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Nov 9 12:14:28 2010 +0000
|
||||||
|
|
||||||
|
eglibc: fix build of eglibc-initial for make 3.82
|
||||||
|
|
||||||
|
Make 3.82, as shipped with Fedora 14, fixes some holes in the parser which in
|
||||||
|
turn breaks behaviour of some Makefiles. Most notably eglibc's.
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 6026999e81042a7f6560f9bce04390865509b235
|
||||||
|
Author: Paul Eggleton <paul.eggleton@intel.com>
|
||||||
|
Date: Fri Nov 19 15:03:32 2010 +0000
|
||||||
|
|
||||||
|
qemu: fix failure to find zlib header files during configure
|
||||||
|
|
||||||
|
Corrects problems during configure of qemu-native due to the BUILD_CFLAGS
|
||||||
|
not being included when attempting to compile the test program for zlib
|
||||||
|
within the configure script.
|
||||||
|
|
||||||
|
Signed-off-by: Paul Eggleton <paul.eggleton@intel.com>
|
||||||
|
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
|
||||||
|
|
||||||
|
commit c5ab4d56f97a0e45b124d40c9f536541be04c201
|
||||||
|
Author: Paul Eggleton <paul.eggleton@intel.com>
|
||||||
|
Date: Wed Nov 17 11:37:47 2010 +0000
|
||||||
|
|
||||||
|
openssl-native: disable execstack flag to prevent problems with SELinux
|
||||||
|
|
||||||
|
The execstack flag gets set on libcrypto.so by default which causes SELinux
|
||||||
|
to prevent it from being loaded on systems using SELinux, which includes
|
||||||
|
Fedora. This patch disables the execstack flag. (Note: Red Hat do this in
|
||||||
|
their openssl packaging.)
|
||||||
|
|
||||||
|
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
|
||||||
70
NOTES
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
Name: Laverne
|
||||||
|
Version: 4.0.1
|
||||||
|
Built from Revision: fd7a07b3a2153826bedda2ef76b9a33ab2791680
|
||||||
|
Build Date: Jan 26 2011
|
||||||
|
Builder: autobuilder.pokylinux.org
|
||||||
|
|
||||||
|
The Laverne 4.0.1 Release ensures you can use Poky Laverne on systems running
|
||||||
|
Fedora 14 and Opensuse 11.3, fixes issues with the poky-qemu script, and fixes
|
||||||
|
several other bugs. For the full changelog for Laverne 4.0.1 please read
|
||||||
|
CHANGELOG.
|
||||||
|
|
||||||
|
Following are descriptions of fixes and known issues.
|
||||||
|
|
||||||
|
Fixes
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
* Make 3.82, as shipped with Fedora 14, included parser bug fixes that
|
||||||
|
resulted in a much stricter parser. As a result, the Makefiles could not be
|
||||||
|
parsed for many of the software versions shipped with Laverne. The Makefiles
|
||||||
|
in the following recipes were fixed:
|
||||||
|
|
||||||
|
o eglibc
|
||||||
|
o busybox
|
||||||
|
o procps
|
||||||
|
o linux-libc-headers
|
||||||
|
o gstreamer
|
||||||
|
o gst-plugins
|
||||||
|
o libowl-av
|
||||||
|
o owl-video-widget
|
||||||
|
o dates
|
||||||
|
o contacts
|
||||||
|
o web-webkit
|
||||||
|
|
||||||
|
* The ability to build openssl-native on a system that has SELINUX enabled
|
||||||
|
was restored. (We disabled the execstack flag at compile time.)
|
||||||
|
|
||||||
|
* A host-intrusion issue caused by a failure in QEMU to find zlib headers
|
||||||
|
during configure was fixed. The issue was causing qemu-native to use the
|
||||||
|
system zlib if it was present. If the system zlib was not present the build
|
||||||
|
would fail.
|
||||||
|
|
||||||
|
* Stability and usability enhancements, which included handling relative
|
||||||
|
filesystem paths, were made to poky-qemu scripts.
|
||||||
|
|
||||||
|
* The run-time remapping of package names when adding extra packages to an
|
||||||
|
image via the IMAGE_INSTALL mechanism were fixed.
|
||||||
|
|
||||||
|
* The configure test in quilt for GNU patch was fixed to that it correctly
|
||||||
|
detects the version.
|
||||||
|
|
||||||
|
Known Issues
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
* The mpc3815e-rbd and routerstationpro machines were untested and not a
|
||||||
|
part of the official Laverne 4.0 release. These machines are still unusable
|
||||||
|
for this Laverne 4.0.1 release.
|
||||||
|
o mpx3815e-rdb will not boot due to a kernel/uboot issue Bug #685
|
||||||
|
o routerstation will not boot (by default) due to incorrect boot
|
||||||
|
parameters Bug #681
|
||||||
|
o routerstationpro debug messages related to the ethernet driver print
|
||||||
|
during boot Bug #679
|
||||||
|
* Shutdown/poweroff on qemuarm does not cleanly halt the virtual machine.
|
||||||
|
To workaround this issue use the reboot command. Using this command avoids
|
||||||
|
a "power-cycle" and instead cleanly shuts down the VM Bug #684
|
||||||
|
* Two "Connection Manager" icons appear in the Sato UI. This duplication has
|
||||||
|
been fixed in master. Note that you can use either icon to launch the
|
||||||
|
connectivity UI. Bug #683
|
||||||
|
* The on-screen keyboard incorrectly launches in the qemumips machine. This
|
||||||
|
issue is due to a mis-configured formfactor file Bug #682
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ Changes in Bitbake 1.9.x:
|
|||||||
directory != the cache dir.
|
directory != the cache dir.
|
||||||
- Add md5 and sha256 checksum generation functions to utils.py
|
- Add md5 and sha256 checksum generation functions to utils.py
|
||||||
- Correctly handle '-' characters in class names (#2958)
|
- Correctly handle '-' characters in class names (#2958)
|
||||||
- Make sure expandKeys has been called on the data dictonary before running tasks
|
- Make sure expandKeys has been called on the data dictionary before running tasks
|
||||||
- Correctly add a task override in the form task-TASKNAME.
|
- Correctly add a task override in the form task-TASKNAME.
|
||||||
- Revert the '-' character fix in class names since it breaks things
|
- Revert the '-' character fix in class names since it breaks things
|
||||||
- When a regexp fails to compile for PACKAGES_DYNAMIC, print a more useful error (#4444)
|
- When a regexp fails to compile for PACKAGES_DYNAMIC, print a more useful error (#4444)
|
||||||
|
|||||||
@@ -22,143 +22,160 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import sys, os, getopt, re, time, optparse, xmlrpclib
|
import os
|
||||||
sys.path.insert(0,os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
import sys
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])),
|
||||||
|
'lib'))
|
||||||
|
|
||||||
|
import optparse
|
||||||
|
import warnings
|
||||||
|
from traceback import format_exception
|
||||||
import bb
|
import bb
|
||||||
|
import bb.msg
|
||||||
from bb import cooker
|
from bb import cooker
|
||||||
from bb import ui
|
from bb import ui
|
||||||
from bb import server
|
from bb import server
|
||||||
from bb.server import none
|
from bb.server import none
|
||||||
#from bb.server import xmlrpc
|
#from bb.server import xmlrpc
|
||||||
|
|
||||||
__version__ = "1.9.0"
|
__version__ = "1.11.0"
|
||||||
|
|
||||||
|
|
||||||
if sys.hexversion < 0x020500F0:
|
|
||||||
print "Sorry, python 2.5 or later is required for this version of bitbake"
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
#============================================================================#
|
#============================================================================#
|
||||||
# BBOptions
|
# BBOptions
|
||||||
#============================================================================#
|
#============================================================================#
|
||||||
class BBConfiguration( object ):
|
class BBConfiguration(object):
|
||||||
"""
|
"""
|
||||||
Manages build options and configurations for one run
|
Manages build options and configurations for one run
|
||||||
"""
|
"""
|
||||||
def __init__( self, options ):
|
|
||||||
|
def __init__(self, options):
|
||||||
for key, val in options.__dict__.items():
|
for key, val in options.__dict__.items():
|
||||||
setattr( self, key, val )
|
setattr(self, key, val)
|
||||||
|
self.pkgs_to_build = []
|
||||||
|
|
||||||
|
|
||||||
def print_exception(exc, value, tb):
|
def print_exception(exc, value, tb):
|
||||||
"""
|
"""Send exception information through bb.msg"""
|
||||||
Print the exception to stderr, only showing the traceback if bitbake
|
bb.fatal("".join(format_exception(exc, value, tb, limit=8)))
|
||||||
debugging is enabled.
|
|
||||||
"""
|
|
||||||
if not bb.msg.debug_level['default']:
|
|
||||||
tb = None
|
|
||||||
|
|
||||||
sys.__excepthook__(exc, value, tb)
|
sys.excepthook = print_exception
|
||||||
|
|
||||||
|
|
||||||
|
_warnings_showwarning = warnings.showwarning
|
||||||
|
def _showwarning(message, category, filename, lineno, file=None, line=None):
|
||||||
|
"""Display python warning messages using bb.msg"""
|
||||||
|
if file is not None:
|
||||||
|
if _warnings_showwarning is not None:
|
||||||
|
_warnings_showwarning(message, category, filename, lineno, file, line)
|
||||||
|
else:
|
||||||
|
s = warnings.formatwarning(message, category, filename, lineno)
|
||||||
|
s = s.split("\n")[0]
|
||||||
|
bb.msg.warn(None, s)
|
||||||
|
|
||||||
|
warnings.showwarning = _showwarning
|
||||||
|
warnings.simplefilter("ignore", DeprecationWarning)
|
||||||
|
|
||||||
#============================================================================#
|
#============================================================================#
|
||||||
# main
|
# main
|
||||||
#============================================================================#
|
#============================================================================#
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
return_value = 0
|
return_value = 1
|
||||||
pythonver = sys.version_info
|
|
||||||
if pythonver[0] < 2 or (pythonver[0] == 2 and pythonver[1] < 5):
|
|
||||||
print "Sorry, bitbake needs python 2.5 or later."
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
|
parser = optparse.OptionParser(
|
||||||
usage = """%prog [options] [package ...]
|
version = "BitBake Build Tool Core version %s, %%prog version %s" % (bb.__version__, __version__),
|
||||||
|
usage = """%prog [options] [package ...]
|
||||||
|
|
||||||
Executes the specified task (default is 'build') for a given set of BitBake files.
|
Executes the specified task (default is 'build') for a given set of BitBake files.
|
||||||
It expects that BBFILES is defined, which is a space separated list of files to
|
It expects that BBFILES is defined, which is a space separated list of files to
|
||||||
be executed. BBFILES does support wildcards.
|
be executed. BBFILES does support wildcards.
|
||||||
Default BBFILES are the .bb files in the current directory.""" )
|
Default BBFILES are the .bb files in the current directory.""")
|
||||||
|
|
||||||
parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
|
parser.add_option("-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
|
||||||
action = "store", dest = "buildfile", default = None )
|
action = "store", dest = "buildfile", default = None)
|
||||||
|
|
||||||
parser.add_option( "-k", "--continue", help = "continue as much as possible after an error. While the target that failed, and those that depend on it, cannot be remade, the other dependencies of these targets can be processed all the same.",
|
parser.add_option("-k", "--continue", help = "continue as much as possible after an error. While the target that failed, and those that depend on it, cannot be remade, the other dependencies of these targets can be processed all the same.",
|
||||||
action = "store_false", dest = "abort", default = True )
|
action = "store_false", dest = "abort", default = True)
|
||||||
|
|
||||||
parser.add_option( "-a", "--tryaltconfigs", help = "continue with builds by trying to use alternative providers where possible.",
|
parser.add_option("-a", "--tryaltconfigs", help = "continue with builds by trying to use alternative providers where possible.",
|
||||||
action = "store_true", dest = "tryaltconfigs", default = False )
|
action = "store_true", dest = "tryaltconfigs", default = False)
|
||||||
|
|
||||||
parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
|
parser.add_option("-f", "--force", help = "force run of specified cmd, regardless of stamp status",
|
||||||
action = "store_true", dest = "force", default = False )
|
action = "store_true", dest = "force", default = False)
|
||||||
|
|
||||||
parser.add_option( "-i", "--interactive", help = "drop into the interactive mode also called the BitBake shell.",
|
parser.add_option("-c", "--cmd", help = "Specify task to execute. Note that this only executes the specified task for the providee and the packages it depends on, i.e. 'compile' does not implicitly call stage for the dependencies (IOW: use only if you know what you are doing). Depending on the base.bbclass a listtasks tasks is defined and will show available tasks",
|
||||||
action = "store_true", dest = "interactive", default = False )
|
action = "store", dest = "cmd")
|
||||||
|
|
||||||
parser.add_option( "-c", "--cmd", help = "Specify task to execute. Note that this only executes the specified task for the providee and the packages it depends on, i.e. 'compile' does not implicitly call stage for the dependencies (IOW: use only if you know what you are doing). Depending on the base.bbclass a listtasks tasks is defined and will show available tasks",
|
parser.add_option("-r", "--read", help = "read the specified file before bitbake.conf",
|
||||||
action = "store", dest = "cmd" )
|
action = "append", dest = "file", default = [])
|
||||||
|
|
||||||
parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
|
parser.add_option("-v", "--verbose", help = "output more chit-chat to the terminal",
|
||||||
action = "append", dest = "file", default = [] )
|
action = "store_true", dest = "verbose", default = False)
|
||||||
|
|
||||||
parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
|
parser.add_option("-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
|
||||||
action = "store_true", dest = "verbose", default = False )
|
|
||||||
|
|
||||||
parser.add_option( "-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
|
|
||||||
action = "count", dest="debug", default = 0)
|
action = "count", dest="debug", default = 0)
|
||||||
|
|
||||||
parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
|
parser.add_option("-n", "--dry-run", help = "don't execute, just go through the motions",
|
||||||
action = "store_true", dest = "dry_run", default = False )
|
action = "store_true", dest = "dry_run", default = False)
|
||||||
|
|
||||||
parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
|
parser.add_option("-S", "--dump-signatures", help = "don't execute, just dump out the signature construction information",
|
||||||
action = "store_true", dest = "parse_only", default = False )
|
action = "store_true", dest = "dump_signatures", default = False)
|
||||||
|
|
||||||
parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
|
parser.add_option("-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
|
||||||
action = "store_true", dest = "disable_psyco", default = False )
|
action = "store_true", dest = "parse_only", default = False)
|
||||||
|
|
||||||
parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
|
parser.add_option("-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
|
||||||
action = "store_true", dest = "show_versions", default = False )
|
action = "store_true", dest = "disable_psyco", default = False)
|
||||||
|
|
||||||
parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
|
parser.add_option("-s", "--show-versions", help = "show current and preferred versions of all packages",
|
||||||
action = "store_true", dest = "show_environment", default = False )
|
action = "store_true", dest = "show_versions", default = False)
|
||||||
|
|
||||||
parser.add_option( "-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
|
parser.add_option("-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
|
||||||
action = "store_true", dest = "dot_graph", default = False )
|
action = "store_true", dest = "show_environment", default = False)
|
||||||
|
|
||||||
parser.add_option( "-I", "--ignore-deps", help = """Assume these dependencies don't exist and are already provided (equivalent to ASSUME_PROVIDED). Useful to make dependency graphs more appealing""",
|
parser.add_option("-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax",
|
||||||
action = "append", dest = "extra_assume_provided", default = [] )
|
action = "store_true", dest = "dot_graph", default = False)
|
||||||
|
|
||||||
parser.add_option( "-l", "--log-domains", help = """Show debug logging for the specified logging domains""",
|
parser.add_option("-I", "--ignore-deps", help = """Assume these dependencies don't exist and are already provided (equivalent to ASSUME_PROVIDED). Useful to make dependency graphs more appealing""",
|
||||||
action = "append", dest = "debug_domains", default = [] )
|
action = "append", dest = "extra_assume_provided", default = [])
|
||||||
|
|
||||||
parser.add_option( "-P", "--profile", help = "profile the command and print a report",
|
parser.add_option("-l", "--log-domains", help = """Show debug logging for the specified logging domains""",
|
||||||
action = "store_true", dest = "profile", default = False )
|
action = "append", dest = "debug_domains", default = [])
|
||||||
|
|
||||||
parser.add_option( "-u", "--ui", help = "userinterface to use",
|
parser.add_option("-P", "--profile", help = "profile the command and print a report",
|
||||||
|
action = "store_true", dest = "profile", default = False)
|
||||||
|
|
||||||
|
parser.add_option("-u", "--ui", help = "userinterface to use",
|
||||||
action = "store", dest = "ui")
|
action = "store", dest = "ui")
|
||||||
|
|
||||||
parser.add_option( "", "--revisions-changed", help = "Set the exit code depending on whether upstream floating revisions have changed or not",
|
parser.add_option("", "--revisions-changed", help = "Set the exit code depending on whether upstream floating revisions have changed or not",
|
||||||
action = "store_true", dest = "revisions_changed", default = False )
|
action = "store_true", dest = "revisions_changed", default = False)
|
||||||
|
|
||||||
options, args = parser.parse_args(sys.argv)
|
options, args = parser.parse_args(sys.argv)
|
||||||
|
|
||||||
configuration = BBConfiguration(options)
|
configuration = BBConfiguration(options)
|
||||||
configuration.pkgs_to_build = []
|
|
||||||
configuration.pkgs_to_build.extend(args[1:])
|
configuration.pkgs_to_build.extend(args[1:])
|
||||||
|
configuration.initial_path = os.environ['PATH']
|
||||||
|
|
||||||
#server = bb.server.xmlrpc
|
#server = bb.server.xmlrpc
|
||||||
server = bb.server.none
|
server = bb.server.none
|
||||||
|
|
||||||
# Save a logfile for cooker into the current working directory. When the
|
# Save a logfile for cooker into the current working directory. When the
|
||||||
# server is daemonized this logfile will be truncated.
|
# server is daemonized this logfile will be truncated.
|
||||||
cooker_logfile = os.path.join (os.getcwd(), "cooker.log")
|
cooker_logfile = os.path.join(os.getcwd(), "cooker.log")
|
||||||
|
|
||||||
cooker = bb.cooker.BBCooker(configuration, server)
|
bb.utils.init_logger(bb.msg, configuration.verbose, configuration.debug,
|
||||||
|
configuration.debug_domains)
|
||||||
|
|
||||||
# Clear away any spurious environment variables. But don't wipe the
|
# Clear away any spurious environment variables. But don't wipe the
|
||||||
# environment totally. This is necessary to ensure the correct operation
|
# environment totally. This is necessary to ensure the correct operation
|
||||||
# of the UIs (e.g. for DISPLAY, etc.)
|
# of the UIs (e.g. for DISPLAY, etc.)
|
||||||
bb.utils.clean_environment()
|
bb.utils.clean_environment()
|
||||||
|
|
||||||
|
cooker = bb.cooker.BBCooker(configuration, server)
|
||||||
|
|
||||||
cooker.parseCommandLine()
|
cooker.parseCommandLine()
|
||||||
|
|
||||||
serverinfo = server.BitbakeServerInfo(cooker.server)
|
serverinfo = server.BitbakeServerInfo(cooker.server)
|
||||||
@@ -166,8 +183,6 @@ Default BBFILES are the .bb files in the current directory.""" )
|
|||||||
server.BitBakeServerFork(serverinfo, cooker.serve, cooker_logfile)
|
server.BitBakeServerFork(serverinfo, cooker.serve, cooker_logfile)
|
||||||
del cooker
|
del cooker
|
||||||
|
|
||||||
sys.excepthook = print_exception
|
|
||||||
|
|
||||||
# Setup a connection to the server (cooker)
|
# Setup a connection to the server (cooker)
|
||||||
serverConnection = server.BitBakeServerConnection(serverinfo)
|
serverConnection = server.BitBakeServerConnection(serverinfo)
|
||||||
|
|
||||||
@@ -178,19 +193,24 @@ Default BBFILES are the .bb files in the current directory.""" )
|
|||||||
ui = "knotty"
|
ui = "knotty"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Dynamically load the UI based on the ui name. Although we
|
# Dynamically load the UI based on the ui name. Although we
|
||||||
# suggest a fixed set this allows you to have flexibility in which
|
# suggest a fixed set this allows you to have flexibility in which
|
||||||
# ones are available.
|
# ones are available.
|
||||||
exec "from bb.ui import " + ui
|
uimodule = __import__("bb.ui", fromlist = [ui])
|
||||||
exec "return_value = " + ui + ".init(serverConnection.connection, serverConnection.events)"
|
ui_init = getattr(uimodule, ui).init
|
||||||
except ImportError:
|
except AttributeError:
|
||||||
print "FATAL: Invalid user interface '%s' specified. " % ui
|
print("FATAL: Invalid user interface '%s' specified. " % ui)
|
||||||
print "Valid interfaces are 'ncurses', 'depexp' or the default, 'knotty'."
|
print("Valid interfaces are 'ncurses', 'depexp' or the default, 'knotty'.")
|
||||||
except Exception, e:
|
else:
|
||||||
print "FATAL: Unable to start to '%s' UI due to exception: %s." % (configuration.ui, e)
|
try:
|
||||||
|
return_value = ui_init(serverConnection.connection, serverConnection.events)
|
||||||
|
except Exception as e:
|
||||||
|
print("FATAL: Unable to start to '%s' UI: %s" % (ui, e))
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
serverConnection.terminate()
|
serverConnection.terminate()
|
||||||
return return_value
|
|
||||||
|
return return_value
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
ret = main()
|
ret = main()
|
||||||
|
|||||||
12
bitbake/bin/bitbake-diffsigs
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import warnings
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
||||||
|
|
||||||
|
import bb.siggen
|
||||||
|
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
bb.siggen.compare_sigfiles(sys.argv[1], sys.argv[2])
|
||||||
|
else:
|
||||||
|
bb.siggen.dump_sigfile(sys.argv[1])
|
||||||
117
bitbake/bin/bitbake-runtask
Executable file
@@ -0,0 +1,117 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import warnings
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
||||||
|
|
||||||
|
try:
|
||||||
|
import cPickle as pickle
|
||||||
|
except ImportError:
|
||||||
|
import pickle
|
||||||
|
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
|
||||||
|
|
||||||
|
class BBConfiguration(object):
|
||||||
|
"""
|
||||||
|
Manages build options and configurations for one run
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, debug, debug_domains):
|
||||||
|
setattr(self, "data", {})
|
||||||
|
setattr(self, "file", [])
|
||||||
|
setattr(self, "cmd", None)
|
||||||
|
setattr(self, "dump_signatures", True)
|
||||||
|
setattr(self, "debug", debug)
|
||||||
|
setattr(self, "debug_domains", debug_domains)
|
||||||
|
|
||||||
|
_warnings_showwarning = warnings.showwarning
|
||||||
|
def _showwarning(message, category, filename, lineno, file=None, line=None):
|
||||||
|
"""Display python warning messages using bb.msg"""
|
||||||
|
if file is not None:
|
||||||
|
if _warnings_showwarning is not None:
|
||||||
|
_warnings_showwarning(message, category, filename, lineno, file, line)
|
||||||
|
else:
|
||||||
|
s = warnings.formatwarning(message, category, filename, lineno)
|
||||||
|
s = s.split("\n")[0]
|
||||||
|
bb.msg.warn(None, s)
|
||||||
|
|
||||||
|
warnings.showwarning = _showwarning
|
||||||
|
warnings.simplefilter("ignore", DeprecationWarning)
|
||||||
|
|
||||||
|
import bb.event
|
||||||
|
|
||||||
|
# Need to map our I/O correctly. stdout is a pipe to the server expecting
|
||||||
|
# events. We save this and then map stdout to stderr.
|
||||||
|
|
||||||
|
eventfd = os.dup(sys.stdout.fileno())
|
||||||
|
bb.event.worker_pipe = os.fdopen(eventfd, 'w', 0)
|
||||||
|
|
||||||
|
# map stdout to stderr
|
||||||
|
os.dup2(sys.stderr.fileno(), sys.stdout.fileno())
|
||||||
|
|
||||||
|
# Replace those fds with our own
|
||||||
|
#logout = data.expand("${TMPDIR}/log/stdout.%s" % os.getpid(), self.cfgData, True)
|
||||||
|
#mkdirhier(os.path.dirname(logout))
|
||||||
|
#newso = open("/tmp/stdout.%s" % os.getpid(), 'w')
|
||||||
|
#os.dup2(newso.fileno(), sys.stdout.fileno())
|
||||||
|
#os.dup2(newso.fileno(), sys.stderr.fileno())
|
||||||
|
|
||||||
|
# Don't read from stdin from the parent
|
||||||
|
si = file("/dev/null", 'r')
|
||||||
|
os.dup2(si.fileno( ), sys.stdin.fileno( ))
|
||||||
|
|
||||||
|
# We don't want to see signals to our parent, e.g. Ctrl+C
|
||||||
|
os.setpgrp()
|
||||||
|
|
||||||
|
# Save out the PID so that the event can include it the
|
||||||
|
# events
|
||||||
|
bb.event.worker_pid = os.getpid()
|
||||||
|
bb.event.useStdout = False
|
||||||
|
|
||||||
|
hashfile = sys.argv[1]
|
||||||
|
buildfile = sys.argv[2]
|
||||||
|
taskname = sys.argv[3]
|
||||||
|
|
||||||
|
import bb.cooker
|
||||||
|
|
||||||
|
p = pickle.Unpickler(file(hashfile, "rb"))
|
||||||
|
hashdata = p.load()
|
||||||
|
|
||||||
|
debug = hashdata["msg-debug"]
|
||||||
|
debug_domains = hashdata["msg-debug-domains"]
|
||||||
|
verbose = hashdata["verbose"]
|
||||||
|
|
||||||
|
bb.utils.init_logger(bb.msg, verbose, debug, debug_domains)
|
||||||
|
|
||||||
|
cooker = bb.cooker.BBCooker(BBConfiguration(debug, debug_domains), None)
|
||||||
|
cooker.parseConfiguration()
|
||||||
|
|
||||||
|
cooker.bb_cache = bb.cache.init(cooker)
|
||||||
|
cooker.status = bb.cache.CacheData()
|
||||||
|
|
||||||
|
(fn, cls) = cooker.bb_cache.virtualfn2realfn(buildfile)
|
||||||
|
buildfile = cooker.matchFile(fn)
|
||||||
|
fn = cooker.bb_cache.realfn2virtual(buildfile, cls)
|
||||||
|
|
||||||
|
cooker.buildSetVars()
|
||||||
|
|
||||||
|
# Load data into the cache for fn and parse the loaded cache data
|
||||||
|
the_data = cooker.bb_cache.loadDataFull(fn, cooker.get_file_appends(fn), cooker.configuration.data)
|
||||||
|
cooker.bb_cache.setData(fn, buildfile, the_data)
|
||||||
|
cooker.bb_cache.handle_data(fn, cooker.status)
|
||||||
|
|
||||||
|
if taskname.endswith("_setscene"):
|
||||||
|
the_data.setVarFlag(taskname, "quieterrors", "1")
|
||||||
|
|
||||||
|
bb.parse.siggen.set_taskdata(hashdata["hashes"], hashdata["deps"])
|
||||||
|
|
||||||
|
for h in hashdata["hashes"]:
|
||||||
|
bb.data.setVar("BBHASH_%s" % h, hashdata["hashes"][h], the_data)
|
||||||
|
for h in hashdata["deps"]:
|
||||||
|
bb.data.setVar("BBHASHDEPS_%s" % h, hashdata["deps"][h], the_data)
|
||||||
|
|
||||||
|
ret = 0
|
||||||
|
if sys.argv[4] != "True":
|
||||||
|
ret = bb.build.exec_task(fn, taskname, the_data)
|
||||||
|
sys.exit(ret)
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ class HTMLFormatter:
|
|||||||
From pydoc... almost identical at least
|
From pydoc... almost identical at least
|
||||||
"""
|
"""
|
||||||
while pairs:
|
while pairs:
|
||||||
(a,b) = pairs[0]
|
(a, b) = pairs[0]
|
||||||
text = join(split(text, a), b)
|
text = join(split(text, a), b)
|
||||||
pairs = pairs[1:]
|
pairs = pairs[1:]
|
||||||
return text
|
return text
|
||||||
@@ -87,7 +87,7 @@ class HTMLFormatter:
|
|||||||
|
|
||||||
return txt + ",".join(txts)
|
return txt + ",".join(txts)
|
||||||
|
|
||||||
def groups(self,item):
|
def groups(self, item):
|
||||||
"""
|
"""
|
||||||
Create HTML to link to related groups
|
Create HTML to link to related groups
|
||||||
"""
|
"""
|
||||||
@@ -99,12 +99,12 @@ class HTMLFormatter:
|
|||||||
txt = "<p><b>See also:</b><br>"
|
txt = "<p><b>See also:</b><br>"
|
||||||
txts = []
|
txts = []
|
||||||
for group in item.groups():
|
for group in item.groups():
|
||||||
txts.append( """<a href="group%s.html">%s</a> """ % (group,group) )
|
txts.append( """<a href="group%s.html">%s</a> """ % (group, group) )
|
||||||
|
|
||||||
return txt + ",".join(txts)
|
return txt + ",".join(txts)
|
||||||
|
|
||||||
|
|
||||||
def createKeySite(self,item):
|
def createKeySite(self, item):
|
||||||
"""
|
"""
|
||||||
Create a site for a key. It contains the header/navigator, a heading,
|
Create a site for a key. It contains the header/navigator, a heading,
|
||||||
the description, links to related keys and to the groups.
|
the description, links to related keys and to the groups.
|
||||||
@@ -149,8 +149,7 @@ class HTMLFormatter:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
groups = ""
|
groups = ""
|
||||||
sorted_groups = doc.groups()
|
sorted_groups = sorted(doc.groups())
|
||||||
sorted_groups.sort()
|
|
||||||
for group in sorted_groups:
|
for group in sorted_groups:
|
||||||
groups += """<a href="group%s.html">%s</a><br>""" % (group, group)
|
groups += """<a href="group%s.html">%s</a><br>""" % (group, group)
|
||||||
|
|
||||||
@@ -185,8 +184,7 @@ class HTMLFormatter:
|
|||||||
Create Overview of all avilable keys
|
Create Overview of all avilable keys
|
||||||
"""
|
"""
|
||||||
keys = ""
|
keys = ""
|
||||||
sorted_keys = doc.doc_keys()
|
sorted_keys = sorted(doc.doc_keys())
|
||||||
sorted_keys.sort()
|
|
||||||
for key in sorted_keys:
|
for key in sorted_keys:
|
||||||
keys += """<a href="key%s.html">%s</a><br>""" % (key, key)
|
keys += """<a href="key%s.html">%s</a><br>""" % (key, key)
|
||||||
|
|
||||||
@@ -214,7 +212,7 @@ class HTMLFormatter:
|
|||||||
description += "<h2 Description of Grozp %s</h2>" % gr
|
description += "<h2 Description of Grozp %s</h2>" % gr
|
||||||
description += _description
|
description += _description
|
||||||
|
|
||||||
items.sort(lambda x,y:cmp(x.name(),y.name()))
|
items.sort(lambda x, y:cmp(x.name(), y.name()))
|
||||||
for group in items:
|
for group in items:
|
||||||
groups += """<a href="key%s.html">%s</a><br>""" % (group.name(), group.name())
|
groups += """<a href="key%s.html">%s</a><br>""" % (group.name(), group.name())
|
||||||
|
|
||||||
@@ -343,7 +341,7 @@ class DocumentationItem:
|
|||||||
def addGroup(self, group):
|
def addGroup(self, group):
|
||||||
self._groups.append(group)
|
self._groups.append(group)
|
||||||
|
|
||||||
def addRelation(self,relation):
|
def addRelation(self, relation):
|
||||||
self._related.append(relation)
|
self._related.append(relation)
|
||||||
|
|
||||||
def sort(self):
|
def sort(self):
|
||||||
@@ -396,7 +394,7 @@ class Documentation:
|
|||||||
"""
|
"""
|
||||||
return self.__groups.keys()
|
return self.__groups.keys()
|
||||||
|
|
||||||
def group_content(self,group_name):
|
def group_content(self, group_name):
|
||||||
"""
|
"""
|
||||||
Return a list of keys/names that are in a specefic
|
Return a list of keys/names that are in a specefic
|
||||||
group or the empty list
|
group or the empty list
|
||||||
@@ -412,7 +410,7 @@ def parse_cmdline(args):
|
|||||||
Parse the CMD line and return the result as a n-tuple
|
Parse the CMD line and return the result as a n-tuple
|
||||||
"""
|
"""
|
||||||
|
|
||||||
parser = optparse.OptionParser( version = "Bitbake Documentation Tool Core version %s, %%prog version %s" % (bb.__version__,__version__))
|
parser = optparse.OptionParser( version = "Bitbake Documentation Tool Core version %s, %%prog version %s" % (bb.__version__, __version__))
|
||||||
usage = """%prog [options]
|
usage = """%prog [options]
|
||||||
|
|
||||||
Create a set of html pages (documentation) for a bitbake.conf....
|
Create a set of html pages (documentation) for a bitbake.conf....
|
||||||
@@ -428,7 +426,7 @@ Create a set of html pages (documentation) for a bitbake.conf....
|
|||||||
parser.add_option( "-D", "--debug", help = "Increase the debug level",
|
parser.add_option( "-D", "--debug", help = "Increase the debug level",
|
||||||
action = "count", dest = "debug", default = 0 )
|
action = "count", dest = "debug", default = 0 )
|
||||||
|
|
||||||
parser.add_option( "-v","--verbose", help = "output more chit-char to the terminal",
|
parser.add_option( "-v", "--verbose", help = "output more chit-char to the terminal",
|
||||||
action = "store_true", dest = "verbose", default = False )
|
action = "store_true", dest = "verbose", default = False )
|
||||||
|
|
||||||
options, args = parser.parse_args( sys.argv )
|
options, args = parser.parse_args( sys.argv )
|
||||||
@@ -443,7 +441,7 @@ def main():
|
|||||||
The main Method
|
The main Method
|
||||||
"""
|
"""
|
||||||
|
|
||||||
(config_file,output_dir) = parse_cmdline( sys.argv )
|
(config_file, output_dir) = parse_cmdline( sys.argv )
|
||||||
|
|
||||||
# right to let us load the file now
|
# right to let us load the file now
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -215,13 +215,11 @@ addtask printdate before do_build</screen></para>
|
|||||||
<para>BitBake allows to install event handlers. Events are triggered at certain points during operation, such as, the beginning of operation against a given .bb, the start of a given task, task failure, task success, et cetera. The intent was to make it easy to do things like email notifications on build failure.</para>
|
<para>BitBake allows to install event handlers. Events are triggered at certain points during operation, such as, the beginning of operation against a given .bb, the start of a given task, task failure, task success, et cetera. The intent was to make it easy to do things like email notifications on build failure.</para>
|
||||||
<para><screen>addhandler myclass_eventhandler
|
<para><screen>addhandler myclass_eventhandler
|
||||||
python myclass_eventhandler() {
|
python myclass_eventhandler() {
|
||||||
from bb.event import NotHandled, getName
|
from bb.event import getName
|
||||||
from bb import data
|
from bb import data
|
||||||
|
|
||||||
print "The name of the Event is %s" % getName(e)
|
print("The name of the Event is %s" % getName(e))
|
||||||
print "The file we run for is %s" % data.getVar('FILE', e.data, True)
|
print("The file we run for is %s" % data.getVar('FILE', e.data, True))
|
||||||
|
|
||||||
return NotHandled
|
|
||||||
}
|
}
|
||||||
</screen></para><para>
|
</screen></para><para>
|
||||||
This event handler gets called every time an event is triggered. A global variable <varname>e</varname> is defined. <varname>e</varname>.data contains an instance of bb.data. With the getName(<varname>e</varname>)
|
This event handler gets called every time an event is triggered. A global variable <varname>e</varname> is defined. <varname>e</varname>.data contains an instance of bb.data. With the getName(<varname>e</varname>)
|
||||||
@@ -318,9 +316,9 @@ a per URI parameters separated by a <quote>;</quote> consisting of a key and a v
|
|||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>CVS File Fetcher</title>
|
<title>CVS File Fetcher</title>
|
||||||
<para>The URN for the CVS Fetcher is <emphasis>cvs</emphasis>. This Fetcher honors the variables <varname>DL_DIR</varname>, <varname>SRCDATE</varname>, <varname>FETCHCOMMAND_cvs</varname>, <varname>UPDATECOMMAND_cvs</varname>. <varname>DL_DIRS</varname> specifies where a temporary checkout is saved, <varname>SRCDATE</varname> specifies which date to use when doing the fetching (the special value of "now" will cause the checkout to be updated on every build), <varname>FETCHCOMMAND</varname> and <varname>UPDATECOMMAND</varname> specify which executables should be used when doing the CVS checkout or update.
|
<para>The URN for the CVS Fetcher is <emphasis>cvs</emphasis>. This Fetcher honors the variables <varname>DL_DIR</varname>, <varname>SRCDATE</varname>, <varname>FETCHCOMMAND_cvs</varname>, <varname>UPDATECOMMAND_cvs</varname>. <varname>DL_DIR</varname> specifies where a temporary checkout is saved, <varname>SRCDATE</varname> specifies which date to use when doing the fetching (the special value of "now" will cause the checkout to be updated on every build), <varname>FETCHCOMMAND</varname> and <varname>UPDATECOMMAND</varname> specify which executables should be used when doing the CVS checkout or update.
|
||||||
</para>
|
</para>
|
||||||
<para>The supported Parameters are <varname>module</varname>, <varname>tag</varname>, <varname>date</varname>, <varname>method</varname>, <varname>localdir</varname>, <varname>rsh</varname>. The <varname>module</varname> specifies which module to check out, the <varname>tag</varname> describes which CVS TAG should be used for the checkout by default the TAG is empty. A <varname>date</varname> can be specified to override the SRCDATE of the configuration to checkout a specific date. The special value of "now" will cause the checkout to be updated on every build.<varname>method</varname> is by default <emphasis>pserver</emphasis>, if <emphasis>ext</emphasis> is used the <varname>rsh</varname> parameter will be evaluated and <varname>CVS_RSH</varname> will be set. Finally <varname>localdir</varname> is used to checkout into a special directory relative to <varname>CVSDIR></varname>.
|
<para>The supported Parameters are <varname>module</varname>, <varname>tag</varname>, <varname>date</varname>, <varname>method</varname>, <varname>localdir</varname>, <varname>rsh</varname>. The <varname>module</varname> specifies which module to check out, the <varname>tag</varname> describes which CVS TAG should be used for the checkout by default the TAG is empty. A <varname>date</varname> can be specified to override the SRCDATE of the configuration to checkout a specific date. The special value of "now" will cause the checkout to be updated on every build.<varname>method</varname> is by default <emphasis>pserver</emphasis>, if <emphasis>ext</emphasis> is used the <varname>rsh</varname> parameter will be evaluated and <varname>CVS_RSH</varname> will be set. Finally <varname>localdir</varname> is used to checkout into a special directory relative to <varname>CVSDIR</varname>.
|
||||||
<screen><varname>SRC_URI</varname> = "cvs://CVSROOT;module=mymodule;tag=some-version;method=ext"
|
<screen><varname>SRC_URI</varname> = "cvs://CVSROOT;module=mymodule;tag=some-version;method=ext"
|
||||||
<varname>SRC_URI</varname> = "cvs://CVSROOT;module=mymodule;date=20060126;localdir=usethat"
|
<varname>SRC_URI</varname> = "cvs://CVSROOT;module=mymodule;date=20060126;localdir=usethat"
|
||||||
</screen>
|
</screen>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
# This is a copy on write dictionary and set which abuses classes to try and be nice and fast.
|
# This is a copy on write dictionary and set which abuses classes to try and be nice and fast.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006 Tim Amsell
|
# Copyright (C) 2006 Tim Amsell
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License version 2 as
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -18,29 +18,31 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
#
|
#
|
||||||
#Please Note:
|
#Please Note:
|
||||||
# Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW.
|
# Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW.
|
||||||
# Assign a file to __warn__ to get warnings about slow operations.
|
# Assign a file to __warn__ to get warnings about slow operations.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
import copy
|
import copy
|
||||||
import types
|
import types
|
||||||
types.ImmutableTypes = tuple([ \
|
ImmutableTypes = (
|
||||||
types.BooleanType, \
|
types.NoneType,
|
||||||
types.ComplexType, \
|
bool,
|
||||||
types.FloatType, \
|
complex,
|
||||||
types.IntType, \
|
float,
|
||||||
types.LongType, \
|
int,
|
||||||
types.NoneType, \
|
long,
|
||||||
types.TupleType, \
|
tuple,
|
||||||
frozenset] + \
|
frozenset,
|
||||||
list(types.StringTypes))
|
basestring
|
||||||
|
)
|
||||||
|
|
||||||
MUTABLE = "__mutable__"
|
MUTABLE = "__mutable__"
|
||||||
|
|
||||||
class COWMeta(type):
|
class COWMeta(type):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class COWDictMeta(COWMeta):
|
class COWDictMeta(COWMeta):
|
||||||
__warn__ = False
|
__warn__ = False
|
||||||
__hasmutable__ = False
|
__hasmutable__ = False
|
||||||
@@ -59,12 +61,12 @@ class COWDictMeta(COWMeta):
|
|||||||
__call__ = cow
|
__call__ = cow
|
||||||
|
|
||||||
def __setitem__(cls, key, value):
|
def __setitem__(cls, key, value):
|
||||||
if not isinstance(value, types.ImmutableTypes):
|
if not isinstance(value, ImmutableTypes):
|
||||||
if not isinstance(value, COWMeta):
|
if not isinstance(value, COWMeta):
|
||||||
cls.__hasmutable__ = True
|
cls.__hasmutable__ = True
|
||||||
key += MUTABLE
|
key += MUTABLE
|
||||||
setattr(cls, key, value)
|
setattr(cls, key, value)
|
||||||
|
|
||||||
def __getmutable__(cls, key, readonly=False):
|
def __getmutable__(cls, key, readonly=False):
|
||||||
nkey = key + MUTABLE
|
nkey = key + MUTABLE
|
||||||
try:
|
try:
|
||||||
@@ -77,10 +79,10 @@ class COWDictMeta(COWMeta):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
if not cls.__warn__ is False and not isinstance(value, COWMeta):
|
if not cls.__warn__ is False and not isinstance(value, COWMeta):
|
||||||
print >> cls.__warn__, "Warning: Doing a copy because %s is a mutable type." % key
|
print("Warning: Doing a copy because %s is a mutable type." % key, file=cls.__warn__)
|
||||||
try:
|
try:
|
||||||
value = value.copy()
|
value = value.copy()
|
||||||
except AttributeError, e:
|
except AttributeError as e:
|
||||||
value = copy.copy(value)
|
value = copy.copy(value)
|
||||||
setattr(cls, nkey, value)
|
setattr(cls, nkey, value)
|
||||||
return value
|
return value
|
||||||
@@ -98,13 +100,13 @@ class COWDictMeta(COWMeta):
|
|||||||
value = getattr(cls, key)
|
value = getattr(cls, key)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
value = cls.__getmutable__(key, readonly)
|
value = cls.__getmutable__(key, readonly)
|
||||||
|
|
||||||
# This is for values which have been deleted
|
# This is for values which have been deleted
|
||||||
if value is cls.__marker__:
|
if value is cls.__marker__:
|
||||||
raise AttributeError("key %s does not exist." % key)
|
raise AttributeError("key %s does not exist." % key)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
except AttributeError, e:
|
except AttributeError as e:
|
||||||
if not default is cls.__getmarker__:
|
if not default is cls.__getmarker__:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
@@ -118,6 +120,9 @@ class COWDictMeta(COWMeta):
|
|||||||
key += MUTABLE
|
key += MUTABLE
|
||||||
delattr(cls, key)
|
delattr(cls, key)
|
||||||
|
|
||||||
|
def __contains__(cls, key):
|
||||||
|
return cls.has_key(key)
|
||||||
|
|
||||||
def has_key(cls, key):
|
def has_key(cls, key):
|
||||||
value = cls.__getreadonly__(key, cls.__marker__)
|
value = cls.__getreadonly__(key, cls.__marker__)
|
||||||
if value is cls.__marker__:
|
if value is cls.__marker__:
|
||||||
@@ -127,7 +132,7 @@ class COWDictMeta(COWMeta):
|
|||||||
def iter(cls, type, readonly=False):
|
def iter(cls, type, readonly=False):
|
||||||
for key in dir(cls):
|
for key in dir(cls):
|
||||||
if key.startswith("__"):
|
if key.startswith("__"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if key.endswith(MUTABLE):
|
if key.endswith(MUTABLE):
|
||||||
key = key[:-len(MUTABLE)]
|
key = key[:-len(MUTABLE)]
|
||||||
@@ -153,11 +158,11 @@ class COWDictMeta(COWMeta):
|
|||||||
return cls.iter("keys")
|
return cls.iter("keys")
|
||||||
def itervalues(cls, readonly=False):
|
def itervalues(cls, readonly=False):
|
||||||
if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
|
if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
|
||||||
print >> cls.__warn__, "Warning: If you arn't going to change any of the values call with True."
|
print("Warning: If you arn't going to change any of the values call with True.", file=cls.__warn__)
|
||||||
return cls.iter("values", readonly)
|
return cls.iter("values", readonly)
|
||||||
def iteritems(cls, readonly=False):
|
def iteritems(cls, readonly=False):
|
||||||
if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
|
if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
|
||||||
print >> cls.__warn__, "Warning: If you arn't going to change any of the values call with True."
|
print("Warning: If you arn't going to change any of the values call with True.", file=cls.__warn__)
|
||||||
return cls.iter("items", readonly)
|
return cls.iter("items", readonly)
|
||||||
|
|
||||||
class COWSetMeta(COWDictMeta):
|
class COWSetMeta(COWDictMeta):
|
||||||
@@ -176,13 +181,13 @@ class COWSetMeta(COWDictMeta):
|
|||||||
|
|
||||||
def remove(cls, value):
|
def remove(cls, value):
|
||||||
COWDictMeta.__delitem__(cls, repr(hash(value)))
|
COWDictMeta.__delitem__(cls, repr(hash(value)))
|
||||||
|
|
||||||
def __in__(cls, value):
|
def __in__(cls, value):
|
||||||
return COWDictMeta.has_key(repr(hash(value)))
|
return COWDictMeta.has_key(repr(hash(value)))
|
||||||
|
|
||||||
def iterkeys(cls):
|
def iterkeys(cls):
|
||||||
raise TypeError("sets don't have keys")
|
raise TypeError("sets don't have keys")
|
||||||
|
|
||||||
def iteritems(cls):
|
def iteritems(cls):
|
||||||
raise TypeError("sets don't have 'items'")
|
raise TypeError("sets don't have 'items'")
|
||||||
|
|
||||||
@@ -199,120 +204,120 @@ if __name__ == "__main__":
|
|||||||
import sys
|
import sys
|
||||||
COWDictBase.__warn__ = sys.stderr
|
COWDictBase.__warn__ = sys.stderr
|
||||||
a = COWDictBase()
|
a = COWDictBase()
|
||||||
print "a", a
|
print("a", a)
|
||||||
|
|
||||||
a['a'] = 'a'
|
a['a'] = 'a'
|
||||||
a['b'] = 'b'
|
a['b'] = 'b'
|
||||||
a['dict'] = {}
|
a['dict'] = {}
|
||||||
|
|
||||||
b = a.copy()
|
b = a.copy()
|
||||||
print "b", b
|
print("b", b)
|
||||||
b['c'] = 'b'
|
b['c'] = 'b'
|
||||||
|
|
||||||
print
|
print()
|
||||||
|
|
||||||
print "a", a
|
print("a", a)
|
||||||
for x in a.iteritems():
|
for x in a.iteritems():
|
||||||
print x
|
print(x)
|
||||||
print "--"
|
print("--")
|
||||||
print "b", b
|
print("b", b)
|
||||||
for x in b.iteritems():
|
for x in b.iteritems():
|
||||||
print x
|
print(x)
|
||||||
print
|
print()
|
||||||
|
|
||||||
b['dict']['a'] = 'b'
|
b['dict']['a'] = 'b'
|
||||||
b['a'] = 'c'
|
b['a'] = 'c'
|
||||||
|
|
||||||
print "a", a
|
print("a", a)
|
||||||
for x in a.iteritems():
|
for x in a.iteritems():
|
||||||
print x
|
print(x)
|
||||||
print "--"
|
print("--")
|
||||||
print "b", b
|
print("b", b)
|
||||||
for x in b.iteritems():
|
for x in b.iteritems():
|
||||||
print x
|
print(x)
|
||||||
print
|
print()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
b['dict2']
|
b['dict2']
|
||||||
except KeyError, e:
|
except KeyError as e:
|
||||||
print "Okay!"
|
print("Okay!")
|
||||||
|
|
||||||
a['set'] = COWSetBase()
|
a['set'] = COWSetBase()
|
||||||
a['set'].add("o1")
|
a['set'].add("o1")
|
||||||
a['set'].add("o1")
|
a['set'].add("o1")
|
||||||
a['set'].add("o2")
|
a['set'].add("o2")
|
||||||
|
|
||||||
print "a", a
|
print("a", a)
|
||||||
for x in a['set'].itervalues():
|
for x in a['set'].itervalues():
|
||||||
print x
|
print(x)
|
||||||
print "--"
|
print("--")
|
||||||
print "b", b
|
print("b", b)
|
||||||
for x in b['set'].itervalues():
|
for x in b['set'].itervalues():
|
||||||
print x
|
print(x)
|
||||||
print
|
print()
|
||||||
|
|
||||||
b['set'].add('o3')
|
b['set'].add('o3')
|
||||||
|
|
||||||
print "a", a
|
print("a", a)
|
||||||
for x in a['set'].itervalues():
|
for x in a['set'].itervalues():
|
||||||
print x
|
print(x)
|
||||||
print "--"
|
print("--")
|
||||||
print "b", b
|
print("b", b)
|
||||||
for x in b['set'].itervalues():
|
for x in b['set'].itervalues():
|
||||||
print x
|
print(x)
|
||||||
print
|
print()
|
||||||
|
|
||||||
a['set2'] = set()
|
a['set2'] = set()
|
||||||
a['set2'].add("o1")
|
a['set2'].add("o1")
|
||||||
a['set2'].add("o1")
|
a['set2'].add("o1")
|
||||||
a['set2'].add("o2")
|
a['set2'].add("o2")
|
||||||
|
|
||||||
print "a", a
|
print("a", a)
|
||||||
for x in a.iteritems():
|
for x in a.iteritems():
|
||||||
print x
|
print(x)
|
||||||
print "--"
|
print("--")
|
||||||
print "b", b
|
print("b", b)
|
||||||
for x in b.iteritems(readonly=True):
|
for x in b.iteritems(readonly=True):
|
||||||
print x
|
print(x)
|
||||||
print
|
print()
|
||||||
|
|
||||||
del b['b']
|
del b['b']
|
||||||
try:
|
try:
|
||||||
print b['b']
|
print(b['b'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print "Yay! deleted key raises error"
|
print("Yay! deleted key raises error")
|
||||||
|
|
||||||
if b.has_key('b'):
|
if b.has_key('b'):
|
||||||
print "Boo!"
|
print("Boo!")
|
||||||
else:
|
else:
|
||||||
print "Yay - has_key with delete works!"
|
print("Yay - has_key with delete works!")
|
||||||
|
|
||||||
print "a", a
|
print("a", a)
|
||||||
for x in a.iteritems():
|
for x in a.iteritems():
|
||||||
print x
|
print(x)
|
||||||
print "--"
|
print("--")
|
||||||
print "b", b
|
print("b", b)
|
||||||
for x in b.iteritems(readonly=True):
|
for x in b.iteritems(readonly=True):
|
||||||
print x
|
print(x)
|
||||||
print
|
print()
|
||||||
|
|
||||||
b.__revertitem__('b')
|
b.__revertitem__('b')
|
||||||
|
|
||||||
print "a", a
|
print("a", a)
|
||||||
for x in a.iteritems():
|
for x in a.iteritems():
|
||||||
print x
|
print(x)
|
||||||
print "--"
|
print("--")
|
||||||
print "b", b
|
print("b", b)
|
||||||
for x in b.iteritems(readonly=True):
|
for x in b.iteritems(readonly=True):
|
||||||
print x
|
print(x)
|
||||||
print
|
print()
|
||||||
|
|
||||||
b.__revertitem__('dict')
|
b.__revertitem__('dict')
|
||||||
print "a", a
|
print("a", a)
|
||||||
for x in a.iteritems():
|
for x in a.iteritems():
|
||||||
print x
|
print(x)
|
||||||
print "--"
|
print("--")
|
||||||
print "b", b
|
print("b", b)
|
||||||
for x in b.iteritems(readonly=True):
|
for x in b.iteritems(readonly=True):
|
||||||
print x
|
print(x)
|
||||||
print
|
print()
|
||||||
|
|||||||
@@ -21,39 +21,14 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
__version__ = "1.9.0"
|
__version__ = "1.11.0"
|
||||||
|
|
||||||
__all__ = [
|
import sys
|
||||||
|
if sys.version_info < (2, 6, 0):
|
||||||
|
raise RuntimeError("Sorry, python 2.6.0 or later is required for this version of bitbake")
|
||||||
|
|
||||||
"debug",
|
import os
|
||||||
"note",
|
import bb.msg
|
||||||
"error",
|
|
||||||
"fatal",
|
|
||||||
|
|
||||||
"mkdirhier",
|
|
||||||
"movefile",
|
|
||||||
"vercmp",
|
|
||||||
|
|
||||||
# fetch
|
|
||||||
"decodeurl",
|
|
||||||
"encodeurl",
|
|
||||||
|
|
||||||
# modules
|
|
||||||
"parse",
|
|
||||||
"data",
|
|
||||||
"command",
|
|
||||||
"event",
|
|
||||||
"build",
|
|
||||||
"fetch",
|
|
||||||
"manifest",
|
|
||||||
"methodpool",
|
|
||||||
"cache",
|
|
||||||
"runqueue",
|
|
||||||
"taskdata",
|
|
||||||
"providers",
|
|
||||||
]
|
|
||||||
|
|
||||||
import sys, os, types, re, string
|
|
||||||
|
|
||||||
if "BBDEBUG" in os.environ:
|
if "BBDEBUG" in os.environ:
|
||||||
level = int(os.environ["BBDEBUG"])
|
level = int(os.environ["BBDEBUG"])
|
||||||
@@ -81,14 +56,45 @@ def fatal(*args):
|
|||||||
bb.msg.fatal(None, ''.join(args))
|
bb.msg.fatal(None, ''.join(args))
|
||||||
|
|
||||||
|
|
||||||
|
def deprecated(func, name = None, advice = ""):
|
||||||
|
"""This is a decorator which can be used to mark functions
|
||||||
|
as deprecated. It will result in a warning being emmitted
|
||||||
|
when the function is used."""
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
if advice:
|
||||||
|
advice = ": %s" % advice
|
||||||
|
if name is None:
|
||||||
|
name = func.__name__
|
||||||
|
|
||||||
|
def newFunc(*args, **kwargs):
|
||||||
|
warnings.warn("Call to deprecated function %s%s." % (name,
|
||||||
|
advice),
|
||||||
|
category = PendingDeprecationWarning,
|
||||||
|
stacklevel = 2)
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
newFunc.__name__ = func.__name__
|
||||||
|
newFunc.__doc__ = func.__doc__
|
||||||
|
newFunc.__dict__.update(func.__dict__)
|
||||||
|
return newFunc
|
||||||
|
|
||||||
# For compatibility
|
# For compatibility
|
||||||
from bb.fetch import MalformedUrl, encodeurl, decodeurl
|
def deprecate_import(current, modulename, fromlist, renames = None):
|
||||||
from bb.data import VarExpandError
|
"""Import objects from one module into another, wrapping them with a DeprecationWarning"""
|
||||||
from bb.utils import mkdirhier, movefile, copyfile, which
|
import sys
|
||||||
from bb.utils import vercmp
|
|
||||||
|
|
||||||
|
module = __import__(modulename, fromlist = fromlist)
|
||||||
|
for position, objname in enumerate(fromlist):
|
||||||
|
obj = getattr(module, objname)
|
||||||
|
newobj = deprecated(obj, "{0}.{1}".format(current, objname),
|
||||||
|
"Please use {0}.{1} instead".format(modulename, objname))
|
||||||
|
if renames:
|
||||||
|
newname = renames[position]
|
||||||
|
else:
|
||||||
|
newname = objname
|
||||||
|
|
||||||
if __name__ == "__main__":
|
setattr(sys.modules[current], newname, newobj)
|
||||||
import doctest, bb
|
|
||||||
bb.msg.set_debug_level(0)
|
deprecate_import(__name__, "bb.fetch", ("MalformedUrl", "encodeurl", "decodeurl"))
|
||||||
doctest.testmod(bb)
|
deprecate_import(__name__, "bb.utils", ("mkdirhier", "movefile", "copyfile", "which"))
|
||||||
|
deprecate_import(__name__, "bb.utils", ["vercmp_string"], ["vercmp"])
|
||||||
|
|||||||
@@ -27,8 +27,9 @@
|
|||||||
|
|
||||||
from bb import data, event, mkdirhier, utils
|
from bb import data, event, mkdirhier, utils
|
||||||
import bb, os, sys
|
import bb, os, sys
|
||||||
|
import bb.utils
|
||||||
|
|
||||||
# When we execute a python function we'd like certain things
|
# When we execute a python function we'd like certain things
|
||||||
# in all namespaces, hence we add them to __builtins__
|
# in all namespaces, hence we add them to __builtins__
|
||||||
# If we do not do this and use the exec globals, they will
|
# If we do not do this and use the exec globals, they will
|
||||||
# not be available to subfunctions.
|
# not be available to subfunctions.
|
||||||
@@ -43,12 +44,6 @@ class FuncFailed(Exception):
|
|||||||
Second paramter is a logfile (optional)
|
Second paramter is a logfile (optional)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class EventException(Exception):
|
|
||||||
"""Exception which is associated with an Event."""
|
|
||||||
|
|
||||||
def __init__(self, msg, event):
|
|
||||||
self.args = msg, event
|
|
||||||
|
|
||||||
class TaskBase(event.Event):
|
class TaskBase(event.Event):
|
||||||
"""Base class for task events"""
|
"""Base class for task events"""
|
||||||
|
|
||||||
@@ -79,7 +74,7 @@ class TaskFailed(TaskBase):
|
|||||||
self.msg = msg
|
self.msg = msg
|
||||||
TaskBase.__init__(self, t, d)
|
TaskBase.__init__(self, t, d)
|
||||||
|
|
||||||
class InvalidTask(TaskBase):
|
class TaskInvalid(TaskBase):
|
||||||
"""Invalid Task"""
|
"""Invalid Task"""
|
||||||
|
|
||||||
# functions
|
# functions
|
||||||
@@ -89,27 +84,29 @@ def exec_func(func, d, dirs = None):
|
|||||||
|
|
||||||
body = data.getVar(func, d)
|
body = data.getVar(func, d)
|
||||||
if not body:
|
if not body:
|
||||||
|
bb.warn("Function %s doesn't exist" % func)
|
||||||
return
|
return
|
||||||
|
|
||||||
flags = data.getVarFlags(func, d)
|
flags = data.getVarFlags(func, d)
|
||||||
for item in ['deps', 'check', 'interactive', 'python', 'cleandirs', 'dirs', 'lockfiles', 'fakeroot']:
|
for item in ['deps', 'check', 'interactive', 'python', 'cleandirs', 'dirs', 'lockfiles', 'fakeroot', 'task']:
|
||||||
if not item in flags:
|
if not item in flags:
|
||||||
flags[item] = None
|
flags[item] = None
|
||||||
|
|
||||||
ispython = flags['python']
|
ispython = flags['python']
|
||||||
|
|
||||||
cleandirs = (data.expand(flags['cleandirs'], d) or "").split()
|
cleandirs = flags['cleandirs']
|
||||||
for cdir in cleandirs:
|
if cleandirs:
|
||||||
os.system("rm -rf %s" % cdir)
|
for cdir in data.expand(cleandirs, d).split():
|
||||||
|
os.system("rm -rf %s" % cdir)
|
||||||
|
|
||||||
|
if dirs is None:
|
||||||
|
dirs = flags['dirs']
|
||||||
|
if dirs:
|
||||||
|
dirs = data.expand(dirs, d).split()
|
||||||
|
|
||||||
if dirs:
|
if dirs:
|
||||||
dirs = data.expand(dirs, d)
|
for adir in dirs:
|
||||||
else:
|
bb.utils.mkdirhier(adir)
|
||||||
dirs = (data.expand(flags['dirs'], d) or "").split()
|
|
||||||
for adir in dirs:
|
|
||||||
mkdirhier(adir)
|
|
||||||
|
|
||||||
if len(dirs) > 0:
|
|
||||||
adir = dirs[-1]
|
adir = dirs[-1]
|
||||||
else:
|
else:
|
||||||
adir = data.getVar('B', d, 1)
|
adir = data.getVar('B', d, 1)
|
||||||
@@ -120,45 +117,23 @@ def exec_func(func, d, dirs = None):
|
|||||||
except OSError:
|
except OSError:
|
||||||
prevdir = data.getVar('TOPDIR', d, True)
|
prevdir = data.getVar('TOPDIR', d, True)
|
||||||
|
|
||||||
# Setup logfiles
|
# Setup scriptfile
|
||||||
t = data.getVar('T', d, 1)
|
t = data.getVar('T', d, 1)
|
||||||
if not t:
|
if not t:
|
||||||
bb.msg.fatal(bb.msg.domain.Build, "T not set")
|
raise SystemExit("T variable not set, unable to build")
|
||||||
mkdirhier(t)
|
bb.utils.mkdirhier(t)
|
||||||
logfile = "%s/log.%s.%s" % (t, func, str(os.getpid()))
|
|
||||||
runfile = "%s/run.%s.%s" % (t, func, str(os.getpid()))
|
runfile = "%s/run.%s.%s" % (t, func, str(os.getpid()))
|
||||||
|
logfile = d.getVar("BB_LOGFILE", True)
|
||||||
|
|
||||||
# Change to correct directory (if specified)
|
# Change to correct directory (if specified)
|
||||||
if adir and os.access(adir, os.F_OK):
|
if adir and os.access(adir, os.F_OK):
|
||||||
os.chdir(adir)
|
os.chdir(adir)
|
||||||
|
|
||||||
# Handle logfiles
|
|
||||||
si = file('/dev/null', 'r')
|
|
||||||
try:
|
|
||||||
if bb.msg.debug_level['default'] > 0 or ispython:
|
|
||||||
so = os.popen("tee \"%s\"" % logfile, "w")
|
|
||||||
else:
|
|
||||||
so = file(logfile, 'w')
|
|
||||||
except OSError, e:
|
|
||||||
bb.msg.error(bb.msg.domain.Build, "opening log file: %s" % e)
|
|
||||||
pass
|
|
||||||
|
|
||||||
se = so
|
|
||||||
|
|
||||||
# Dup the existing fds so we dont lose them
|
|
||||||
osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()]
|
|
||||||
oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()]
|
|
||||||
ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
|
|
||||||
|
|
||||||
# Replace those fds with our own
|
|
||||||
os.dup2(si.fileno(), osi[1])
|
|
||||||
os.dup2(so.fileno(), oso[1])
|
|
||||||
os.dup2(se.fileno(), ose[1])
|
|
||||||
|
|
||||||
locks = []
|
locks = []
|
||||||
lockfiles = (data.expand(flags['lockfiles'], d) or "").split()
|
lockfiles = flags['lockfiles']
|
||||||
for lock in lockfiles:
|
if lockfiles:
|
||||||
locks.append(bb.utils.lockfile(lock))
|
for lock in data.expand(lockfiles, d).split():
|
||||||
|
locks.append(bb.utils.lockfile(lock))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Run the function
|
# Run the function
|
||||||
@@ -179,47 +154,25 @@ def exec_func(func, d, dirs = None):
|
|||||||
for lock in locks:
|
for lock in locks:
|
||||||
bb.utils.unlockfile(lock)
|
bb.utils.unlockfile(lock)
|
||||||
|
|
||||||
# Restore the backup fds
|
|
||||||
os.dup2(osi[0], osi[1])
|
|
||||||
os.dup2(oso[0], oso[1])
|
|
||||||
os.dup2(ose[0], ose[1])
|
|
||||||
|
|
||||||
# Close our logs
|
|
||||||
si.close()
|
|
||||||
so.close()
|
|
||||||
se.close()
|
|
||||||
|
|
||||||
if os.path.exists(logfile) and os.path.getsize(logfile) == 0:
|
|
||||||
bb.msg.debug(2, bb.msg.domain.Build, "Zero size logfile %s, removing" % logfile)
|
|
||||||
os.remove(logfile)
|
|
||||||
|
|
||||||
# Close the backup fds
|
|
||||||
os.close(osi[0])
|
|
||||||
os.close(oso[0])
|
|
||||||
os.close(ose[0])
|
|
||||||
|
|
||||||
def exec_func_python(func, d, runfile, logfile):
|
def exec_func_python(func, d, runfile, logfile):
|
||||||
"""Execute a python BB 'function'"""
|
"""Execute a python BB 'function'"""
|
||||||
import re, os
|
|
||||||
|
|
||||||
bbfile = bb.data.getVar('FILE', d, 1)
|
bbfile = bb.data.getVar('FILE', d, 1)
|
||||||
tmp = "def " + func + "():\n%s" % data.getVar(func, d)
|
tmp = "def " + func + "(d):\n%s" % data.getVar(func, d)
|
||||||
tmp += '\n' + func + '()'
|
tmp += '\n' + func + '(d)'
|
||||||
|
|
||||||
f = open(runfile, "w")
|
f = open(runfile, "w")
|
||||||
f.write(tmp)
|
f.write(tmp)
|
||||||
comp = utils.better_compile(tmp, func, bbfile)
|
comp = utils.better_compile(tmp, func, bbfile)
|
||||||
g = {} # globals
|
|
||||||
g['d'] = d
|
|
||||||
try:
|
try:
|
||||||
utils.better_exec(comp, g, tmp, bbfile)
|
utils.better_exec(comp, {"d": d}, tmp, bbfile)
|
||||||
except:
|
except:
|
||||||
(t,value,tb) = sys.exc_info()
|
(t, value, tb) = sys.exc_info()
|
||||||
|
|
||||||
if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
|
if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
|
||||||
raise
|
raise
|
||||||
bb.msg.error(bb.msg.domain.Build, "Function %s failed" % func)
|
raise FuncFailed("Function %s failed" % func, logfile)
|
||||||
raise FuncFailed("function %s failed" % func, logfile)
|
|
||||||
|
|
||||||
def exec_func_shell(func, d, runfile, logfile, flags):
|
def exec_func_shell(func, d, runfile, logfile, flags):
|
||||||
"""Execute a shell BB 'function' Returns true if execution was successful.
|
"""Execute a shell BB 'function' Returns true if execution was successful.
|
||||||
@@ -241,32 +194,29 @@ def exec_func_shell(func, d, runfile, logfile, flags):
|
|||||||
f = open(runfile, "w")
|
f = open(runfile, "w")
|
||||||
f.write("#!/bin/sh -e\n")
|
f.write("#!/bin/sh -e\n")
|
||||||
if bb.msg.debug_level['default'] > 0: f.write("set -x\n")
|
if bb.msg.debug_level['default'] > 0: f.write("set -x\n")
|
||||||
data.emit_env(f, d)
|
data.emit_func(func, f, d)
|
||||||
|
|
||||||
f.write("cd %s\n" % os.getcwd())
|
f.write("cd %s\n" % os.getcwd())
|
||||||
if func: f.write("%s\n" % func)
|
if func: f.write("%s\n" % func)
|
||||||
f.close()
|
f.close()
|
||||||
os.chmod(runfile, 0775)
|
os.chmod(runfile, 0775)
|
||||||
if not func:
|
if not func:
|
||||||
bb.msg.error(bb.msg.domain.Build, "Function not specified")
|
|
||||||
raise FuncFailed("Function not specified for exec_func_shell")
|
raise FuncFailed("Function not specified for exec_func_shell")
|
||||||
|
|
||||||
# execute function
|
# execute function
|
||||||
if flags['fakeroot']:
|
if flags['fakeroot'] and not flags['task']:
|
||||||
maybe_fakeroot = "PATH=\"%s\" fakeroot " % bb.data.getVar("PATH", d, 1)
|
bb.fatal("Function %s specifies fakeroot but isn't a task?!" % func)
|
||||||
else:
|
|
||||||
maybe_fakeroot = ''
|
|
||||||
lang_environment = "LC_ALL=C "
|
lang_environment = "LC_ALL=C "
|
||||||
ret = os.system('%s%ssh -e %s' % (lang_environment, maybe_fakeroot, runfile))
|
ret = os.system('%ssh -e %s' % (lang_environment, runfile))
|
||||||
|
|
||||||
if ret == 0:
|
if ret == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
bb.msg.error(bb.msg.domain.Build, "Function %s failed" % func)
|
|
||||||
raise FuncFailed("function %s failed" % func, logfile)
|
raise FuncFailed("function %s failed" % func, logfile)
|
||||||
|
|
||||||
|
|
||||||
def exec_task(task, d):
|
def exec_task(fn, task, d):
|
||||||
"""Execute an BB 'task'
|
"""Execute an BB 'task'
|
||||||
|
|
||||||
The primary difference between executing a task versus executing
|
The primary difference between executing a task versus executing
|
||||||
@@ -275,7 +225,13 @@ def exec_task(task, d):
|
|||||||
|
|
||||||
# Check whther this is a valid task
|
# Check whther this is a valid task
|
||||||
if not data.getVarFlag(task, 'task', d):
|
if not data.getVarFlag(task, 'task', d):
|
||||||
raise EventException("No such task", InvalidTask(task, d))
|
event.fire(TaskInvalid(task, d), d)
|
||||||
|
bb.msg.error(bb.msg.domain.Build, "No such task: %s" % task)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
quieterr = False
|
||||||
|
if d.getVarFlag(task, "quieterrors") is not None:
|
||||||
|
quieterr = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % task)
|
bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % task)
|
||||||
@@ -284,29 +240,126 @@ def exec_task(task, d):
|
|||||||
data.setVar('OVERRIDES', 'task-%s:%s' % (task[3:], old_overrides), localdata)
|
data.setVar('OVERRIDES', 'task-%s:%s' % (task[3:], old_overrides), localdata)
|
||||||
data.update_data(localdata)
|
data.update_data(localdata)
|
||||||
data.expandKeys(localdata)
|
data.expandKeys(localdata)
|
||||||
|
data.setVar('BB_FILENAME', fn, d)
|
||||||
|
data.setVar('BB_CURRENTTASK', task[3:], d)
|
||||||
event.fire(TaskStarted(task, localdata), localdata)
|
event.fire(TaskStarted(task, localdata), localdata)
|
||||||
|
|
||||||
|
# Setup logfiles
|
||||||
|
t = data.getVar('T', d, 1)
|
||||||
|
if not t:
|
||||||
|
raise SystemExit("T variable not set, unable to build")
|
||||||
|
bb.utils.mkdirhier(t)
|
||||||
|
loglink = "%s/log.%s" % (t, task)
|
||||||
|
logfile = "%s/log.%s.%s" % (t, task, str(os.getpid()))
|
||||||
|
d.setVar("BB_LOGFILE", logfile)
|
||||||
|
|
||||||
|
# Even though the log file has not yet been opened, lets create the link
|
||||||
|
if loglink:
|
||||||
|
try:
|
||||||
|
os.remove(loglink)
|
||||||
|
except OSError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.symlink(logfile, loglink)
|
||||||
|
except OSError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Handle logfiles
|
||||||
|
si = file('/dev/null', 'r')
|
||||||
|
try:
|
||||||
|
so = file(logfile, 'w')
|
||||||
|
except OSError as e:
|
||||||
|
bb.msg.error(bb.msg.domain.Build, "opening log file: %s" % e)
|
||||||
|
pass
|
||||||
|
se = so
|
||||||
|
|
||||||
|
# Dup the existing fds so we dont lose them
|
||||||
|
osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()]
|
||||||
|
oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()]
|
||||||
|
ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
|
||||||
|
|
||||||
|
# Replace those fds with our own
|
||||||
|
os.dup2(si.fileno(), osi[1])
|
||||||
|
os.dup2(so.fileno(), oso[1])
|
||||||
|
os.dup2(se.fileno(), ose[1])
|
||||||
|
|
||||||
|
# Since we've remapped stdout and stderr, its safe for log messages to be printed there now
|
||||||
|
# exec_func can nest so we have to save state
|
||||||
|
origstdout = bb.event.useStdout
|
||||||
|
bb.event.useStdout = True
|
||||||
|
|
||||||
|
|
||||||
|
prefuncs = (data.getVarFlag(task, 'prefuncs', localdata) or "").split()
|
||||||
|
for func in prefuncs:
|
||||||
|
exec_func(func, localdata)
|
||||||
exec_func(task, localdata)
|
exec_func(task, localdata)
|
||||||
|
postfuncs = (data.getVarFlag(task, 'postfuncs', localdata) or "").split()
|
||||||
|
for func in postfuncs:
|
||||||
|
exec_func(func, localdata)
|
||||||
|
|
||||||
event.fire(TaskSucceeded(task, localdata), localdata)
|
event.fire(TaskSucceeded(task, localdata), localdata)
|
||||||
except FuncFailed, message:
|
|
||||||
|
# make stamp, or cause event and raise exception
|
||||||
|
if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d):
|
||||||
|
make_stamp(task, d)
|
||||||
|
|
||||||
|
except FuncFailed as message:
|
||||||
# Try to extract the optional logfile
|
# Try to extract the optional logfile
|
||||||
try:
|
try:
|
||||||
(msg, logfile) = message
|
(msg, logfile) = message
|
||||||
except:
|
except:
|
||||||
logfile = None
|
logfile = None
|
||||||
msg = message
|
msg = message
|
||||||
bb.msg.note(1, bb.msg.domain.Build, "Task failed: %s" % message )
|
if not quieterr:
|
||||||
failedevent = TaskFailed(msg, logfile, task, d)
|
bb.msg.error(bb.msg.domain.Build, "Task failed: %s" % message )
|
||||||
event.fire(failedevent, d)
|
failedevent = TaskFailed(msg, logfile, task, d)
|
||||||
raise EventException("Function failed in task: %s" % message, failedevent)
|
event.fire(failedevent, d)
|
||||||
|
return 1
|
||||||
|
|
||||||
# make stamp, or cause event and raise exception
|
except Exception:
|
||||||
if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d):
|
from traceback import format_exc
|
||||||
make_stamp(task, d)
|
if not quieterr:
|
||||||
|
bb.msg.error(bb.msg.domain.Build, "Build of %s failed" % (task))
|
||||||
|
bb.msg.error(bb.msg.domain.Build, format_exc())
|
||||||
|
failedevent = TaskFailed("Task Failed", None, task, d)
|
||||||
|
event.fire(failedevent, d)
|
||||||
|
return 1
|
||||||
|
finally:
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
bb.event.useStdout = origstdout
|
||||||
|
|
||||||
|
# Restore the backup fds
|
||||||
|
os.dup2(osi[0], osi[1])
|
||||||
|
os.dup2(oso[0], oso[1])
|
||||||
|
os.dup2(ose[0], ose[1])
|
||||||
|
|
||||||
|
# Close our logs
|
||||||
|
si.close()
|
||||||
|
so.close()
|
||||||
|
se.close()
|
||||||
|
|
||||||
|
if logfile and os.path.exists(logfile) and os.path.getsize(logfile) == 0:
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Build, "Zero size logfile %s, removing" % logfile)
|
||||||
|
os.remove(logfile)
|
||||||
|
try:
|
||||||
|
os.remove(loglink)
|
||||||
|
except OSError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Close the backup fds
|
||||||
|
os.close(osi[0])
|
||||||
|
os.close(oso[0])
|
||||||
|
os.close(ose[0])
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
def extract_stamp(d, fn):
|
def extract_stamp(d, fn):
|
||||||
"""
|
"""
|
||||||
Extracts stamp format which is either a data dictonary (fn unset)
|
Extracts stamp format which is either a data dictionary (fn unset)
|
||||||
or a dataCache entry (fn set).
|
or a dataCache entry (fn set).
|
||||||
"""
|
"""
|
||||||
if fn:
|
if fn:
|
||||||
return d.stamp[fn]
|
return d.stamp[fn]
|
||||||
@@ -323,7 +376,7 @@ def stamp_internal(task, d, file_name):
|
|||||||
if not stamp:
|
if not stamp:
|
||||||
return
|
return
|
||||||
stamp = "%s.%s" % (stamp, task)
|
stamp = "%s.%s" % (stamp, task)
|
||||||
mkdirhier(os.path.dirname(stamp))
|
bb.utils.mkdirhier(os.path.dirname(stamp))
|
||||||
# Remove the file and recreate to force timestamp
|
# Remove the file and recreate to force timestamp
|
||||||
# change on broken NFS filesystems
|
# change on broken NFS filesystems
|
||||||
if os.access(stamp, os.F_OK):
|
if os.access(stamp, os.F_OK):
|
||||||
@@ -363,7 +416,7 @@ def add_tasks(tasklist, d):
|
|||||||
if not task in task_deps['tasks']:
|
if not task in task_deps['tasks']:
|
||||||
task_deps['tasks'].append(task)
|
task_deps['tasks'].append(task)
|
||||||
|
|
||||||
flags = data.getVarFlags(task, d)
|
flags = data.getVarFlags(task, d)
|
||||||
def getTask(name):
|
def getTask(name):
|
||||||
if not name in task_deps:
|
if not name in task_deps:
|
||||||
task_deps[name] = {}
|
task_deps[name] = {}
|
||||||
@@ -375,6 +428,7 @@ def add_tasks(tasklist, d):
|
|||||||
getTask('rdeptask')
|
getTask('rdeptask')
|
||||||
getTask('recrdeptask')
|
getTask('recrdeptask')
|
||||||
getTask('nostamp')
|
getTask('nostamp')
|
||||||
|
getTask('fakeroot')
|
||||||
task_deps['parents'][task] = []
|
task_deps['parents'][task] = []
|
||||||
for dep in flags['deps']:
|
for dep in flags['deps']:
|
||||||
dep = data.expand(dep, d)
|
dep = data.expand(dep, d)
|
||||||
@@ -389,4 +443,3 @@ def remove_task(task, kill, d):
|
|||||||
If kill is 1, also remove tasks that depend on this task."""
|
If kill is 1, also remove tasks that depend on this task."""
|
||||||
|
|
||||||
data.delVarFlag(task, 'task', d)
|
data.delVarFlag(task, 'task', d)
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
|
||||||
import os, re
|
import os
|
||||||
import bb.data
|
import bb.data
|
||||||
import bb.utils
|
import bb.utils
|
||||||
|
|
||||||
@@ -38,16 +38,16 @@ except ImportError:
|
|||||||
import pickle
|
import pickle
|
||||||
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
|
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
|
||||||
|
|
||||||
__cache_version__ = "131"
|
__cache_version__ = "132"
|
||||||
|
|
||||||
class Cache:
|
class Cache:
|
||||||
"""
|
"""
|
||||||
BitBake Cache implementation
|
BitBake Cache implementation
|
||||||
"""
|
"""
|
||||||
def __init__(self, cooker):
|
def __init__(self, data):
|
||||||
|
|
||||||
|
|
||||||
self.cachedir = bb.data.getVar("CACHE", cooker.configuration.data, True)
|
self.cachedir = bb.data.getVar("CACHE", data, True)
|
||||||
self.clean = {}
|
self.clean = {}
|
||||||
self.checked = {}
|
self.checked = {}
|
||||||
self.depends_cache = {}
|
self.depends_cache = {}
|
||||||
@@ -61,30 +61,28 @@ class Cache:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.has_cache = True
|
self.has_cache = True
|
||||||
self.cachefile = os.path.join(self.cachedir,"bb_cache.dat")
|
self.cachefile = os.path.join(self.cachedir, "bb_cache.dat")
|
||||||
|
|
||||||
bb.msg.debug(1, bb.msg.domain.Cache, "Using cache in '%s'" % self.cachedir)
|
bb.msg.debug(1, bb.msg.domain.Cache, "Using cache in '%s'" % self.cachedir)
|
||||||
try:
|
bb.utils.mkdirhier(self.cachedir)
|
||||||
os.stat( self.cachedir )
|
|
||||||
except OSError:
|
|
||||||
bb.mkdirhier( self.cachedir )
|
|
||||||
|
|
||||||
# If any of configuration.data's dependencies are newer than the
|
# If any of configuration.data's dependencies are newer than the
|
||||||
# cache there isn't even any point in loading it...
|
# cache there isn't even any point in loading it...
|
||||||
newest_mtime = 0
|
newest_mtime = 0
|
||||||
deps = bb.data.getVar("__depends", cooker.configuration.data, True)
|
deps = bb.data.getVar("__depends", data)
|
||||||
for f,old_mtime in deps:
|
|
||||||
if old_mtime > newest_mtime:
|
old_mtimes = [old_mtime for f, old_mtime in deps]
|
||||||
newest_mtime = old_mtime
|
old_mtimes.append(newest_mtime)
|
||||||
|
newest_mtime = max(old_mtimes)
|
||||||
|
|
||||||
if bb.parse.cached_mtime_noerror(self.cachefile) >= newest_mtime:
|
if bb.parse.cached_mtime_noerror(self.cachefile) >= newest_mtime:
|
||||||
try:
|
try:
|
||||||
p = pickle.Unpickler(file(self.cachefile, "rb"))
|
p = pickle.Unpickler(file(self.cachefile, "rb"))
|
||||||
self.depends_cache, version_data = p.load()
|
self.depends_cache, version_data = p.load()
|
||||||
if version_data['CACHE_VER'] != __cache_version__:
|
if version_data['CACHE_VER'] != __cache_version__:
|
||||||
raise ValueError, 'Cache Version Mismatch'
|
raise ValueError('Cache Version Mismatch')
|
||||||
if version_data['BITBAKE_VER'] != bb.__version__:
|
if version_data['BITBAKE_VER'] != bb.__version__:
|
||||||
raise ValueError, 'Bitbake Version Mismatch'
|
raise ValueError('Bitbake Version Mismatch')
|
||||||
except EOFError:
|
except EOFError:
|
||||||
bb.msg.note(1, bb.msg.domain.Cache, "Truncated cache found, rebuilding...")
|
bb.msg.note(1, bb.msg.domain.Cache, "Truncated cache found, rebuilding...")
|
||||||
self.depends_cache = {}
|
self.depends_cache = {}
|
||||||
@@ -92,27 +90,23 @@ class Cache:
|
|||||||
bb.msg.note(1, bb.msg.domain.Cache, "Invalid cache found, rebuilding...")
|
bb.msg.note(1, bb.msg.domain.Cache, "Invalid cache found, rebuilding...")
|
||||||
self.depends_cache = {}
|
self.depends_cache = {}
|
||||||
else:
|
else:
|
||||||
try:
|
if os.path.isfile(self.cachefile):
|
||||||
os.stat( self.cachefile )
|
|
||||||
bb.msg.note(1, bb.msg.domain.Cache, "Out of date cache found, rebuilding...")
|
bb.msg.note(1, bb.msg.domain.Cache, "Out of date cache found, rebuilding...")
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def getVar(self, var, fn, exp = 0):
|
def getVar(self, var, fn, exp = 0):
|
||||||
"""
|
"""
|
||||||
Gets the value of a variable
|
Gets the value of a variable
|
||||||
(similar to getVar in the data class)
|
(similar to getVar in the data class)
|
||||||
|
|
||||||
There are two scenarios:
|
There are two scenarios:
|
||||||
1. We have cached data - serve from depends_cache[fn]
|
1. We have cached data - serve from depends_cache[fn]
|
||||||
2. We're learning what data to cache - serve from data
|
2. We're learning what data to cache - serve from data
|
||||||
backend but add a copy of the data to the cache.
|
backend but add a copy of the data to the cache.
|
||||||
"""
|
"""
|
||||||
if fn in self.clean:
|
if fn in self.clean:
|
||||||
return self.depends_cache[fn][var]
|
return self.depends_cache[fn][var]
|
||||||
|
|
||||||
if not fn in self.depends_cache:
|
self.depends_cache.setdefault(fn, {})
|
||||||
self.depends_cache[fn] = {}
|
|
||||||
|
|
||||||
if fn != self.data_fn:
|
if fn != self.data_fn:
|
||||||
# We're trying to access data in the cache which doesn't exist
|
# We're trying to access data in the cache which doesn't exist
|
||||||
@@ -134,14 +128,14 @@ class Cache:
|
|||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
# Make sure __depends makes the depends_cache
|
# Make sure __depends makes the depends_cache
|
||||||
# If we're a virtual class we need to make sure all our depends are appended
|
# If we're a virtual class we need to make sure all our depends are appended
|
||||||
# to the depends of fn.
|
# to the depends of fn.
|
||||||
depends = self.getVar("__depends", virtualfn, True) or []
|
depends = self.getVar("__depends", virtualfn) or set()
|
||||||
|
self.depends_cache.setdefault(fn, {})
|
||||||
if "__depends" not in self.depends_cache[fn] or not self.depends_cache[fn]["__depends"]:
|
if "__depends" not in self.depends_cache[fn] or not self.depends_cache[fn]["__depends"]:
|
||||||
self.depends_cache[fn]["__depends"] = depends
|
self.depends_cache[fn]["__depends"] = depends
|
||||||
for dep in depends:
|
else:
|
||||||
if dep not in self.depends_cache[fn]["__depends"]:
|
self.depends_cache[fn]["__depends"].update(depends)
|
||||||
self.depends_cache[fn]["__depends"].append(dep)
|
|
||||||
|
|
||||||
# Make sure the variants always make it into the cache too
|
# Make sure the variants always make it into the cache too
|
||||||
self.getVar('__VARIANTS', virtualfn, True)
|
self.getVar('__VARIANTS', virtualfn, True)
|
||||||
@@ -171,7 +165,7 @@ class Cache:
|
|||||||
#bb.msg.debug(2, bb.msg.domain.Cache, "realfn2virtual %s and %s to %s" % (realfn, cls, "virtual:" + cls + ":" + realfn))
|
#bb.msg.debug(2, bb.msg.domain.Cache, "realfn2virtual %s and %s to %s" % (realfn, cls, "virtual:" + cls + ":" + realfn))
|
||||||
return "virtual:" + cls + ":" + realfn
|
return "virtual:" + cls + ":" + realfn
|
||||||
|
|
||||||
def loadDataFull(self, virtualfn, cfgData):
|
def loadDataFull(self, virtualfn, appends, cfgData):
|
||||||
"""
|
"""
|
||||||
Return a complete set of data for fn.
|
Return a complete set of data for fn.
|
||||||
To do this, we need to parse the file.
|
To do this, we need to parse the file.
|
||||||
@@ -181,10 +175,10 @@ class Cache:
|
|||||||
|
|
||||||
bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s (full)" % fn)
|
bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s (full)" % fn)
|
||||||
|
|
||||||
bb_data = self.load_bbfile(fn, cfgData)
|
bb_data = self.load_bbfile(fn, appends, cfgData)
|
||||||
return bb_data[cls]
|
return bb_data[cls]
|
||||||
|
|
||||||
def loadData(self, fn, cfgData, cacheData):
|
def loadData(self, fn, appends, cfgData, cacheData):
|
||||||
"""
|
"""
|
||||||
Load a subset of data for fn.
|
Load a subset of data for fn.
|
||||||
If the cached data is valid we do nothing,
|
If the cached data is valid we do nothing,
|
||||||
@@ -212,12 +206,12 @@ class Cache:
|
|||||||
|
|
||||||
bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s" % fn)
|
bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s" % fn)
|
||||||
|
|
||||||
bb_data = self.load_bbfile(fn, cfgData)
|
bb_data = self.load_bbfile(fn, appends, cfgData)
|
||||||
|
|
||||||
for data in bb_data:
|
for data in bb_data:
|
||||||
virtualfn = self.realfn2virtual(fn, data)
|
virtualfn = self.realfn2virtual(fn, data)
|
||||||
self.setData(virtualfn, fn, bb_data[data])
|
self.setData(virtualfn, fn, bb_data[data])
|
||||||
if self.getVar("__SKIPPED", virtualfn, True):
|
if self.getVar("__SKIPPED", virtualfn):
|
||||||
skipped += 1
|
skipped += 1
|
||||||
bb.msg.debug(1, bb.msg.domain.Cache, "Skipping %s" % virtualfn)
|
bb.msg.debug(1, bb.msg.domain.Cache, "Skipping %s" % virtualfn)
|
||||||
else:
|
else:
|
||||||
@@ -258,11 +252,11 @@ class Cache:
|
|||||||
self.remove(fn)
|
self.remove(fn)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
mtime = bb.parse.cached_mtime_noerror(fn)
|
mtime = bb.parse.cached_mtime_noerror(fn)
|
||||||
|
|
||||||
# Check file still exists
|
# Check file still exists
|
||||||
if mtime == 0:
|
if mtime == 0:
|
||||||
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s not longer exists" % fn)
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s no longer exists" % fn)
|
||||||
self.remove(fn)
|
self.remove(fn)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -275,7 +269,7 @@ class Cache:
|
|||||||
# Check dependencies are still valid
|
# Check dependencies are still valid
|
||||||
depends = self.getVar("__depends", fn, True)
|
depends = self.getVar("__depends", fn, True)
|
||||||
if depends:
|
if depends:
|
||||||
for f,old_mtime in depends:
|
for f, old_mtime in depends:
|
||||||
fmtime = bb.parse.cached_mtime_noerror(f)
|
fmtime = bb.parse.cached_mtime_noerror(f)
|
||||||
# Check if file still exists
|
# Check if file still exists
|
||||||
if old_mtime != 0 and fmtime == 0:
|
if old_mtime != 0 and fmtime == 0:
|
||||||
@@ -291,11 +285,25 @@ class Cache:
|
|||||||
if not fn in self.clean:
|
if not fn in self.clean:
|
||||||
self.clean[fn] = ""
|
self.clean[fn] = ""
|
||||||
|
|
||||||
|
invalid = False
|
||||||
# Mark extended class data as clean too
|
# Mark extended class data as clean too
|
||||||
multi = self.getVar('__VARIANTS', fn, True)
|
multi = self.getVar('__VARIANTS', fn, True)
|
||||||
for cls in (multi or "").split():
|
for cls in (multi or "").split():
|
||||||
virtualfn = self.realfn2virtual(fn, cls)
|
virtualfn = self.realfn2virtual(fn, cls)
|
||||||
self.clean[virtualfn] = ""
|
self.clean[virtualfn] = ""
|
||||||
|
if not virtualfn in self.depends_cache:
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s is not cached" % virtualfn)
|
||||||
|
invalid = True
|
||||||
|
|
||||||
|
# If any one of the varients is not present, mark cache as invalid for all
|
||||||
|
if invalid:
|
||||||
|
for cls in (multi or "").split():
|
||||||
|
virtualfn = self.realfn2virtual(fn, cls)
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: Removing %s from cache" % virtualfn)
|
||||||
|
del self.clean[virtualfn]
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: Removing %s from cache" % fn)
|
||||||
|
del self.clean[fn]
|
||||||
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -345,14 +353,14 @@ class Cache:
|
|||||||
|
|
||||||
def handle_data(self, file_name, cacheData):
|
def handle_data(self, file_name, cacheData):
|
||||||
"""
|
"""
|
||||||
Save data we need into the cache
|
Save data we need into the cache
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pn = self.getVar('PN', file_name, True)
|
pn = self.getVar('PN', file_name, True)
|
||||||
pe = self.getVar('PE', file_name, True) or "0"
|
pe = self.getVar('PE', file_name, True) or "0"
|
||||||
pv = self.getVar('PV', file_name, True)
|
pv = self.getVar('PV', file_name, True)
|
||||||
if 'SRCREVINACTION' in pv:
|
if 'SRCREVINACTION' in pv:
|
||||||
bb.note("Found SRCREVINACTION in PV (%s) or %s. Please report this bug." % (pv, file_name))
|
bb.msg.note(1, bb.msg.domain.Cache, "Found SRCREVINACTION in PV (%s) or %s. Please report this bug." % (pv, file_name))
|
||||||
pr = self.getVar('PR', file_name, True)
|
pr = self.getVar('PR', file_name, True)
|
||||||
dp = int(self.getVar('DEFAULT_PREFERENCE', file_name, True) or "0")
|
dp = int(self.getVar('DEFAULT_PREFERENCE', file_name, True) or "0")
|
||||||
depends = bb.utils.explode_deps(self.getVar("DEPENDS", file_name, True) or "")
|
depends = bb.utils.explode_deps(self.getVar("DEPENDS", file_name, True) or "")
|
||||||
@@ -360,7 +368,7 @@ class Cache:
|
|||||||
packages_dynamic = (self.getVar('PACKAGES_DYNAMIC', file_name, True) or "").split()
|
packages_dynamic = (self.getVar('PACKAGES_DYNAMIC', file_name, True) or "").split()
|
||||||
rprovides = (self.getVar("RPROVIDES", file_name, True) or "").split()
|
rprovides = (self.getVar("RPROVIDES", file_name, True) or "").split()
|
||||||
|
|
||||||
cacheData.task_deps[file_name] = self.getVar("_task_deps", file_name, True)
|
cacheData.task_deps[file_name] = self.getVar("_task_deps", file_name)
|
||||||
|
|
||||||
# build PackageName to FileName lookup table
|
# build PackageName to FileName lookup table
|
||||||
if pn not in cacheData.pkg_pn:
|
if pn not in cacheData.pkg_pn:
|
||||||
@@ -369,9 +377,13 @@ class Cache:
|
|||||||
|
|
||||||
cacheData.stamp[file_name] = self.getVar('STAMP', file_name, True)
|
cacheData.stamp[file_name] = self.getVar('STAMP', file_name, True)
|
||||||
|
|
||||||
|
cacheData.tasks[file_name] = self.getVar('__BBTASKS', file_name, True)
|
||||||
|
for t in cacheData.tasks[file_name]:
|
||||||
|
cacheData.basetaskhash[file_name + "." + t] = self.getVar("BB_BASEHASH_task-%s" % t, file_name, True)
|
||||||
|
|
||||||
# build FileName to PackageName lookup table
|
# build FileName to PackageName lookup table
|
||||||
cacheData.pkg_fn[file_name] = pn
|
cacheData.pkg_fn[file_name] = pn
|
||||||
cacheData.pkg_pepvpr[file_name] = (pe,pv,pr)
|
cacheData.pkg_pepvpr[file_name] = (pe, pv, pr)
|
||||||
cacheData.pkg_dp[file_name] = dp
|
cacheData.pkg_dp[file_name] = dp
|
||||||
|
|
||||||
provides = [pn]
|
provides = [pn]
|
||||||
@@ -400,13 +412,13 @@ class Cache:
|
|||||||
if not dep in cacheData.all_depends:
|
if not dep in cacheData.all_depends:
|
||||||
cacheData.all_depends.append(dep)
|
cacheData.all_depends.append(dep)
|
||||||
|
|
||||||
# Build reverse hash for PACKAGES, so runtime dependencies
|
# Build reverse hash for PACKAGES, so runtime dependencies
|
||||||
# can be be resolved (RDEPENDS, RRECOMMENDS etc.)
|
# can be be resolved (RDEPENDS, RRECOMMENDS etc.)
|
||||||
for package in packages:
|
for package in packages:
|
||||||
if not package in cacheData.packages:
|
if not package in cacheData.packages:
|
||||||
cacheData.packages[package] = []
|
cacheData.packages[package] = []
|
||||||
cacheData.packages[package].append(file_name)
|
cacheData.packages[package].append(file_name)
|
||||||
rprovides += (self.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split()
|
rprovides += (self.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split()
|
||||||
|
|
||||||
for package in packages_dynamic:
|
for package in packages_dynamic:
|
||||||
if not package in cacheData.packages_dynamic:
|
if not package in cacheData.packages_dynamic:
|
||||||
@@ -441,42 +453,53 @@ class Cache:
|
|||||||
if not self.getVar('BROKEN', file_name, True) and not self.getVar('EXCLUDE_FROM_WORLD', file_name, True):
|
if not self.getVar('BROKEN', file_name, True) and not self.getVar('EXCLUDE_FROM_WORLD', file_name, True):
|
||||||
cacheData.possible_world.append(file_name)
|
cacheData.possible_world.append(file_name)
|
||||||
|
|
||||||
|
cacheData.hashfn[file_name] = self.getVar('BB_HASHFILENAME', file_name, True)
|
||||||
|
|
||||||
# Touch this to make sure its in the cache
|
# Touch this to make sure its in the cache
|
||||||
self.getVar('__BB_DONT_CACHE', file_name, True)
|
self.getVar('__BB_DONT_CACHE', file_name, True)
|
||||||
self.getVar('__VARIANTS', file_name, True)
|
self.getVar('__VARIANTS', file_name, True)
|
||||||
|
|
||||||
def load_bbfile( self, bbfile , config):
|
def load_bbfile(self, bbfile, appends, config):
|
||||||
"""
|
"""
|
||||||
Load and parse one .bb build file
|
Load and parse one .bb build file
|
||||||
Return the data and whether parsing resulted in the file being skipped
|
Return the data and whether parsing resulted in the file being skipped
|
||||||
"""
|
"""
|
||||||
|
chdir_back = False
|
||||||
|
|
||||||
import bb
|
from bb import data, parse
|
||||||
from bb import utils, data, parse, debug, event, fatal
|
|
||||||
|
|
||||||
# expand tmpdir to include this topdir
|
# expand tmpdir to include this topdir
|
||||||
data.setVar('TMPDIR', data.getVar('TMPDIR', config, 1) or "", config)
|
data.setVar('TMPDIR', data.getVar('TMPDIR', config, 1) or "", config)
|
||||||
bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
|
bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
|
||||||
oldpath = os.path.abspath(os.getcwd())
|
oldpath = os.path.abspath(os.getcwd())
|
||||||
if bb.parse.cached_mtime_noerror(bbfile_loc):
|
parse.cached_mtime_noerror(bbfile_loc)
|
||||||
os.chdir(bbfile_loc)
|
|
||||||
bb_data = data.init_db(config)
|
bb_data = data.init_db(config)
|
||||||
|
# The ConfHandler first looks if there is a TOPDIR and if not
|
||||||
|
# then it would call getcwd().
|
||||||
|
# Previously, we chdir()ed to bbfile_loc, called the handler
|
||||||
|
# and finally chdir()ed back, a couple of thousand times. We now
|
||||||
|
# just fill in TOPDIR to point to bbfile_loc if there is no TOPDIR yet.
|
||||||
|
if not data.getVar('TOPDIR', bb_data):
|
||||||
|
chdir_back = True
|
||||||
|
data.setVar('TOPDIR', bbfile_loc, bb_data)
|
||||||
try:
|
try:
|
||||||
|
if appends:
|
||||||
|
data.setVar('__BBAPPEND', " ".join(appends), bb_data)
|
||||||
bb_data = parse.handle(bbfile, bb_data) # read .bb data
|
bb_data = parse.handle(bbfile, bb_data) # read .bb data
|
||||||
os.chdir(oldpath)
|
if chdir_back: os.chdir(oldpath)
|
||||||
return bb_data
|
return bb_data
|
||||||
except:
|
except:
|
||||||
os.chdir(oldpath)
|
if chdir_back: os.chdir(oldpath)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def init(cooker):
|
def init(cooker):
|
||||||
"""
|
"""
|
||||||
The Objective: Cache the minimum amount of data possible yet get to the
|
The Objective: Cache the minimum amount of data possible yet get to the
|
||||||
stage of building packages (i.e. tryBuild) without reparsing any .bb files.
|
stage of building packages (i.e. tryBuild) without reparsing any .bb files.
|
||||||
|
|
||||||
To do this, we intercept getVar calls and only cache the variables we see
|
To do this, we intercept getVar calls and only cache the variables we see
|
||||||
being accessed. We rely on the cache getVar calls being made for all
|
being accessed. We rely on the cache getVar calls being made for all
|
||||||
variables bitbake might need to use to reach this stage. For each cached
|
variables bitbake might need to use to reach this stage. For each cached
|
||||||
file we need to track:
|
file we need to track:
|
||||||
|
|
||||||
* Its mtime
|
* Its mtime
|
||||||
@@ -486,7 +509,7 @@ def init(cooker):
|
|||||||
Files causing parsing errors are evicted from the cache.
|
Files causing parsing errors are evicted from the cache.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return Cache(cooker)
|
return Cache(cooker.configuration.data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -522,6 +545,9 @@ class CacheData:
|
|||||||
self.task_deps = {}
|
self.task_deps = {}
|
||||||
self.stamp = {}
|
self.stamp = {}
|
||||||
self.preferred = {}
|
self.preferred = {}
|
||||||
|
self.tasks = {}
|
||||||
|
self.basetaskhash = {}
|
||||||
|
self.hashfn = {}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Indirect Cache variables
|
Indirect Cache variables
|
||||||
|
|||||||
329
bitbake/lib/bb/codeparser.py
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
from pysh import pyshyacc, pyshlex
|
||||||
|
from itertools import chain
|
||||||
|
from bb import msg, utils
|
||||||
|
import ast
|
||||||
|
import codegen
|
||||||
|
|
||||||
|
PARSERCACHE_VERSION = 2
|
||||||
|
|
||||||
|
try:
|
||||||
|
import cPickle as pickle
|
||||||
|
except ImportError:
|
||||||
|
import pickle
|
||||||
|
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
|
||||||
|
|
||||||
|
def check_indent(codestr):
|
||||||
|
"""If the code is indented, add a top level piece of code to 'remove' the indentation"""
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while codestr[i] in ["\n", " ", " "]:
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
if i == 0:
|
||||||
|
return codestr
|
||||||
|
|
||||||
|
if codestr[i-1] is " " or codestr[i-1] is " ":
|
||||||
|
return "if 1:\n" + codestr
|
||||||
|
|
||||||
|
return codestr
|
||||||
|
|
||||||
|
pythonparsecache = {}
|
||||||
|
shellparsecache = {}
|
||||||
|
|
||||||
|
def parser_cachefile(d):
|
||||||
|
cachedir = bb.data.getVar("PERSISTENT_DIR", d, True) or bb.data.getVar("CACHE", d, True)
|
||||||
|
if cachedir in [None, '']:
|
||||||
|
return None
|
||||||
|
bb.utils.mkdirhier(cachedir)
|
||||||
|
cachefile = os.path.join(cachedir, "bb_codeparser.dat")
|
||||||
|
bb.msg.debug(1, bb.msg.domain.Cache, "Using cache in '%s' for codeparser cache" % cachefile)
|
||||||
|
return cachefile
|
||||||
|
|
||||||
|
def parser_cache_init(d):
|
||||||
|
|
||||||
|
cachefile = parser_cachefile(d)
|
||||||
|
if not cachefile:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
p = pickle.Unpickler(file(cachefile, "rb"))
|
||||||
|
data, version = p.load()
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
if version != PARSERCACHE_VERSION:
|
||||||
|
return
|
||||||
|
|
||||||
|
bb.codeparser.pythonparsecache = data[0]
|
||||||
|
bb.codeparser.shellparsecache = data[1]
|
||||||
|
|
||||||
|
def parser_cache_save(d):
|
||||||
|
|
||||||
|
cachefile = parser_cachefile(d)
|
||||||
|
if not cachefile:
|
||||||
|
return
|
||||||
|
|
||||||
|
p = pickle.Pickler(file(cachefile, "wb"), -1)
|
||||||
|
p.dump([[bb.codeparser.pythonparsecache, bb.codeparser.shellparsecache], PARSERCACHE_VERSION])
|
||||||
|
|
||||||
|
class PythonParser():
|
||||||
|
class ValueVisitor():
|
||||||
|
"""Visitor to traverse a python abstract syntax tree and obtain
|
||||||
|
the variables referenced via bitbake metadata APIs, and the external
|
||||||
|
functions called.
|
||||||
|
"""
|
||||||
|
|
||||||
|
getvars = ("d.getVar", "bb.data.getVar", "data.getVar")
|
||||||
|
expands = ("d.expand", "bb.data.expand", "data.expand")
|
||||||
|
execs = ("bb.build.exec_func", "bb.build.exec_task")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _compare_name(cls, strparts, node):
|
||||||
|
"""Given a sequence of strings representing a python name,
|
||||||
|
where the last component is the actual Name and the prior
|
||||||
|
elements are Attribute nodes, determine if the supplied node
|
||||||
|
matches.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not strparts:
|
||||||
|
return True
|
||||||
|
|
||||||
|
current, rest = strparts[0], strparts[1:]
|
||||||
|
if isinstance(node, ast.Attribute):
|
||||||
|
if current == node.attr:
|
||||||
|
return cls._compare_name(rest, node.value)
|
||||||
|
elif isinstance(node, ast.Name):
|
||||||
|
if current == node.id:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def compare_name(cls, value, node):
|
||||||
|
"""Convenience function for the _compare_node method, which
|
||||||
|
can accept a string (which is split by '.' for you), or an
|
||||||
|
iterable of strings, in which case it checks to see if any of
|
||||||
|
them match, similar to isinstance.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if isinstance(value, basestring):
|
||||||
|
return cls._compare_name(tuple(reversed(value.split("."))),
|
||||||
|
node)
|
||||||
|
else:
|
||||||
|
return any(cls.compare_name(item, node) for item in value)
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
self.var_references = set()
|
||||||
|
self.var_execs = set()
|
||||||
|
self.direct_func_calls = set()
|
||||||
|
self.var_expands = set()
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def warn(cls, func, arg):
|
||||||
|
"""Warn about calls of bitbake APIs which pass a non-literal
|
||||||
|
argument for the variable name, as we're not able to track such
|
||||||
|
a reference.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
funcstr = codegen.to_source(func)
|
||||||
|
argstr = codegen.to_source(arg)
|
||||||
|
except TypeError:
|
||||||
|
msg.debug(2, None, "Failed to convert function and argument to source form")
|
||||||
|
else:
|
||||||
|
msg.debug(1, None, "Warning: in call to '%s', argument '%s' is not a literal" %
|
||||||
|
(funcstr, argstr))
|
||||||
|
|
||||||
|
def visit_Call(self, node):
|
||||||
|
if self.compare_name(self.getvars, node.func):
|
||||||
|
if isinstance(node.args[0], ast.Str):
|
||||||
|
self.var_references.add(node.args[0].s)
|
||||||
|
else:
|
||||||
|
self.warn(node.func, node.args[0])
|
||||||
|
elif self.compare_name(self.expands, node.func):
|
||||||
|
if isinstance(node.args[0], ast.Str):
|
||||||
|
self.warn(node.func, node.args[0])
|
||||||
|
self.var_expands.update(node.args[0].s)
|
||||||
|
elif isinstance(node.args[0], ast.Call) and \
|
||||||
|
self.compare_name(self.getvars, node.args[0].func):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.warn(node.func, node.args[0])
|
||||||
|
elif self.compare_name(self.execs, node.func):
|
||||||
|
if isinstance(node.args[0], ast.Str):
|
||||||
|
self.var_execs.add(node.args[0].s)
|
||||||
|
else:
|
||||||
|
self.warn(node.func, node.args[0])
|
||||||
|
elif isinstance(node.func, ast.Name):
|
||||||
|
self.direct_func_calls.add(node.func.id)
|
||||||
|
elif isinstance(node.func, ast.Attribute):
|
||||||
|
# We must have a qualified name. Therefore we need
|
||||||
|
# to walk the chain of 'Attribute' nodes to determine
|
||||||
|
# the qualification.
|
||||||
|
attr_node = node.func.value
|
||||||
|
identifier = node.func.attr
|
||||||
|
while isinstance(attr_node, ast.Attribute):
|
||||||
|
identifier = attr_node.attr + "." + identifier
|
||||||
|
attr_node = attr_node.value
|
||||||
|
if isinstance(attr_node, ast.Name):
|
||||||
|
identifier = attr_node.id + "." + identifier
|
||||||
|
self.direct_func_calls.add(identifier)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
#self.funcdefs = set()
|
||||||
|
self.execs = set()
|
||||||
|
#self.external_cmds = set()
|
||||||
|
self.references = set()
|
||||||
|
|
||||||
|
def parse_python(self, node):
|
||||||
|
|
||||||
|
h = hash(str(node))
|
||||||
|
|
||||||
|
if h in pythonparsecache:
|
||||||
|
self.references = pythonparsecache[h]["refs"]
|
||||||
|
self.execs = pythonparsecache[h]["execs"]
|
||||||
|
return
|
||||||
|
|
||||||
|
code = compile(check_indent(str(node)), "<string>", "exec",
|
||||||
|
ast.PyCF_ONLY_AST)
|
||||||
|
|
||||||
|
visitor = self.ValueVisitor(code)
|
||||||
|
for n in ast.walk(code):
|
||||||
|
if n.__class__.__name__ == "Call":
|
||||||
|
visitor.visit_Call(n)
|
||||||
|
|
||||||
|
self.references.update(visitor.var_references)
|
||||||
|
self.references.update(visitor.var_execs)
|
||||||
|
self.execs = visitor.direct_func_calls
|
||||||
|
|
||||||
|
pythonparsecache[h] = {}
|
||||||
|
pythonparsecache[h]["refs"] = self.references
|
||||||
|
pythonparsecache[h]["execs"] = self.execs
|
||||||
|
|
||||||
|
class ShellParser():
|
||||||
|
def __init__(self):
|
||||||
|
self.funcdefs = set()
|
||||||
|
self.allexecs = set()
|
||||||
|
self.execs = set()
|
||||||
|
|
||||||
|
def parse_shell(self, value):
|
||||||
|
"""Parse the supplied shell code in a string, returning the external
|
||||||
|
commands it executes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
h = hash(str(value))
|
||||||
|
|
||||||
|
if h in shellparsecache:
|
||||||
|
self.execs = shellparsecache[h]["execs"]
|
||||||
|
return self.execs
|
||||||
|
|
||||||
|
try:
|
||||||
|
tokens, _ = pyshyacc.parse(value, eof=True, debug=False)
|
||||||
|
except pyshlex.NeedMore:
|
||||||
|
raise ShellSyntaxError("Unexpected EOF")
|
||||||
|
|
||||||
|
for token in tokens:
|
||||||
|
self.process_tokens(token)
|
||||||
|
self.execs = set(cmd for cmd in self.allexecs if cmd not in self.funcdefs)
|
||||||
|
|
||||||
|
shellparsecache[h] = {}
|
||||||
|
shellparsecache[h]["execs"] = self.execs
|
||||||
|
|
||||||
|
return self.execs
|
||||||
|
|
||||||
|
def process_tokens(self, tokens):
|
||||||
|
"""Process a supplied portion of the syntax tree as returned by
|
||||||
|
pyshyacc.parse.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def function_definition(value):
|
||||||
|
self.funcdefs.add(value.name)
|
||||||
|
return [value.body], None
|
||||||
|
|
||||||
|
def case_clause(value):
|
||||||
|
# Element 0 of each item in the case is the list of patterns, and
|
||||||
|
# Element 1 of each item in the case is the list of commands to be
|
||||||
|
# executed when that pattern matches.
|
||||||
|
words = chain(*[item[0] for item in value.items])
|
||||||
|
cmds = chain(*[item[1] for item in value.items])
|
||||||
|
return cmds, words
|
||||||
|
|
||||||
|
def if_clause(value):
|
||||||
|
main = chain(value.cond, value.if_cmds)
|
||||||
|
rest = value.else_cmds
|
||||||
|
if isinstance(rest, tuple) and rest[0] == "elif":
|
||||||
|
return chain(main, if_clause(rest[1]))
|
||||||
|
else:
|
||||||
|
return chain(main, rest)
|
||||||
|
|
||||||
|
def simple_command(value):
|
||||||
|
return None, chain(value.words, (assign[1] for assign in value.assigns))
|
||||||
|
|
||||||
|
token_handlers = {
|
||||||
|
"and_or": lambda x: ((x.left, x.right), None),
|
||||||
|
"async": lambda x: ([x], None),
|
||||||
|
"brace_group": lambda x: (x.cmds, None),
|
||||||
|
"for_clause": lambda x: (x.cmds, x.items),
|
||||||
|
"function_definition": function_definition,
|
||||||
|
"if_clause": lambda x: (if_clause(x), None),
|
||||||
|
"pipeline": lambda x: (x.commands, None),
|
||||||
|
"redirect_list": lambda x: ([x.cmd], None),
|
||||||
|
"subshell": lambda x: (x.cmds, None),
|
||||||
|
"while_clause": lambda x: (chain(x.condition, x.cmds), None),
|
||||||
|
"until_clause": lambda x: (chain(x.condition, x.cmds), None),
|
||||||
|
"simple_command": simple_command,
|
||||||
|
"case_clause": case_clause,
|
||||||
|
}
|
||||||
|
|
||||||
|
for token in tokens:
|
||||||
|
name, value = token
|
||||||
|
try:
|
||||||
|
more_tokens, words = token_handlers[name](value)
|
||||||
|
except KeyError:
|
||||||
|
raise NotImplementedError("Unsupported token type " + name)
|
||||||
|
|
||||||
|
if more_tokens:
|
||||||
|
self.process_tokens(more_tokens)
|
||||||
|
|
||||||
|
if words:
|
||||||
|
self.process_words(words)
|
||||||
|
|
||||||
|
def process_words(self, words):
|
||||||
|
"""Process a set of 'words' in pyshyacc parlance, which includes
|
||||||
|
extraction of executed commands from $() blocks, as well as grabbing
|
||||||
|
the command name argument.
|
||||||
|
"""
|
||||||
|
|
||||||
|
words = list(words)
|
||||||
|
for word in list(words):
|
||||||
|
wtree = pyshlex.make_wordtree(word[1])
|
||||||
|
for part in wtree:
|
||||||
|
if not isinstance(part, list):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if part[0] in ('`', '$('):
|
||||||
|
command = pyshlex.wordtree_as_string(part[1:-1])
|
||||||
|
self.parse_shell(command)
|
||||||
|
|
||||||
|
if word[0] in ("cmd_name", "cmd_word"):
|
||||||
|
if word in words:
|
||||||
|
words.remove(word)
|
||||||
|
|
||||||
|
usetoken = False
|
||||||
|
for word in words:
|
||||||
|
if word[0] in ("cmd_name", "cmd_word") or \
|
||||||
|
(usetoken and word[0] == "TOKEN"):
|
||||||
|
if "=" in word[1]:
|
||||||
|
usetoken = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
cmd = word[1]
|
||||||
|
if cmd.startswith("$"):
|
||||||
|
msg.debug(1, None, "Warning: execution of non-literal command '%s'" % cmd)
|
||||||
|
elif cmd == "eval":
|
||||||
|
command = " ".join(word for _, word in words[1:])
|
||||||
|
self.parse_shell(command)
|
||||||
|
else:
|
||||||
|
self.allexecs.add(cmd)
|
||||||
|
break
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ Provide an interface to interact with the bitbake server through 'commands'
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The bitbake server takes 'commands' from its UI/commandline.
|
The bitbake server takes 'commands' from its UI/commandline.
|
||||||
Commands are either synchronous or asynchronous.
|
Commands are either synchronous or asynchronous.
|
||||||
Async commands return data to the client in the form of events.
|
Async commands return data to the client in the form of events.
|
||||||
Sync commands must only return data through the function return value
|
Sync commands must only return data through the function return value
|
||||||
@@ -62,7 +62,7 @@ class Command:
|
|||||||
try:
|
try:
|
||||||
command = commandline.pop(0)
|
command = commandline.pop(0)
|
||||||
if command in CommandsSync.__dict__:
|
if command in CommandsSync.__dict__:
|
||||||
# Can run synchronous commands straight away
|
# Can run synchronous commands straight away
|
||||||
return getattr(CommandsSync, command)(self.cmds_sync, self, commandline)
|
return getattr(CommandsSync, command)(self.cmds_sync, self, commandline)
|
||||||
if self.currentAsyncCommand is not None:
|
if self.currentAsyncCommand is not None:
|
||||||
return "Busy (%s in progress)" % self.currentAsyncCommand[0]
|
return "Busy (%s in progress)" % self.currentAsyncCommand[0]
|
||||||
@@ -89,7 +89,17 @@ class Command:
|
|||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
except:
|
except KeyboardInterrupt as exc:
|
||||||
|
self.finishAsyncCommand("Interrupted")
|
||||||
|
return False
|
||||||
|
except SystemExit as exc:
|
||||||
|
arg = exc.args[0]
|
||||||
|
if isinstance(arg, basestring):
|
||||||
|
self.finishAsyncCommand(arg)
|
||||||
|
else:
|
||||||
|
self.finishAsyncCommand("Exited with %s" % arg)
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
import traceback
|
import traceback
|
||||||
self.finishAsyncCommand(traceback.format_exc())
|
self.finishAsyncCommand(traceback.format_exc())
|
||||||
return False
|
return False
|
||||||
@@ -268,6 +278,3 @@ class CookerCommandSetExitCode(bb.event.Event):
|
|||||||
def __init__(self, exitcode):
|
def __init__(self, exitcode):
|
||||||
bb.event.Event.__init__(self)
|
bb.event.Event.__init__(self)
|
||||||
self.exitcode = int(exitcode)
|
self.exitcode = int(exitcode)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,11 +22,13 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import sys, os, getopt, glob, copy, os.path, re, time
|
from __future__ import print_function
|
||||||
|
import sys, os, glob, os.path, re, time
|
||||||
|
import sre_constants
|
||||||
|
from cStringIO import StringIO
|
||||||
|
from contextlib import closing
|
||||||
import bb
|
import bb
|
||||||
from bb import utils, data, parse, event, cache, providers, taskdata, runqueue
|
from bb import utils, data, parse, event, cache, providers, taskdata, command, runqueue
|
||||||
from bb import command
|
|
||||||
import itertools, sre_constants
|
|
||||||
|
|
||||||
class MultipleMatches(Exception):
|
class MultipleMatches(Exception):
|
||||||
"""
|
"""
|
||||||
@@ -68,23 +70,16 @@ class BBCooker:
|
|||||||
self.cache = None
|
self.cache = None
|
||||||
self.bb_cache = None
|
self.bb_cache = None
|
||||||
|
|
||||||
self.server = server.BitBakeServer(self)
|
if server:
|
||||||
|
self.server = server.BitBakeServer(self)
|
||||||
|
|
||||||
self.configuration = configuration
|
self.configuration = configuration
|
||||||
|
|
||||||
if self.configuration.verbose:
|
|
||||||
bb.msg.set_verbose(True)
|
|
||||||
|
|
||||||
if self.configuration.debug:
|
|
||||||
bb.msg.set_debug_level(self.configuration.debug)
|
|
||||||
else:
|
|
||||||
bb.msg.set_debug_level(0)
|
|
||||||
|
|
||||||
if self.configuration.debug_domains:
|
|
||||||
bb.msg.set_debug_domains(self.configuration.debug_domains)
|
|
||||||
|
|
||||||
self.configuration.data = bb.data.init()
|
self.configuration.data = bb.data.init()
|
||||||
|
|
||||||
|
if not server:
|
||||||
|
bb.data.setVar("BB_WORKERCONTEXT", "1", self.configuration.data)
|
||||||
|
|
||||||
bb.data.inheritFromOS(self.configuration.data)
|
bb.data.inheritFromOS(self.configuration.data)
|
||||||
|
|
||||||
self.parseConfigurationFiles(self.configuration.file)
|
self.parseConfigurationFiles(self.configuration.file)
|
||||||
@@ -132,11 +127,11 @@ class BBCooker:
|
|||||||
self.commandlineAction = None
|
self.commandlineAction = None
|
||||||
|
|
||||||
if 'world' in self.configuration.pkgs_to_build:
|
if 'world' in self.configuration.pkgs_to_build:
|
||||||
bb.error("'world' is not a valid target for --environment.")
|
bb.msg.error(bb.msg.domain.Build, "'world' is not a valid target for --environment.")
|
||||||
elif len(self.configuration.pkgs_to_build) > 1:
|
elif len(self.configuration.pkgs_to_build) > 1:
|
||||||
bb.error("Only one target can be used with the --environment option.")
|
bb.msg.error(bb.msg.domain.Build, "Only one target can be used with the --environment option.")
|
||||||
elif self.configuration.buildfile and len(self.configuration.pkgs_to_build) > 0:
|
elif self.configuration.buildfile and len(self.configuration.pkgs_to_build) > 0:
|
||||||
bb.error("No target should be used with the --environment and --buildfile options.")
|
bb.msg.error(bb.msg.domain.Build, "No target should be used with the --environment and --buildfile options.")
|
||||||
elif len(self.configuration.pkgs_to_build) > 0:
|
elif len(self.configuration.pkgs_to_build) > 0:
|
||||||
self.commandlineAction = ["showEnvironmentTarget", self.configuration.pkgs_to_build]
|
self.commandlineAction = ["showEnvironmentTarget", self.configuration.pkgs_to_build]
|
||||||
else:
|
else:
|
||||||
@@ -149,21 +144,18 @@ class BBCooker:
|
|||||||
self.commandlineAction = ["showVersions"]
|
self.commandlineAction = ["showVersions"]
|
||||||
elif self.configuration.parse_only:
|
elif self.configuration.parse_only:
|
||||||
self.commandlineAction = ["parseFiles"]
|
self.commandlineAction = ["parseFiles"]
|
||||||
# FIXME - implement
|
|
||||||
#elif self.configuration.interactive:
|
|
||||||
# self.interactiveMode()
|
|
||||||
elif self.configuration.dot_graph:
|
elif self.configuration.dot_graph:
|
||||||
if self.configuration.pkgs_to_build:
|
if self.configuration.pkgs_to_build:
|
||||||
self.commandlineAction = ["generateDotGraph", self.configuration.pkgs_to_build, self.configuration.cmd]
|
self.commandlineAction = ["generateDotGraph", self.configuration.pkgs_to_build, self.configuration.cmd]
|
||||||
else:
|
else:
|
||||||
self.commandlineAction = None
|
self.commandlineAction = None
|
||||||
bb.error("Please specify a package name for dependency graph generation.")
|
bb.msg.error(bb.msg.domain.Build, "Please specify a package name for dependency graph generation.")
|
||||||
else:
|
else:
|
||||||
if self.configuration.pkgs_to_build:
|
if self.configuration.pkgs_to_build:
|
||||||
self.commandlineAction = ["buildTargets", self.configuration.pkgs_to_build, self.configuration.cmd]
|
self.commandlineAction = ["buildTargets", self.configuration.pkgs_to_build, self.configuration.cmd]
|
||||||
else:
|
else:
|
||||||
self.commandlineAction = None
|
self.commandlineAction = None
|
||||||
bb.error("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
|
bb.msg.error(bb.msg.domain.Build, "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
|
||||||
|
|
||||||
def runCommands(self, server, data, abort):
|
def runCommands(self, server, data, abort):
|
||||||
"""
|
"""
|
||||||
@@ -174,38 +166,6 @@ class BBCooker:
|
|||||||
|
|
||||||
return self.command.runAsyncCommand()
|
return self.command.runAsyncCommand()
|
||||||
|
|
||||||
def tryBuildPackage(self, fn, item, task, the_data):
|
|
||||||
"""
|
|
||||||
Build one task of a package, optionally build following task depends
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if not self.configuration.dry_run:
|
|
||||||
bb.build.exec_task('do_%s' % task, the_data)
|
|
||||||
return True
|
|
||||||
except bb.build.FuncFailed:
|
|
||||||
bb.msg.error(bb.msg.domain.Build, "task stack execution failed")
|
|
||||||
raise
|
|
||||||
except bb.build.EventException, e:
|
|
||||||
event = e.args[1]
|
|
||||||
bb.msg.error(bb.msg.domain.Build, "%s event exception, aborting" % bb.event.getName(event))
|
|
||||||
raise
|
|
||||||
|
|
||||||
def tryBuild(self, fn, task):
|
|
||||||
"""
|
|
||||||
Build a provider and its dependencies.
|
|
||||||
build_depends is a list of previous build dependencies (not runtime)
|
|
||||||
If build_depends is empty, we're dealing with a runtime depends
|
|
||||||
"""
|
|
||||||
|
|
||||||
the_data = self.bb_cache.loadDataFull(fn, self.configuration.data)
|
|
||||||
|
|
||||||
item = self.status.pkg_fn[fn]
|
|
||||||
|
|
||||||
#if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
|
|
||||||
# return True
|
|
||||||
|
|
||||||
return self.tryBuildPackage(fn, item, task, the_data)
|
|
||||||
|
|
||||||
def showVersions(self):
|
def showVersions(self):
|
||||||
|
|
||||||
# Need files parsed
|
# Need files parsed
|
||||||
@@ -217,7 +177,7 @@ class BBCooker:
|
|||||||
|
|
||||||
# Sort by priority
|
# Sort by priority
|
||||||
for pn in pkg_pn:
|
for pn in pkg_pn:
|
||||||
(last_ver,last_file,pref_ver,pref_file) = bb.providers.findBestProvider(pn, self.configuration.data, self.status)
|
(last_ver, last_file, pref_ver, pref_file) = bb.providers.findBestProvider(pn, self.configuration.data, self.status)
|
||||||
preferred_versions[pn] = (pref_ver, pref_file)
|
preferred_versions[pn] = (pref_ver, pref_file)
|
||||||
latest_versions[pn] = (last_ver, last_file)
|
latest_versions[pn] = (last_ver, last_file)
|
||||||
|
|
||||||
@@ -270,28 +230,23 @@ class BBCooker:
|
|||||||
|
|
||||||
if fn:
|
if fn:
|
||||||
try:
|
try:
|
||||||
envdata = self.bb_cache.loadDataFull(fn, self.configuration.data)
|
envdata = self.bb_cache.loadDataFull(fn, self.get_file_appends(fn), self.configuration.data)
|
||||||
except IOError, e:
|
except IOError as e:
|
||||||
bb.msg.error(bb.msg.domain.Parsing, "Unable to read %s: %s" % (fn, e))
|
bb.msg.error(bb.msg.domain.Parsing, "Unable to read %s: %s" % (fn, e))
|
||||||
raise
|
raise
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
bb.msg.error(bb.msg.domain.Parsing, "%s" % e)
|
bb.msg.error(bb.msg.domain.Parsing, "%s" % e)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
class dummywrite:
|
|
||||||
def __init__(self):
|
|
||||||
self.writebuf = ""
|
|
||||||
def write(self, output):
|
|
||||||
self.writebuf = self.writebuf + output
|
|
||||||
|
|
||||||
# emit variables and shell functions
|
# emit variables and shell functions
|
||||||
try:
|
try:
|
||||||
data.update_data(envdata)
|
data.update_data(envdata)
|
||||||
wb = dummywrite()
|
with closing(StringIO()) as env:
|
||||||
data.emit_env(wb, envdata, True)
|
data.emit_env(env, envdata, True)
|
||||||
bb.msg.plain(wb.writebuf)
|
bb.msg.plain(env.getvalue())
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
|
bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
|
||||||
|
|
||||||
# emit the metadata which isnt valid shell
|
# emit the metadata which isnt valid shell
|
||||||
data.expandKeys(envdata)
|
data.expandKeys(envdata)
|
||||||
for e in envdata.keys():
|
for e in envdata.keys():
|
||||||
@@ -324,9 +279,9 @@ class BBCooker:
|
|||||||
taskdata.add_unresolved(localdata, self.status)
|
taskdata.add_unresolved(localdata, self.status)
|
||||||
|
|
||||||
rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
|
rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
|
||||||
rq.prepare_runqueue()
|
rq.rqdata.prepare()
|
||||||
|
|
||||||
seen_fnids = []
|
seen_fnids = []
|
||||||
depend_tree = {}
|
depend_tree = {}
|
||||||
depend_tree["depends"] = {}
|
depend_tree["depends"] = {}
|
||||||
depend_tree["tdepends"] = {}
|
depend_tree["tdepends"] = {}
|
||||||
@@ -336,9 +291,9 @@ class BBCooker:
|
|||||||
depend_tree["rdepends-pkg"] = {}
|
depend_tree["rdepends-pkg"] = {}
|
||||||
depend_tree["rrecs-pkg"] = {}
|
depend_tree["rrecs-pkg"] = {}
|
||||||
|
|
||||||
for task in range(len(rq.runq_fnid)):
|
for task in range(len(rq.rqdata.runq_fnid)):
|
||||||
taskname = rq.runq_task[task]
|
taskname = rq.rqdata.runq_task[task]
|
||||||
fnid = rq.runq_fnid[task]
|
fnid = rq.rqdata.runq_fnid[task]
|
||||||
fn = taskdata.fn_index[fnid]
|
fn = taskdata.fn_index[fnid]
|
||||||
pn = self.status.pkg_fn[fn]
|
pn = self.status.pkg_fn[fn]
|
||||||
version = "%s:%s-%s" % self.status.pkg_pepvpr[fn]
|
version = "%s:%s-%s" % self.status.pkg_pepvpr[fn]
|
||||||
@@ -346,13 +301,13 @@ class BBCooker:
|
|||||||
depend_tree["pn"][pn] = {}
|
depend_tree["pn"][pn] = {}
|
||||||
depend_tree["pn"][pn]["filename"] = fn
|
depend_tree["pn"][pn]["filename"] = fn
|
||||||
depend_tree["pn"][pn]["version"] = version
|
depend_tree["pn"][pn]["version"] = version
|
||||||
for dep in rq.runq_depends[task]:
|
for dep in rq.rqdata.runq_depends[task]:
|
||||||
depfn = taskdata.fn_index[rq.runq_fnid[dep]]
|
depfn = taskdata.fn_index[rq.rqdata.runq_fnid[dep]]
|
||||||
deppn = self.status.pkg_fn[depfn]
|
deppn = self.status.pkg_fn[depfn]
|
||||||
dotname = "%s.%s" % (pn, rq.runq_task[task])
|
dotname = "%s.%s" % (pn, rq.rqdata.runq_task[task])
|
||||||
if not dotname in depend_tree["tdepends"]:
|
if not dotname in depend_tree["tdepends"]:
|
||||||
depend_tree["tdepends"][dotname] = []
|
depend_tree["tdepends"][dotname] = []
|
||||||
depend_tree["tdepends"][dotname].append("%s.%s" % (deppn, rq.runq_task[dep]))
|
depend_tree["tdepends"][dotname].append("%s.%s" % (deppn, rq.rqdata.runq_task[dep]))
|
||||||
if fnid not in seen_fnids:
|
if fnid not in seen_fnids:
|
||||||
seen_fnids.append(fnid)
|
seen_fnids.append(fnid)
|
||||||
packages = []
|
packages = []
|
||||||
@@ -363,7 +318,7 @@ class BBCooker:
|
|||||||
|
|
||||||
depend_tree["rdepends-pn"][pn] = []
|
depend_tree["rdepends-pn"][pn] = []
|
||||||
for rdep in taskdata.rdepids[fnid]:
|
for rdep in taskdata.rdepids[fnid]:
|
||||||
depend_tree["rdepends-pn"][pn].append(taskdata.run_names_index[rdep])
|
depend_tree["rdepends-pn"][pn].append(taskdata.run_names_index[rdep])
|
||||||
|
|
||||||
rdepends = self.status.rundeps[fn]
|
rdepends = self.status.rundeps[fn]
|
||||||
for package in rdepends:
|
for package in rdepends:
|
||||||
@@ -408,51 +363,51 @@ class BBCooker:
|
|||||||
|
|
||||||
# Prints a flattened form of package-depends below where subpackages of a package are merged into the main pn
|
# Prints a flattened form of package-depends below where subpackages of a package are merged into the main pn
|
||||||
depends_file = file('pn-depends.dot', 'w' )
|
depends_file = file('pn-depends.dot', 'w' )
|
||||||
print >> depends_file, "digraph depends {"
|
print("digraph depends {", file=depends_file)
|
||||||
for pn in depgraph["pn"]:
|
for pn in depgraph["pn"]:
|
||||||
fn = depgraph["pn"][pn]["filename"]
|
fn = depgraph["pn"][pn]["filename"]
|
||||||
version = depgraph["pn"][pn]["version"]
|
version = depgraph["pn"][pn]["version"]
|
||||||
print >> depends_file, '"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn)
|
print('"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn), file=depends_file)
|
||||||
for pn in depgraph["depends"]:
|
for pn in depgraph["depends"]:
|
||||||
for depend in depgraph["depends"][pn]:
|
for depend in depgraph["depends"][pn]:
|
||||||
print >> depends_file, '"%s" -> "%s"' % (pn, depend)
|
print('"%s" -> "%s"' % (pn, depend), file=depends_file)
|
||||||
for pn in depgraph["rdepends-pn"]:
|
for pn in depgraph["rdepends-pn"]:
|
||||||
for rdepend in depgraph["rdepends-pn"][pn]:
|
for rdepend in depgraph["rdepends-pn"][pn]:
|
||||||
print >> depends_file, '"%s" -> "%s" [style=dashed]' % (pn, rdepend)
|
print('"%s" -> "%s" [style=dashed]' % (pn, rdepend), file=depends_file)
|
||||||
print >> depends_file, "}"
|
print("}", file=depends_file)
|
||||||
bb.msg.plain("PN dependencies saved to 'pn-depends.dot'")
|
bb.msg.plain("PN dependencies saved to 'pn-depends.dot'")
|
||||||
|
|
||||||
depends_file = file('package-depends.dot', 'w' )
|
depends_file = file('package-depends.dot', 'w' )
|
||||||
print >> depends_file, "digraph depends {"
|
print("digraph depends {", file=depends_file)
|
||||||
for package in depgraph["packages"]:
|
for package in depgraph["packages"]:
|
||||||
pn = depgraph["packages"][package]["pn"]
|
pn = depgraph["packages"][package]["pn"]
|
||||||
fn = depgraph["packages"][package]["filename"]
|
fn = depgraph["packages"][package]["filename"]
|
||||||
version = depgraph["packages"][package]["version"]
|
version = depgraph["packages"][package]["version"]
|
||||||
if package == pn:
|
if package == pn:
|
||||||
print >> depends_file, '"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn)
|
print('"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn), file=depends_file)
|
||||||
else:
|
else:
|
||||||
print >> depends_file, '"%s" [label="%s(%s) %s\\n%s"]' % (package, package, pn, version, fn)
|
print('"%s" [label="%s(%s) %s\\n%s"]' % (package, package, pn, version, fn), file=depends_file)
|
||||||
for depend in depgraph["depends"][pn]:
|
for depend in depgraph["depends"][pn]:
|
||||||
print >> depends_file, '"%s" -> "%s"' % (package, depend)
|
print('"%s" -> "%s"' % (package, depend), file=depends_file)
|
||||||
for package in depgraph["rdepends-pkg"]:
|
for package in depgraph["rdepends-pkg"]:
|
||||||
for rdepend in depgraph["rdepends-pkg"][package]:
|
for rdepend in depgraph["rdepends-pkg"][package]:
|
||||||
print >> depends_file, '"%s" -> "%s" [style=dashed]' % (package, rdepend)
|
print('"%s" -> "%s" [style=dashed]' % (package, rdepend), file=depends_file)
|
||||||
for package in depgraph["rrecs-pkg"]:
|
for package in depgraph["rrecs-pkg"]:
|
||||||
for rdepend in depgraph["rrecs-pkg"][package]:
|
for rdepend in depgraph["rrecs-pkg"][package]:
|
||||||
print >> depends_file, '"%s" -> "%s" [style=dashed]' % (package, rdepend)
|
print('"%s" -> "%s" [style=dashed]' % (package, rdepend), file=depends_file)
|
||||||
print >> depends_file, "}"
|
print("}", file=depends_file)
|
||||||
bb.msg.plain("Package dependencies saved to 'package-depends.dot'")
|
bb.msg.plain("Package dependencies saved to 'package-depends.dot'")
|
||||||
|
|
||||||
tdepends_file = file('task-depends.dot', 'w' )
|
tdepends_file = file('task-depends.dot', 'w' )
|
||||||
print >> tdepends_file, "digraph depends {"
|
print("digraph depends {", file=tdepends_file)
|
||||||
for task in depgraph["tdepends"]:
|
for task in depgraph["tdepends"]:
|
||||||
(pn, taskname) = task.rsplit(".", 1)
|
(pn, taskname) = task.rsplit(".", 1)
|
||||||
fn = depgraph["pn"][pn]["filename"]
|
fn = depgraph["pn"][pn]["filename"]
|
||||||
version = depgraph["pn"][pn]["version"]
|
version = depgraph["pn"][pn]["version"]
|
||||||
print >> tdepends_file, '"%s.%s" [label="%s %s\\n%s\\n%s"]' % (pn, taskname, pn, taskname, version, fn)
|
print('"%s.%s" [label="%s %s\\n%s\\n%s"]' % (pn, taskname, pn, taskname, version, fn), file=tdepends_file)
|
||||||
for dep in depgraph["tdepends"][task]:
|
for dep in depgraph["tdepends"][task]:
|
||||||
print >> tdepends_file, '"%s" -> "%s"' % (task, dep)
|
print('"%s" -> "%s"' % (task, dep), file=tdepends_file)
|
||||||
print >> tdepends_file, "}"
|
print("}", file=tdepends_file)
|
||||||
bb.msg.plain("Task dependencies saved to 'task-depends.dot'")
|
bb.msg.plain("Task dependencies saved to 'task-depends.dot'")
|
||||||
|
|
||||||
def buildDepgraph( self ):
|
def buildDepgraph( self ):
|
||||||
@@ -463,9 +418,12 @@ class BBCooker:
|
|||||||
bb.data.update_data(localdata)
|
bb.data.update_data(localdata)
|
||||||
bb.data.expandKeys(localdata)
|
bb.data.expandKeys(localdata)
|
||||||
|
|
||||||
|
matched = set()
|
||||||
def calc_bbfile_priority(filename):
|
def calc_bbfile_priority(filename):
|
||||||
for (regex, pri) in self.status.bbfile_config_priorities:
|
for _, _, regex, pri in self.status.bbfile_config_priorities:
|
||||||
if regex.match(filename):
|
if regex.match(filename):
|
||||||
|
if not regex in matched:
|
||||||
|
matched.add(regex)
|
||||||
return pri
|
return pri
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -484,6 +442,11 @@ class BBCooker:
|
|||||||
for p in self.status.pkg_fn:
|
for p in self.status.pkg_fn:
|
||||||
self.status.bbfile_priority[p] = calc_bbfile_priority(p)
|
self.status.bbfile_priority[p] = calc_bbfile_priority(p)
|
||||||
|
|
||||||
|
for collection, pattern, regex, _ in self.status.bbfile_config_priorities:
|
||||||
|
if not regex in matched:
|
||||||
|
bb.msg.warn(bb.msg.domain.Provider, "No bb files matched BBFILE_PATTERN_%s '%s'" %
|
||||||
|
(collection, pattern))
|
||||||
|
|
||||||
def buildWorldTargetList(self):
|
def buildWorldTargetList(self):
|
||||||
"""
|
"""
|
||||||
Build package list for "bitbake world"
|
Build package list for "bitbake world"
|
||||||
@@ -516,31 +479,59 @@ class BBCooker:
|
|||||||
"""Drop off into a shell"""
|
"""Drop off into a shell"""
|
||||||
try:
|
try:
|
||||||
from bb import shell
|
from bb import shell
|
||||||
except ImportError, details:
|
except ImportError as details:
|
||||||
bb.msg.fatal(bb.msg.domain.Parsing, "Sorry, shell not available (%s)" % details )
|
bb.msg.fatal(bb.msg.domain.Parsing, "Sorry, shell not available (%s)" % details )
|
||||||
else:
|
else:
|
||||||
shell.start( self )
|
shell.start( self )
|
||||||
|
|
||||||
|
def _findLayerConf(self):
|
||||||
|
path = os.getcwd()
|
||||||
|
while path != "/":
|
||||||
|
bblayers = os.path.join(path, "conf", "bblayers.conf")
|
||||||
|
if os.path.exists(bblayers):
|
||||||
|
return bblayers
|
||||||
|
|
||||||
|
path, _ = os.path.split(path)
|
||||||
|
|
||||||
def parseConfigurationFiles(self, files):
|
def parseConfigurationFiles(self, files):
|
||||||
try:
|
try:
|
||||||
data = self.configuration.data
|
data = self.configuration.data
|
||||||
|
|
||||||
|
bb.parse.init_parser(data, self.configuration.dump_signatures)
|
||||||
for f in files:
|
for f in files:
|
||||||
data = bb.parse.handle(f, data)
|
data = bb.parse.handle(f, data)
|
||||||
|
|
||||||
layerconf = os.path.join(os.getcwd(), "conf", "bblayers.conf")
|
layerconf = self._findLayerConf()
|
||||||
if os.path.exists(layerconf):
|
if layerconf:
|
||||||
bb.msg.debug(2, bb.msg.domain.Parsing, "Found bblayers.conf (%s)" % layerconf)
|
bb.msg.debug(2, bb.msg.domain.Parsing, "Found bblayers.conf (%s)" % layerconf)
|
||||||
data = bb.parse.handle(layerconf, data)
|
data = bb.parse.handle(layerconf, data)
|
||||||
|
|
||||||
layers = (bb.data.getVar('BBLAYERS', data, True) or "").split()
|
layers = (bb.data.getVar('BBLAYERS', data, True) or "").split()
|
||||||
|
|
||||||
|
data = bb.data.createCopy(data)
|
||||||
for layer in layers:
|
for layer in layers:
|
||||||
bb.msg.debug(2, bb.msg.domain.Parsing, "Adding layer %s" % layer)
|
bb.msg.debug(2, bb.msg.domain.Parsing, "Adding layer %s" % layer)
|
||||||
bb.data.setVar('LAYERDIR', layer, data)
|
bb.data.setVar('LAYERDIR', layer, data)
|
||||||
data = bb.parse.handle(os.path.join(layer, "conf", "layer.conf"), data)
|
data = bb.parse.handle(os.path.join(layer, "conf", "layer.conf"), data)
|
||||||
|
|
||||||
|
# XXX: Hack, relies on the local keys of the datasmart
|
||||||
|
# instance being stored in the 'dict' attribute and makes
|
||||||
|
# assumptions about how variable expansion works, but
|
||||||
|
# there's no better way to force an expansion of a single
|
||||||
|
# variable across the datastore today, and this at least
|
||||||
|
# lets us reference LAYERDIR without having to immediately
|
||||||
|
# eval all our variables that use it.
|
||||||
|
for key in data.dict:
|
||||||
|
if key != "_data":
|
||||||
|
value = data.getVar(key, False)
|
||||||
|
if value and "${LAYERDIR}" in value:
|
||||||
|
data.setVar(key, value.replace("${LAYERDIR}", layer))
|
||||||
|
|
||||||
bb.data.delVar('LAYERDIR', data)
|
bb.data.delVar('LAYERDIR', data)
|
||||||
|
|
||||||
|
if not data.getVar("BBPATH", True):
|
||||||
|
bb.fatal("The BBPATH variable is not set")
|
||||||
|
|
||||||
data = bb.parse.handle(os.path.join("conf", "bitbake.conf"), data)
|
data = bb.parse.handle(os.path.join("conf", "bitbake.conf"), data)
|
||||||
|
|
||||||
self.configuration.data = data
|
self.configuration.data = data
|
||||||
@@ -552,16 +543,20 @@ class BBCooker:
|
|||||||
|
|
||||||
# Nomally we only register event handlers at the end of parsing .bb files
|
# Nomally we only register event handlers at the end of parsing .bb files
|
||||||
# We register any handlers we've found so far here...
|
# We register any handlers we've found so far here...
|
||||||
for var in data.getVar('__BBHANDLERS', self.configuration.data) or []:
|
for var in bb.data.getVar('__BBHANDLERS', self.configuration.data) or []:
|
||||||
bb.event.register(var,bb.data.getVar(var, self.configuration.data))
|
bb.event.register(var, bb.data.getVar(var, self.configuration.data))
|
||||||
|
|
||||||
bb.fetch.fetcher_init(self.configuration.data)
|
if bb.data.getVar("BB_WORKERCONTEXT", self.configuration.data) is None:
|
||||||
|
bb.fetch.fetcher_init(self.configuration.data)
|
||||||
|
bb.codeparser.parser_cache_init(self.configuration.data)
|
||||||
|
|
||||||
|
bb.parse.init_parser(data, self.configuration.dump_signatures)
|
||||||
|
|
||||||
bb.event.fire(bb.event.ConfigParsed(), self.configuration.data)
|
bb.event.fire(bb.event.ConfigParsed(), self.configuration.data)
|
||||||
|
|
||||||
except IOError, e:
|
except IOError as e:
|
||||||
bb.msg.fatal(bb.msg.domain.Parsing, "Error when parsing %s: %s" % (files, str(e)))
|
bb.msg.fatal(bb.msg.domain.Parsing, "Error when parsing %s: %s" % (files, str(e)))
|
||||||
except bb.parse.ParseError, details:
|
except bb.parse.ParseError as details:
|
||||||
bb.msg.fatal(bb.msg.domain.Parsing, "Unable to parse %s (%s)" % (files, details) )
|
bb.msg.fatal(bb.msg.domain.Parsing, "Unable to parse %s (%s)" % (files, details) )
|
||||||
|
|
||||||
def handleCollections( self, collections ):
|
def handleCollections( self, collections ):
|
||||||
@@ -584,7 +579,7 @@ class BBCooker:
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
pri = int(priority)
|
pri = int(priority)
|
||||||
self.status.bbfile_config_priorities.append((cre, pri))
|
self.status.bbfile_config_priorities.append((c, regex, cre, pri))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
bb.msg.error(bb.msg.domain.Parsing, "invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
|
bb.msg.error(bb.msg.domain.Parsing, "invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
|
||||||
|
|
||||||
@@ -593,8 +588,8 @@ class BBCooker:
|
|||||||
Setup any variables needed before starting a build
|
Setup any variables needed before starting a build
|
||||||
"""
|
"""
|
||||||
if not bb.data.getVar("BUILDNAME", self.configuration.data):
|
if not bb.data.getVar("BUILDNAME", self.configuration.data):
|
||||||
bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
|
bb.data.setVar("BUILDNAME", time.strftime('%Y%m%d%H%M'), self.configuration.data)
|
||||||
bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()), self.configuration.data)
|
bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S', time.gmtime()), self.configuration.data)
|
||||||
|
|
||||||
def matchFiles(self, buildfile):
|
def matchFiles(self, buildfile):
|
||||||
"""
|
"""
|
||||||
@@ -602,11 +597,11 @@ class BBCooker:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
bf = os.path.abspath(buildfile)
|
bf = os.path.abspath(buildfile)
|
||||||
|
(filelist, masked) = self.collect_bbfiles()
|
||||||
try:
|
try:
|
||||||
os.stat(bf)
|
os.stat(bf)
|
||||||
return [bf]
|
return [bf]
|
||||||
except OSError:
|
except OSError:
|
||||||
(filelist, masked) = self.collect_bbfiles()
|
|
||||||
regexp = re.compile(buildfile)
|
regexp = re.compile(buildfile)
|
||||||
matches = []
|
matches = []
|
||||||
for f in filelist:
|
for f in filelist:
|
||||||
@@ -641,13 +636,19 @@ class BBCooker:
|
|||||||
if (task == None):
|
if (task == None):
|
||||||
task = self.configuration.cmd
|
task = self.configuration.cmd
|
||||||
|
|
||||||
fn = self.matchFile(buildfile)
|
self.bb_cache = bb.cache.init(self)
|
||||||
|
self.status = bb.cache.CacheData()
|
||||||
|
|
||||||
|
(fn, cls) = self.bb_cache.virtualfn2realfn(buildfile)
|
||||||
|
buildfile = self.matchFile(fn)
|
||||||
|
fn = self.bb_cache.realfn2virtual(buildfile, cls)
|
||||||
|
|
||||||
self.buildSetVars()
|
self.buildSetVars()
|
||||||
|
|
||||||
# Load data into the cache for fn and parse the loaded cache data
|
# Load data into the cache for fn and parse the loaded cache data
|
||||||
self.bb_cache = bb.cache.init(self)
|
the_data = self.bb_cache.loadDataFull(fn, self.get_file_appends(fn), self.configuration.data)
|
||||||
self.status = bb.cache.CacheData()
|
self.bb_cache.setData(fn, buildfile, the_data)
|
||||||
self.bb_cache.loadData(fn, self.configuration.data, self.status)
|
self.bb_cache.handle_data(fn, self.status)
|
||||||
|
|
||||||
# Tweak some variables
|
# Tweak some variables
|
||||||
item = self.bb_cache.getVar('PN', fn, True)
|
item = self.bb_cache.getVar('PN', fn, True)
|
||||||
@@ -672,6 +673,9 @@ class BBCooker:
|
|||||||
buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
|
buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
|
||||||
bb.event.fire(bb.event.BuildStarted(buildname, [item]), self.configuration.event_data)
|
bb.event.fire(bb.event.BuildStarted(buildname, [item]), self.configuration.event_data)
|
||||||
|
|
||||||
|
# Clear locks
|
||||||
|
bb.fetch.persistent_database_connection = {}
|
||||||
|
|
||||||
# Execute the runqueue
|
# Execute the runqueue
|
||||||
runlist = [[item, "do_%s" % task]]
|
runlist = [[item, "do_%s" % task]]
|
||||||
|
|
||||||
@@ -686,8 +690,8 @@ class BBCooker:
|
|||||||
failures = 0
|
failures = 0
|
||||||
try:
|
try:
|
||||||
retval = rq.execute_runqueue()
|
retval = rq.execute_runqueue()
|
||||||
except runqueue.TaskFailure, fnids:
|
except runqueue.TaskFailure as exc:
|
||||||
for fnid in fnids:
|
for fnid in exc.args:
|
||||||
bb.msg.error(bb.msg.domain.Build, "'%s' failed" % taskdata.fn_index[fnid])
|
bb.msg.error(bb.msg.domain.Build, "'%s' failed" % taskdata.fn_index[fnid])
|
||||||
failures = failures + 1
|
failures = failures + 1
|
||||||
retval = False
|
retval = False
|
||||||
@@ -695,6 +699,8 @@ class BBCooker:
|
|||||||
bb.event.fire(bb.event.BuildCompleted(buildname, item, failures), self.configuration.event_data)
|
bb.event.fire(bb.event.BuildCompleted(buildname, item, failures), self.configuration.event_data)
|
||||||
self.command.finishAsyncCommand()
|
self.command.finishAsyncCommand()
|
||||||
return False
|
return False
|
||||||
|
if retval is True:
|
||||||
|
return True
|
||||||
return 0.5
|
return 0.5
|
||||||
|
|
||||||
self.server.register_idle_function(buildFileIdle, rq)
|
self.server.register_idle_function(buildFileIdle, rq)
|
||||||
@@ -714,7 +720,6 @@ class BBCooker:
|
|||||||
targets = self.checkPackages(targets)
|
targets = self.checkPackages(targets)
|
||||||
|
|
||||||
def buildTargetsIdle(server, rq, abort):
|
def buildTargetsIdle(server, rq, abort):
|
||||||
|
|
||||||
if abort or self.cookerAction == cookerStop:
|
if abort or self.cookerAction == cookerStop:
|
||||||
rq.finish_runqueue(True)
|
rq.finish_runqueue(True)
|
||||||
elif self.cookerAction == cookerShutdown:
|
elif self.cookerAction == cookerShutdown:
|
||||||
@@ -722,8 +727,8 @@ class BBCooker:
|
|||||||
failures = 0
|
failures = 0
|
||||||
try:
|
try:
|
||||||
retval = rq.execute_runqueue()
|
retval = rq.execute_runqueue()
|
||||||
except runqueue.TaskFailure, fnids:
|
except runqueue.TaskFailure as exc:
|
||||||
for fnid in fnids:
|
for fnid in exc.args:
|
||||||
bb.msg.error(bb.msg.domain.Build, "'%s' failed" % taskdata.fn_index[fnid])
|
bb.msg.error(bb.msg.domain.Build, "'%s' failed" % taskdata.fn_index[fnid])
|
||||||
failures = failures + 1
|
failures = failures + 1
|
||||||
retval = False
|
retval = False
|
||||||
@@ -731,6 +736,8 @@ class BBCooker:
|
|||||||
bb.event.fire(bb.event.BuildCompleted(buildname, targets, failures), self.configuration.event_data)
|
bb.event.fire(bb.event.BuildCompleted(buildname, targets, failures), self.configuration.event_data)
|
||||||
self.command.finishAsyncCommand()
|
self.command.finishAsyncCommand()
|
||||||
return None
|
return None
|
||||||
|
if retval is True:
|
||||||
|
return True
|
||||||
return 0.5
|
return 0.5
|
||||||
|
|
||||||
self.buildSetVars()
|
self.buildSetVars()
|
||||||
@@ -750,6 +757,9 @@ class BBCooker:
|
|||||||
runlist.append([k, "do_%s" % task])
|
runlist.append([k, "do_%s" % task])
|
||||||
taskdata.add_unresolved(localdata, self.status)
|
taskdata.add_unresolved(localdata, self.status)
|
||||||
|
|
||||||
|
# Clear locks
|
||||||
|
bb.fetch.persistent_database_connection = {}
|
||||||
|
|
||||||
rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
|
rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
|
||||||
|
|
||||||
self.server.register_idle_function(buildTargetsIdle, rq)
|
self.server.register_idle_function(buildTargetsIdle, rq)
|
||||||
@@ -780,13 +790,12 @@ class BBCooker:
|
|||||||
|
|
||||||
ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
|
ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
|
||||||
self.status.ignored_dependencies = set(ignore.split())
|
self.status.ignored_dependencies = set(ignore.split())
|
||||||
|
|
||||||
for dep in self.configuration.extra_assume_provided:
|
for dep in self.configuration.extra_assume_provided:
|
||||||
self.status.ignored_dependencies.add(dep)
|
self.status.ignored_dependencies.add(dep)
|
||||||
|
|
||||||
self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
|
self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
|
||||||
|
|
||||||
bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files")
|
|
||||||
(filelist, masked) = self.collect_bbfiles()
|
(filelist, masked) = self.collect_bbfiles()
|
||||||
bb.data.renameVar("__depends", "__base_depends", self.configuration.data)
|
bb.data.renameVar("__depends", "__base_depends", self.configuration.data)
|
||||||
|
|
||||||
@@ -821,11 +830,11 @@ class BBCooker:
|
|||||||
for f in contents:
|
for f in contents:
|
||||||
(root, ext) = os.path.splitext(f)
|
(root, ext) = os.path.splitext(f)
|
||||||
if ext == ".bb":
|
if ext == ".bb":
|
||||||
bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
|
bbfiles.append(os.path.abspath(os.path.join(os.getcwd(), f)))
|
||||||
return bbfiles
|
return bbfiles
|
||||||
|
|
||||||
def find_bbfiles( self, path ):
|
def find_bbfiles( self, path ):
|
||||||
"""Find all the .bb files in a directory"""
|
"""Find all the .bb and .bbappend files in a directory"""
|
||||||
from os.path import join
|
from os.path import join
|
||||||
|
|
||||||
found = []
|
found = []
|
||||||
@@ -833,7 +842,7 @@ class BBCooker:
|
|||||||
for ignored in ('SCCS', 'CVS', '.svn'):
|
for ignored in ('SCCS', 'CVS', '.svn'):
|
||||||
if ignored in dirs:
|
if ignored in dirs:
|
||||||
dirs.remove(ignored)
|
dirs.remove(ignored)
|
||||||
found += [join(dir,f) for f in files if f.endswith('.bb')]
|
found += [join(dir, f) for f in files if (f.endswith('.bb') or f.endswith('.bbappend'))]
|
||||||
|
|
||||||
return found
|
return found
|
||||||
|
|
||||||
@@ -842,6 +851,8 @@ class BBCooker:
|
|||||||
parsed, cached, skipped, masked = 0, 0, 0, 0
|
parsed, cached, skipped, masked = 0, 0, 0, 0
|
||||||
self.bb_cache = bb.cache.init(self)
|
self.bb_cache = bb.cache.init(self)
|
||||||
|
|
||||||
|
bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files")
|
||||||
|
|
||||||
files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
|
files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
|
||||||
data.setVar("BBFILES", " ".join(files), self.configuration.data)
|
data.setVar("BBFILES", " ".join(files), self.configuration.data)
|
||||||
|
|
||||||
@@ -856,9 +867,7 @@ class BBCooker:
|
|||||||
for f in files:
|
for f in files:
|
||||||
if os.path.isdir(f):
|
if os.path.isdir(f):
|
||||||
dirfiles = self.find_bbfiles(f)
|
dirfiles = self.find_bbfiles(f)
|
||||||
if dirfiles:
|
newfiles.update(dirfiles)
|
||||||
newfiles.update(dirfiles)
|
|
||||||
continue
|
|
||||||
else:
|
else:
|
||||||
globbed = glob.glob(f)
|
globbed = glob.glob(f)
|
||||||
if not globbed and os.path.exists(f):
|
if not globbed and os.path.exists(f):
|
||||||
@@ -867,23 +876,45 @@ class BBCooker:
|
|||||||
|
|
||||||
bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1)
|
bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1)
|
||||||
|
|
||||||
if not bbmask:
|
if bbmask:
|
||||||
return (list(newfiles), 0)
|
try:
|
||||||
|
bbmask_compiled = re.compile(bbmask)
|
||||||
|
except sre_constants.error:
|
||||||
|
bb.msg.fatal(bb.msg.domain.Collection, "BBMASK is not a valid regular expression.")
|
||||||
|
|
||||||
try:
|
bbfiles = []
|
||||||
bbmask_compiled = re.compile(bbmask)
|
bbappend = []
|
||||||
except sre_constants.error:
|
|
||||||
bb.msg.fatal(bb.msg.domain.Collection, "BBMASK is not a valid regular expression.")
|
|
||||||
|
|
||||||
finalfiles = []
|
|
||||||
for f in newfiles:
|
for f in newfiles:
|
||||||
if bbmask_compiled.search(f):
|
if bbmask and bbmask_compiled.search(f):
|
||||||
bb.msg.debug(1, bb.msg.domain.Collection, "skipping masked file %s" % f)
|
bb.msg.debug(1, bb.msg.domain.Collection, "skipping masked file %s" % f)
|
||||||
masked += 1
|
masked += 1
|
||||||
continue
|
continue
|
||||||
finalfiles.append(f)
|
if f.endswith('.bb'):
|
||||||
|
bbfiles.append(f)
|
||||||
|
elif f.endswith('.bbappend'):
|
||||||
|
bbappend.append(f)
|
||||||
|
else:
|
||||||
|
bb.msg.note(1, bb.msg.domain.Collection, "File %s of unknown filetype in BBFILES? Ignorning..." % f)
|
||||||
|
|
||||||
return (finalfiles, masked)
|
# Build a list of .bbappend files for each .bb file
|
||||||
|
self.appendlist = {}
|
||||||
|
for f in bbappend:
|
||||||
|
base = os.path.basename(f).replace('.bbappend', '.bb')
|
||||||
|
if not base in self.appendlist:
|
||||||
|
self.appendlist[base] = []
|
||||||
|
self.appendlist[base].append(f)
|
||||||
|
|
||||||
|
return (bbfiles, masked)
|
||||||
|
|
||||||
|
def get_file_appends(self, fn):
|
||||||
|
"""
|
||||||
|
Returns a list of .bbappend files to apply to fn
|
||||||
|
NB: collect_files() must have been called prior to this
|
||||||
|
"""
|
||||||
|
f = os.path.basename(fn)
|
||||||
|
if f in self.appendlist:
|
||||||
|
return self.appendlist[f]
|
||||||
|
return []
|
||||||
|
|
||||||
def serve(self):
|
def serve(self):
|
||||||
|
|
||||||
@@ -917,9 +948,9 @@ class BBCooker:
|
|||||||
pout.close()
|
pout.close()
|
||||||
else:
|
else:
|
||||||
self.server.serve_forever()
|
self.server.serve_forever()
|
||||||
|
|
||||||
bb.event.fire(CookerExit(), self.configuration.event_data)
|
bb.event.fire(CookerExit(), self.configuration.event_data)
|
||||||
|
|
||||||
class CookerExit(bb.event.Event):
|
class CookerExit(bb.event.Event):
|
||||||
"""
|
"""
|
||||||
Notify clients of the Cooker shutdown
|
Notify clients of the Cooker shutdown
|
||||||
@@ -948,12 +979,12 @@ class CookerParser:
|
|||||||
self.pointer = 0
|
self.pointer = 0
|
||||||
|
|
||||||
def parse_next(self):
|
def parse_next(self):
|
||||||
|
cooker = self.cooker
|
||||||
if self.pointer < len(self.filelist):
|
if self.pointer < len(self.filelist):
|
||||||
f = self.filelist[self.pointer]
|
f = self.filelist[self.pointer]
|
||||||
cooker = self.cooker
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fromCache, skipped, virtuals = cooker.bb_cache.loadData(f, cooker.configuration.data, cooker.status)
|
fromCache, skipped, virtuals = cooker.bb_cache.loadData(f, cooker.get_file_appends(f), cooker.configuration.data, cooker.status)
|
||||||
if fromCache:
|
if fromCache:
|
||||||
self.cached += 1
|
self.cached += 1
|
||||||
else:
|
else:
|
||||||
@@ -962,7 +993,7 @@ class CookerParser:
|
|||||||
self.skipped += skipped
|
self.skipped += skipped
|
||||||
self.virtuals += virtuals
|
self.virtuals += virtuals
|
||||||
|
|
||||||
except IOError, e:
|
except IOError as e:
|
||||||
self.error += 1
|
self.error += 1
|
||||||
cooker.bb_cache.remove(f)
|
cooker.bb_cache.remove(f)
|
||||||
bb.msg.error(bb.msg.domain.Collection, "opening %s: %s" % (f, e))
|
bb.msg.error(bb.msg.domain.Collection, "opening %s: %s" % (f, e))
|
||||||
@@ -971,7 +1002,7 @@ class CookerParser:
|
|||||||
cooker.bb_cache.remove(f)
|
cooker.bb_cache.remove(f)
|
||||||
cooker.bb_cache.sync()
|
cooker.bb_cache.sync()
|
||||||
raise
|
raise
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
self.error += 1
|
self.error += 1
|
||||||
cooker.bb_cache.remove(f)
|
cooker.bb_cache.remove(f)
|
||||||
bb.msg.error(bb.msg.domain.Collection, "%s while parsing %s" % (e, f))
|
bb.msg.error(bb.msg.domain.Collection, "%s while parsing %s" % (e, f))
|
||||||
@@ -985,8 +1016,8 @@ class CookerParser:
|
|||||||
|
|
||||||
if self.pointer >= self.total:
|
if self.pointer >= self.total:
|
||||||
cooker.bb_cache.sync()
|
cooker.bb_cache.sync()
|
||||||
|
bb.codeparser.parser_cache_save(cooker.configuration.data)
|
||||||
if self.error > 0:
|
if self.error > 0:
|
||||||
raise ParsingErrorsFound
|
raise ParsingErrorsFound
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -1,191 +1,190 @@
|
|||||||
"""
|
"""
|
||||||
Python Deamonizing helper
|
Python Deamonizing helper
|
||||||
|
|
||||||
Configurable daemon behaviors:
|
Configurable daemon behaviors:
|
||||||
|
|
||||||
1.) The current working directory set to the "/" directory.
|
1.) The current working directory set to the "/" directory.
|
||||||
2.) The current file creation mode mask set to 0.
|
2.) The current file creation mode mask set to 0.
|
||||||
3.) Close all open files (1024).
|
3.) Close all open files (1024).
|
||||||
4.) Redirect standard I/O streams to "/dev/null".
|
4.) Redirect standard I/O streams to "/dev/null".
|
||||||
|
|
||||||
A failed call to fork() now raises an exception.
|
A failed call to fork() now raises an exception.
|
||||||
|
|
||||||
References:
|
References:
|
||||||
1) Advanced Programming in the Unix Environment: W. Richard Stevens
|
1) Advanced Programming in the Unix Environment: W. Richard Stevens
|
||||||
2) Unix Programming Frequently Asked Questions:
|
2) Unix Programming Frequently Asked Questions:
|
||||||
http://www.erlenstar.demon.co.uk/unix/faq_toc.html
|
http://www.erlenstar.demon.co.uk/unix/faq_toc.html
|
||||||
|
|
||||||
Modified to allow a function to be daemonized and return for
|
Modified to allow a function to be daemonized and return for
|
||||||
bitbake use by Richard Purdie
|
bitbake use by Richard Purdie
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = "Chad J. Schroeder"
|
__author__ = "Chad J. Schroeder"
|
||||||
__copyright__ = "Copyright (C) 2005 Chad J. Schroeder"
|
__copyright__ = "Copyright (C) 2005 Chad J. Schroeder"
|
||||||
__version__ = "0.2"
|
__version__ = "0.2"
|
||||||
|
|
||||||
# Standard Python modules.
|
# Standard Python modules.
|
||||||
import os # Miscellaneous OS interfaces.
|
import os # Miscellaneous OS interfaces.
|
||||||
import sys # System-specific parameters and functions.
|
import sys # System-specific parameters and functions.
|
||||||
|
|
||||||
# Default daemon parameters.
|
# Default daemon parameters.
|
||||||
# File mode creation mask of the daemon.
|
# File mode creation mask of the daemon.
|
||||||
# For BitBake's children, we do want to inherit the parent umask.
|
# For BitBake's children, we do want to inherit the parent umask.
|
||||||
UMASK = None
|
UMASK = None
|
||||||
|
|
||||||
# Default maximum for the number of available file descriptors.
|
# Default maximum for the number of available file descriptors.
|
||||||
MAXFD = 1024
|
MAXFD = 1024
|
||||||
|
|
||||||
# The standard I/O file descriptors are redirected to /dev/null by default.
|
# The standard I/O file descriptors are redirected to /dev/null by default.
|
||||||
if (hasattr(os, "devnull")):
|
if (hasattr(os, "devnull")):
|
||||||
REDIRECT_TO = os.devnull
|
REDIRECT_TO = os.devnull
|
||||||
else:
|
else:
|
||||||
REDIRECT_TO = "/dev/null"
|
REDIRECT_TO = "/dev/null"
|
||||||
|
|
||||||
def createDaemon(function, logfile):
|
def createDaemon(function, logfile):
|
||||||
"""
|
"""
|
||||||
Detach a process from the controlling terminal and run it in the
|
Detach a process from the controlling terminal and run it in the
|
||||||
background as a daemon, returning control to the caller.
|
background as a daemon, returning control to the caller.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Fork a child process so the parent can exit. This returns control to
|
# Fork a child process so the parent can exit. This returns control to
|
||||||
# the command-line or shell. It also guarantees that the child will not
|
# the command-line or shell. It also guarantees that the child will not
|
||||||
# be a process group leader, since the child receives a new process ID
|
# be a process group leader, since the child receives a new process ID
|
||||||
# and inherits the parent's process group ID. This step is required
|
# and inherits the parent's process group ID. This step is required
|
||||||
# to insure that the next call to os.setsid is successful.
|
# to insure that the next call to os.setsid is successful.
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
except OSError, e:
|
except OSError as e:
|
||||||
raise Exception, "%s [%d]" % (e.strerror, e.errno)
|
raise Exception("%s [%d]" % (e.strerror, e.errno))
|
||||||
|
|
||||||
if (pid == 0): # The first child.
|
if (pid == 0): # The first child.
|
||||||
# To become the session leader of this new session and the process group
|
# To become the session leader of this new session and the process group
|
||||||
# leader of the new process group, we call os.setsid(). The process is
|
# leader of the new process group, we call os.setsid(). The process is
|
||||||
# also guaranteed not to have a controlling terminal.
|
# also guaranteed not to have a controlling terminal.
|
||||||
os.setsid()
|
os.setsid()
|
||||||
|
|
||||||
# Is ignoring SIGHUP necessary?
|
# Is ignoring SIGHUP necessary?
|
||||||
#
|
#
|
||||||
# It's often suggested that the SIGHUP signal should be ignored before
|
# It's often suggested that the SIGHUP signal should be ignored before
|
||||||
# the second fork to avoid premature termination of the process. The
|
# the second fork to avoid premature termination of the process. The
|
||||||
# reason is that when the first child terminates, all processes, e.g.
|
# reason is that when the first child terminates, all processes, e.g.
|
||||||
# the second child, in the orphaned group will be sent a SIGHUP.
|
# the second child, in the orphaned group will be sent a SIGHUP.
|
||||||
#
|
#
|
||||||
# "However, as part of the session management system, there are exactly
|
# "However, as part of the session management system, there are exactly
|
||||||
# two cases where SIGHUP is sent on the death of a process:
|
# two cases where SIGHUP is sent on the death of a process:
|
||||||
#
|
#
|
||||||
# 1) When the process that dies is the session leader of a session that
|
# 1) When the process that dies is the session leader of a session that
|
||||||
# is attached to a terminal device, SIGHUP is sent to all processes
|
# is attached to a terminal device, SIGHUP is sent to all processes
|
||||||
# in the foreground process group of that terminal device.
|
# in the foreground process group of that terminal device.
|
||||||
# 2) When the death of a process causes a process group to become
|
# 2) When the death of a process causes a process group to become
|
||||||
# orphaned, and one or more processes in the orphaned group are
|
# orphaned, and one or more processes in the orphaned group are
|
||||||
# stopped, then SIGHUP and SIGCONT are sent to all members of the
|
# stopped, then SIGHUP and SIGCONT are sent to all members of the
|
||||||
# orphaned group." [2]
|
# orphaned group." [2]
|
||||||
#
|
#
|
||||||
# The first case can be ignored since the child is guaranteed not to have
|
# The first case can be ignored since the child is guaranteed not to have
|
||||||
# a controlling terminal. The second case isn't so easy to dismiss.
|
# a controlling terminal. The second case isn't so easy to dismiss.
|
||||||
# The process group is orphaned when the first child terminates and
|
# The process group is orphaned when the first child terminates and
|
||||||
# POSIX.1 requires that every STOPPED process in an orphaned process
|
# POSIX.1 requires that every STOPPED process in an orphaned process
|
||||||
# group be sent a SIGHUP signal followed by a SIGCONT signal. Since the
|
# group be sent a SIGHUP signal followed by a SIGCONT signal. Since the
|
||||||
# second child is not STOPPED though, we can safely forego ignoring the
|
# second child is not STOPPED though, we can safely forego ignoring the
|
||||||
# SIGHUP signal. In any case, there are no ill-effects if it is ignored.
|
# SIGHUP signal. In any case, there are no ill-effects if it is ignored.
|
||||||
#
|
#
|
||||||
# import signal # Set handlers for asynchronous events.
|
# import signal # Set handlers for asynchronous events.
|
||||||
# signal.signal(signal.SIGHUP, signal.SIG_IGN)
|
# signal.signal(signal.SIGHUP, signal.SIG_IGN)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Fork a second child and exit immediately to prevent zombies. This
|
# Fork a second child and exit immediately to prevent zombies. This
|
||||||
# causes the second child process to be orphaned, making the init
|
# causes the second child process to be orphaned, making the init
|
||||||
# process responsible for its cleanup. And, since the first child is
|
# process responsible for its cleanup. And, since the first child is
|
||||||
# a session leader without a controlling terminal, it's possible for
|
# a session leader without a controlling terminal, it's possible for
|
||||||
# it to acquire one by opening a terminal in the future (System V-
|
# it to acquire one by opening a terminal in the future (System V-
|
||||||
# based systems). This second fork guarantees that the child is no
|
# based systems). This second fork guarantees that the child is no
|
||||||
# longer a session leader, preventing the daemon from ever acquiring
|
# longer a session leader, preventing the daemon from ever acquiring
|
||||||
# a controlling terminal.
|
# a controlling terminal.
|
||||||
pid = os.fork() # Fork a second child.
|
pid = os.fork() # Fork a second child.
|
||||||
except OSError, e:
|
except OSError as e:
|
||||||
raise Exception, "%s [%d]" % (e.strerror, e.errno)
|
raise Exception("%s [%d]" % (e.strerror, e.errno))
|
||||||
|
|
||||||
if (pid == 0): # The second child.
|
if (pid == 0): # The second child.
|
||||||
# We probably don't want the file mode creation mask inherited from
|
# We probably don't want the file mode creation mask inherited from
|
||||||
# the parent, so we give the child complete control over permissions.
|
# the parent, so we give the child complete control over permissions.
|
||||||
if UMASK is not None:
|
if UMASK is not None:
|
||||||
os.umask(UMASK)
|
os.umask(UMASK)
|
||||||
else:
|
else:
|
||||||
# Parent (the first child) of the second child.
|
# Parent (the first child) of the second child.
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
else:
|
else:
|
||||||
# exit() or _exit()?
|
# exit() or _exit()?
|
||||||
# _exit is like exit(), but it doesn't call any functions registered
|
# _exit is like exit(), but it doesn't call any functions registered
|
||||||
# with atexit (and on_exit) or any registered signal handlers. It also
|
# with atexit (and on_exit) or any registered signal handlers. It also
|
||||||
# closes any open file descriptors. Using exit() may cause all stdio
|
# closes any open file descriptors. Using exit() may cause all stdio
|
||||||
# streams to be flushed twice and any temporary files may be unexpectedly
|
# streams to be flushed twice and any temporary files may be unexpectedly
|
||||||
# removed. It's therefore recommended that child branches of a fork()
|
# removed. It's therefore recommended that child branches of a fork()
|
||||||
# and the parent branch(es) of a daemon use _exit().
|
# and the parent branch(es) of a daemon use _exit().
|
||||||
return
|
return
|
||||||
|
|
||||||
# Close all open file descriptors. This prevents the child from keeping
|
# Close all open file descriptors. This prevents the child from keeping
|
||||||
# open any file descriptors inherited from the parent. There is a variety
|
# open any file descriptors inherited from the parent. There is a variety
|
||||||
# of methods to accomplish this task. Three are listed below.
|
# of methods to accomplish this task. Three are listed below.
|
||||||
#
|
#
|
||||||
# Try the system configuration variable, SC_OPEN_MAX, to obtain the maximum
|
# Try the system configuration variable, SC_OPEN_MAX, to obtain the maximum
|
||||||
# number of open file descriptors to close. If it doesn't exists, use
|
# number of open file descriptors to close. If it doesn't exists, use
|
||||||
# the default value (configurable).
|
# the default value (configurable).
|
||||||
#
|
#
|
||||||
# try:
|
# try:
|
||||||
# maxfd = os.sysconf("SC_OPEN_MAX")
|
# maxfd = os.sysconf("SC_OPEN_MAX")
|
||||||
# except (AttributeError, ValueError):
|
# except (AttributeError, ValueError):
|
||||||
# maxfd = MAXFD
|
# maxfd = MAXFD
|
||||||
#
|
#
|
||||||
# OR
|
# OR
|
||||||
#
|
#
|
||||||
# if (os.sysconf_names.has_key("SC_OPEN_MAX")):
|
# if (os.sysconf_names.has_key("SC_OPEN_MAX")):
|
||||||
# maxfd = os.sysconf("SC_OPEN_MAX")
|
# maxfd = os.sysconf("SC_OPEN_MAX")
|
||||||
# else:
|
# else:
|
||||||
# maxfd = MAXFD
|
# maxfd = MAXFD
|
||||||
#
|
#
|
||||||
# OR
|
# OR
|
||||||
#
|
#
|
||||||
# Use the getrlimit method to retrieve the maximum file descriptor number
|
# Use the getrlimit method to retrieve the maximum file descriptor number
|
||||||
# that can be opened by this process. If there is not limit on the
|
# that can be opened by this process. If there is not limit on the
|
||||||
# resource, use the default value.
|
# resource, use the default value.
|
||||||
#
|
#
|
||||||
import resource # Resource usage information.
|
import resource # Resource usage information.
|
||||||
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
|
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
|
||||||
if (maxfd == resource.RLIM_INFINITY):
|
if (maxfd == resource.RLIM_INFINITY):
|
||||||
maxfd = MAXFD
|
maxfd = MAXFD
|
||||||
|
|
||||||
# Iterate through and close all file descriptors.
|
# Iterate through and close all file descriptors.
|
||||||
# for fd in range(0, maxfd):
|
# for fd in range(0, maxfd):
|
||||||
# try:
|
# try:
|
||||||
# os.close(fd)
|
# os.close(fd)
|
||||||
# except OSError: # ERROR, fd wasn't open to begin with (ignored)
|
# except OSError: # ERROR, fd wasn't open to begin with (ignored)
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
# Redirect the standard I/O file descriptors to the specified file. Since
|
# Redirect the standard I/O file descriptors to the specified file. Since
|
||||||
# the daemon has no controlling terminal, most daemons redirect stdin,
|
# the daemon has no controlling terminal, most daemons redirect stdin,
|
||||||
# stdout, and stderr to /dev/null. This is done to prevent side-effects
|
# stdout, and stderr to /dev/null. This is done to prevent side-effects
|
||||||
# from reads and writes to the standard I/O file descriptors.
|
# from reads and writes to the standard I/O file descriptors.
|
||||||
|
|
||||||
# This call to open is guaranteed to return the lowest file descriptor,
|
# This call to open is guaranteed to return the lowest file descriptor,
|
||||||
# which will be 0 (stdin), since it was closed above.
|
# which will be 0 (stdin), since it was closed above.
|
||||||
# os.open(REDIRECT_TO, os.O_RDWR) # standard input (0)
|
# os.open(REDIRECT_TO, os.O_RDWR) # standard input (0)
|
||||||
|
|
||||||
# Duplicate standard input to standard output and standard error.
|
# Duplicate standard input to standard output and standard error.
|
||||||
# os.dup2(0, 1) # standard output (1)
|
# os.dup2(0, 1) # standard output (1)
|
||||||
# os.dup2(0, 2) # standard error (2)
|
# os.dup2(0, 2) # standard error (2)
|
||||||
|
|
||||||
|
|
||||||
si = file('/dev/null', 'r')
|
si = file('/dev/null', 'r')
|
||||||
so = file(logfile, 'w')
|
so = file(logfile, 'w')
|
||||||
se = so
|
se = so
|
||||||
|
|
||||||
|
|
||||||
# Replace those fds with our own
|
# Replace those fds with our own
|
||||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||||
|
|
||||||
function()
|
function()
|
||||||
|
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ operations. At night the cookie monster came by and
|
|||||||
suggested 'give me cookies on setting the variables and
|
suggested 'give me cookies on setting the variables and
|
||||||
things will work out'. Taking this suggestion into account
|
things will work out'. Taking this suggestion into account
|
||||||
applying the skills from the not yet passed 'Entwurf und
|
applying the skills from the not yet passed 'Entwurf und
|
||||||
Analyse von Algorithmen' lecture and the cookie
|
Analyse von Algorithmen' lecture and the cookie
|
||||||
monster seems to be right. We will track setVar more carefully
|
monster seems to be right. We will track setVar more carefully
|
||||||
to have faster update_data and expandKeys operations.
|
to have faster update_data and expandKeys operations.
|
||||||
|
|
||||||
@@ -37,39 +37,41 @@ the speed is more critical here.
|
|||||||
#
|
#
|
||||||
#Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
#Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
import sys, os, re, types
|
import sys, os, re
|
||||||
if sys.argv[0][-5:] == "pydoc":
|
if sys.argv[0][-5:] == "pydoc":
|
||||||
path = os.path.dirname(os.path.dirname(sys.argv[1]))
|
path = os.path.dirname(os.path.dirname(sys.argv[1]))
|
||||||
else:
|
else:
|
||||||
path = os.path.dirname(os.path.dirname(sys.argv[0]))
|
path = os.path.dirname(os.path.dirname(sys.argv[0]))
|
||||||
sys.path.insert(0,path)
|
sys.path.insert(0, path)
|
||||||
|
from itertools import groupby
|
||||||
|
|
||||||
from bb import data_smart
|
from bb import data_smart
|
||||||
|
from bb import codeparser
|
||||||
import bb
|
import bb
|
||||||
|
|
||||||
class VarExpandError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
_dict_type = data_smart.DataSmart
|
_dict_type = data_smart.DataSmart
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
|
"""Return a new object representing the Bitbake data"""
|
||||||
return _dict_type()
|
return _dict_type()
|
||||||
|
|
||||||
def init_db(parent = None):
|
def init_db(parent = None):
|
||||||
|
"""Return a new object representing the Bitbake data,
|
||||||
|
optionally based on an existing object"""
|
||||||
if parent:
|
if parent:
|
||||||
return parent.createCopy()
|
return parent.createCopy()
|
||||||
else:
|
else:
|
||||||
return _dict_type()
|
return _dict_type()
|
||||||
|
|
||||||
def createCopy(source):
|
def createCopy(source):
|
||||||
"""Link the source set to the destination
|
"""Link the source set to the destination
|
||||||
If one does not find the value in the destination set,
|
If one does not find the value in the destination set,
|
||||||
search will go on to the source set to get the value.
|
search will go on to the source set to get the value.
|
||||||
Value from source are copy-on-write. i.e. any try to
|
Value from source are copy-on-write. i.e. any try to
|
||||||
modify one of them will end up putting the modified value
|
modify one of them will end up putting the modified value
|
||||||
in the destination set.
|
in the destination set.
|
||||||
"""
|
"""
|
||||||
return source.createCopy()
|
return source.createCopy()
|
||||||
|
|
||||||
def initVar(var, d):
|
def initVar(var, d):
|
||||||
"""Non-destructive var init for data structure"""
|
"""Non-destructive var init for data structure"""
|
||||||
@@ -77,91 +79,34 @@ def initVar(var, d):
|
|||||||
|
|
||||||
|
|
||||||
def setVar(var, value, d):
|
def setVar(var, value, d):
|
||||||
"""Set a variable to a given value
|
"""Set a variable to a given value"""
|
||||||
|
d.setVar(var, value)
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVar('TEST', 'testcontents', d)
|
|
||||||
>>> print getVar('TEST', d)
|
|
||||||
testcontents
|
|
||||||
"""
|
|
||||||
d.setVar(var,value)
|
|
||||||
|
|
||||||
|
|
||||||
def getVar(var, d, exp = 0):
|
def getVar(var, d, exp = 0):
|
||||||
"""Gets the value of a variable
|
"""Gets the value of a variable"""
|
||||||
|
return d.getVar(var, exp)
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVar('TEST', 'testcontents', d)
|
|
||||||
>>> print getVar('TEST', d)
|
|
||||||
testcontents
|
|
||||||
"""
|
|
||||||
return d.getVar(var,exp)
|
|
||||||
|
|
||||||
|
|
||||||
def renameVar(key, newkey, d):
|
def renameVar(key, newkey, d):
|
||||||
"""Renames a variable from key to newkey
|
"""Renames a variable from key to newkey"""
|
||||||
|
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVar('TEST', 'testcontents', d)
|
|
||||||
>>> renameVar('TEST', 'TEST2', d)
|
|
||||||
>>> print getVar('TEST2', d)
|
|
||||||
testcontents
|
|
||||||
"""
|
|
||||||
d.renameVar(key, newkey)
|
d.renameVar(key, newkey)
|
||||||
|
|
||||||
def delVar(var, d):
|
def delVar(var, d):
|
||||||
"""Removes a variable from the data set
|
"""Removes a variable from the data set"""
|
||||||
|
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVar('TEST', 'testcontents', d)
|
|
||||||
>>> print getVar('TEST', d)
|
|
||||||
testcontents
|
|
||||||
>>> delVar('TEST', d)
|
|
||||||
>>> print getVar('TEST', d)
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
d.delVar(var)
|
d.delVar(var)
|
||||||
|
|
||||||
def setVarFlag(var, flag, flagvalue, d):
|
def setVarFlag(var, flag, flagvalue, d):
|
||||||
"""Set a flag for a given variable to a given value
|
"""Set a flag for a given variable to a given value"""
|
||||||
|
d.setVarFlag(var, flag, flagvalue)
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVarFlag('TEST', 'python', 1, d)
|
|
||||||
>>> print getVarFlag('TEST', 'python', d)
|
|
||||||
1
|
|
||||||
"""
|
|
||||||
d.setVarFlag(var,flag,flagvalue)
|
|
||||||
|
|
||||||
def getVarFlag(var, flag, d):
|
def getVarFlag(var, flag, d):
|
||||||
"""Gets given flag from given var
|
"""Gets given flag from given var"""
|
||||||
|
return d.getVarFlag(var, flag)
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVarFlag('TEST', 'python', 1, d)
|
|
||||||
>>> print getVarFlag('TEST', 'python', d)
|
|
||||||
1
|
|
||||||
"""
|
|
||||||
return d.getVarFlag(var,flag)
|
|
||||||
|
|
||||||
def delVarFlag(var, flag, d):
|
def delVarFlag(var, flag, d):
|
||||||
"""Removes a given flag from the variable's flags
|
"""Removes a given flag from the variable's flags"""
|
||||||
|
d.delVarFlag(var, flag)
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVarFlag('TEST', 'testflag', 1, d)
|
|
||||||
>>> print getVarFlag('TEST', 'testflag', d)
|
|
||||||
1
|
|
||||||
>>> delVarFlag('TEST', 'testflag', d)
|
|
||||||
>>> print getVarFlag('TEST', 'testflag', d)
|
|
||||||
None
|
|
||||||
|
|
||||||
"""
|
|
||||||
d.delVarFlag(var,flag)
|
|
||||||
|
|
||||||
def setVarFlags(var, flags, d):
|
def setVarFlags(var, flags, d):
|
||||||
"""Set the flags for a given variable
|
"""Set the flags for a given variable
|
||||||
@@ -170,115 +115,27 @@ def setVarFlags(var, flags, d):
|
|||||||
setVarFlags will not clear previous
|
setVarFlags will not clear previous
|
||||||
flags. Think of this method as
|
flags. Think of this method as
|
||||||
addVarFlags
|
addVarFlags
|
||||||
|
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> myflags = {}
|
|
||||||
>>> myflags['test'] = 'blah'
|
|
||||||
>>> setVarFlags('TEST', myflags, d)
|
|
||||||
>>> print getVarFlag('TEST', 'test', d)
|
|
||||||
blah
|
|
||||||
"""
|
"""
|
||||||
d.setVarFlags(var,flags)
|
d.setVarFlags(var, flags)
|
||||||
|
|
||||||
def getVarFlags(var, d):
|
def getVarFlags(var, d):
|
||||||
"""Gets a variable's flags
|
"""Gets a variable's flags"""
|
||||||
|
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVarFlag('TEST', 'test', 'blah', d)
|
|
||||||
>>> print getVarFlags('TEST', d)['test']
|
|
||||||
blah
|
|
||||||
"""
|
|
||||||
return d.getVarFlags(var)
|
return d.getVarFlags(var)
|
||||||
|
|
||||||
def delVarFlags(var, d):
|
def delVarFlags(var, d):
|
||||||
"""Removes a variable's flags
|
"""Removes a variable's flags"""
|
||||||
|
|
||||||
Example:
|
|
||||||
>>> data = init()
|
|
||||||
>>> setVarFlag('TEST', 'testflag', 1, data)
|
|
||||||
>>> print getVarFlag('TEST', 'testflag', data)
|
|
||||||
1
|
|
||||||
>>> delVarFlags('TEST', data)
|
|
||||||
>>> print getVarFlags('TEST', data)
|
|
||||||
None
|
|
||||||
|
|
||||||
"""
|
|
||||||
d.delVarFlags(var)
|
d.delVarFlags(var)
|
||||||
|
|
||||||
def keys(d):
|
def keys(d):
|
||||||
"""Return a list of keys in d
|
"""Return a list of keys in d"""
|
||||||
|
|
||||||
Example:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVar('TEST', 1, d)
|
|
||||||
>>> setVar('MOO' , 2, d)
|
|
||||||
>>> setVarFlag('TEST', 'test', 1, d)
|
|
||||||
>>> keys(d)
|
|
||||||
['TEST', 'MOO']
|
|
||||||
"""
|
|
||||||
return d.keys()
|
return d.keys()
|
||||||
|
|
||||||
def getData(d):
|
|
||||||
"""Returns the data object used"""
|
|
||||||
return d
|
|
||||||
|
|
||||||
def setData(newData, d):
|
|
||||||
"""Sets the data object to the supplied value"""
|
|
||||||
d = newData
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
## Cookie Monsters' query functions
|
|
||||||
##
|
|
||||||
def _get_override_vars(d, override):
|
|
||||||
"""
|
|
||||||
Internal!!!
|
|
||||||
|
|
||||||
Get the Names of Variables that have a specific
|
|
||||||
override. This function returns a iterable
|
|
||||||
Set or an empty list
|
|
||||||
"""
|
|
||||||
return []
|
|
||||||
|
|
||||||
def _get_var_flags_triple(d):
|
|
||||||
"""
|
|
||||||
Internal!!!
|
|
||||||
|
|
||||||
"""
|
|
||||||
return []
|
|
||||||
|
|
||||||
__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
|
__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
|
||||||
__expand_python_regexp__ = re.compile(r"\${@.+?}")
|
__expand_python_regexp__ = re.compile(r"\${@.+?}")
|
||||||
|
|
||||||
def expand(s, d, varname = None):
|
def expand(s, d, varname = None):
|
||||||
"""Variable expansion using the data store.
|
"""Variable expansion using the data store"""
|
||||||
|
|
||||||
Example:
|
|
||||||
Standard expansion:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVar('A', 'sshd', d)
|
|
||||||
>>> print expand('/usr/bin/${A}', d)
|
|
||||||
/usr/bin/sshd
|
|
||||||
|
|
||||||
Python expansion:
|
|
||||||
>>> d = init()
|
|
||||||
>>> print expand('result: ${@37 * 72}', d)
|
|
||||||
result: 2664
|
|
||||||
|
|
||||||
Shell expansion:
|
|
||||||
>>> d = init()
|
|
||||||
>>> print expand('${TARGET_MOO}', d)
|
|
||||||
${TARGET_MOO}
|
|
||||||
>>> setVar('TARGET_MOO', 'yupp', d)
|
|
||||||
>>> print expand('${TARGET_MOO}',d)
|
|
||||||
yupp
|
|
||||||
>>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
|
|
||||||
>>> delVar('TARGET_MOO', d)
|
|
||||||
>>> print expand('${SRC_URI}', d)
|
|
||||||
http://somebug.${TARGET_MOO}
|
|
||||||
"""
|
|
||||||
return d.expand(s, varname)
|
return d.expand(s, varname)
|
||||||
|
|
||||||
def expandKeys(alterdata, readdata = None):
|
def expandKeys(alterdata, readdata = None):
|
||||||
@@ -295,38 +152,13 @@ def expandKeys(alterdata, readdata = None):
|
|||||||
continue
|
continue
|
||||||
todolist[key] = ekey
|
todolist[key] = ekey
|
||||||
|
|
||||||
# These two for loops are split for performance to maximise the
|
# These two for loops are split for performance to maximise the
|
||||||
# usefulness of the expand cache
|
# usefulness of the expand cache
|
||||||
|
|
||||||
for key in todolist:
|
for key in todolist:
|
||||||
ekey = todolist[key]
|
ekey = todolist[key]
|
||||||
renameVar(key, ekey, alterdata)
|
renameVar(key, ekey, alterdata)
|
||||||
|
|
||||||
def expandData(alterdata, readdata = None):
|
|
||||||
"""For each variable in alterdata, expand it, and update the var contents.
|
|
||||||
Replacements use data from readdata.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
>>> a=init()
|
|
||||||
>>> b=init()
|
|
||||||
>>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
|
|
||||||
>>> setVar("DL_DIR", "/path/to/whatever", b)
|
|
||||||
>>> expandData(a, b)
|
|
||||||
>>> print getVar("dlmsg", a)
|
|
||||||
dl_dir is /path/to/whatever
|
|
||||||
"""
|
|
||||||
if readdata == None:
|
|
||||||
readdata = alterdata
|
|
||||||
|
|
||||||
for key in keys(alterdata):
|
|
||||||
val = getVar(key, alterdata)
|
|
||||||
if type(val) is not types.StringType:
|
|
||||||
continue
|
|
||||||
expanded = expand(val, readdata)
|
|
||||||
# print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
|
|
||||||
if val != expanded:
|
|
||||||
setVar(key, expanded, alterdata)
|
|
||||||
|
|
||||||
def inheritFromOS(d):
|
def inheritFromOS(d):
|
||||||
"""Inherit variables from the environment."""
|
"""Inherit variables from the environment."""
|
||||||
for s in os.environ.keys():
|
for s in os.environ.keys():
|
||||||
@@ -351,21 +183,15 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
|
|||||||
if all:
|
if all:
|
||||||
oval = getVar(var, d, 0)
|
oval = getVar(var, d, 0)
|
||||||
val = getVar(var, d, 1)
|
val = getVar(var, d, 1)
|
||||||
except KeyboardInterrupt:
|
except (KeyboardInterrupt, bb.build.FuncFailed):
|
||||||
raise
|
raise
|
||||||
except:
|
except Exception, exc:
|
||||||
excname = str(sys.exc_info()[0])
|
o.write('# expansion of %s threw %s: %s\n' % (var, exc.__class__.__name__, str(exc)))
|
||||||
if excname == "bb.build.FuncFailed":
|
|
||||||
raise
|
|
||||||
o.write('# expansion of %s threw %s\n' % (var, excname))
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if all:
|
if all:
|
||||||
o.write('# %s=%s\n' % (var, oval))
|
o.write('# %s=%s\n' % (var, oval))
|
||||||
|
|
||||||
if type(val) is not types.StringType:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
|
if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -375,10 +201,11 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
|
|||||||
o.write('unset %s\n' % varExpanded)
|
o.write('unset %s\n' % varExpanded)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
val.rstrip()
|
|
||||||
if not val:
|
if not val:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
val = str(val)
|
||||||
|
|
||||||
if func:
|
if func:
|
||||||
# NOTE: should probably check for unbalanced {} within the var
|
# NOTE: should probably check for unbalanced {} within the var
|
||||||
o.write("%s() {\n%s\n}\n" % (varExpanded, val))
|
o.write("%s() {\n%s\n}\n" % (varExpanded, val))
|
||||||
@@ -393,173 +220,111 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
|
|||||||
o.write('%s="%s"\n' % (varExpanded, alter))
|
o.write('%s="%s"\n' % (varExpanded, alter))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def emit_env(o=sys.__stdout__, d = init(), all=False):
|
def emit_env(o=sys.__stdout__, d = init(), all=False):
|
||||||
"""Emits all items in the data store in a format such that it can be sourced by a shell."""
|
"""Emits all items in the data store in a format such that it can be sourced by a shell."""
|
||||||
|
|
||||||
env = keys(d)
|
isfunc = lambda key: bool(d.getVarFlag(key, "func"))
|
||||||
|
keys = sorted((key for key in d.keys() if not key.startswith("__")), key=isfunc)
|
||||||
|
grouped = groupby(keys, isfunc)
|
||||||
|
for isfunc, keys in grouped:
|
||||||
|
for key in keys:
|
||||||
|
emit_var(key, o, d, all and not isfunc) and o.write('\n')
|
||||||
|
|
||||||
for e in env:
|
def export_vars(d):
|
||||||
if getVarFlag(e, "func", d):
|
keys = (key for key in d.keys() if d.getVarFlag(key, "export"))
|
||||||
continue
|
ret = {}
|
||||||
emit_var(e, o, d, all) and o.write('\n')
|
for k in keys:
|
||||||
|
try:
|
||||||
|
v = d.getVar(k, True)
|
||||||
|
if v:
|
||||||
|
ret[k] = v
|
||||||
|
except (KeyboardInterrupt, bb.build.FuncFailed):
|
||||||
|
raise
|
||||||
|
except Exception, exc:
|
||||||
|
pass
|
||||||
|
return ret
|
||||||
|
|
||||||
for e in env:
|
def emit_func(func, o=sys.__stdout__, d = init()):
|
||||||
if not getVarFlag(e, "func", d):
|
"""Emits all items in the data store in a format such that it can be sourced by a shell."""
|
||||||
continue
|
|
||||||
emit_var(e, o, d) and o.write('\n')
|
keys = (key for key in d.keys() if not key.startswith("__") and not d.getVarFlag(key, "func"))
|
||||||
|
for key in keys:
|
||||||
|
emit_var(key, o, d, False) and o.write('\n')
|
||||||
|
|
||||||
|
emit_var(func, o, d, False) and o.write('\n')
|
||||||
|
newdeps = bb.codeparser.ShellParser().parse_shell(d.getVar(func, True))
|
||||||
|
seen = set()
|
||||||
|
while newdeps:
|
||||||
|
deps = newdeps
|
||||||
|
seen |= deps
|
||||||
|
newdeps = set()
|
||||||
|
for dep in deps:
|
||||||
|
if bb.data.getVarFlag(dep, "func", d):
|
||||||
|
emit_var(dep, o, d, False) and o.write('\n')
|
||||||
|
newdeps |= bb.codeparser.ShellParser().parse_shell(d.getVar(dep, True))
|
||||||
|
newdeps -= seen
|
||||||
|
|
||||||
def update_data(d):
|
def update_data(d):
|
||||||
"""Modifies the environment vars according to local overrides and commands.
|
"""Performs final steps upon the datastore, including application of overrides"""
|
||||||
Examples:
|
d.finalize()
|
||||||
Appending to a variable:
|
|
||||||
>>> d = init()
|
|
||||||
>>> setVar('TEST', 'this is a', d)
|
|
||||||
>>> setVar('TEST_append', ' test', d)
|
|
||||||
>>> setVar('TEST_append', ' of the emergency broadcast system.', d)
|
|
||||||
>>> update_data(d)
|
|
||||||
>>> print getVar('TEST', d)
|
|
||||||
this is a test of the emergency broadcast system.
|
|
||||||
|
|
||||||
Prepending to a variable:
|
def build_dependencies(key, keys, shelldeps, d):
|
||||||
>>> setVar('TEST', 'virtual/libc', d)
|
deps = set()
|
||||||
>>> setVar('TEST_prepend', 'virtual/tmake ', d)
|
try:
|
||||||
>>> setVar('TEST_prepend', 'virtual/patcher ', d)
|
if d.getVarFlag(key, "func"):
|
||||||
>>> update_data(d)
|
if d.getVarFlag(key, "python"):
|
||||||
>>> print getVar('TEST', d)
|
parsedvar = d.expandWithRefs(d.getVar(key, False), key)
|
||||||
virtual/patcher virtual/tmake virtual/libc
|
parser = bb.codeparser.PythonParser()
|
||||||
|
parser.parse_python(parsedvar.value)
|
||||||
|
deps = deps | parser.references
|
||||||
|
else:
|
||||||
|
parsedvar = d.expandWithRefs(d.getVar(key, False), key)
|
||||||
|
parser = bb.codeparser.ShellParser()
|
||||||
|
parser.parse_shell(parsedvar.value)
|
||||||
|
deps = deps | shelldeps
|
||||||
|
deps = deps | parsedvar.references
|
||||||
|
deps = deps | (keys & parser.execs) | (keys & parsedvar.execs)
|
||||||
|
else:
|
||||||
|
parser = d.expandWithRefs(d.getVar(key, False), key)
|
||||||
|
deps |= parser.references
|
||||||
|
deps = deps | (keys & parser.execs)
|
||||||
|
deps |= set((d.getVarFlag(key, "vardeps") or "").split())
|
||||||
|
except:
|
||||||
|
bb.note("Error expanding variable %s" % key)
|
||||||
|
raise
|
||||||
|
return deps
|
||||||
|
#bb.note("Variable %s references %s and calls %s" % (key, str(deps), str(execs)))
|
||||||
|
#d.setVarFlag(key, "vardeps", deps)
|
||||||
|
|
||||||
Overrides:
|
def generate_dependencies(d):
|
||||||
>>> setVar('TEST_arm', 'target', d)
|
|
||||||
>>> setVar('TEST_ramses', 'machine', d)
|
|
||||||
>>> setVar('TEST_local', 'local', d)
|
|
||||||
>>> setVar('OVERRIDES', 'arm', d)
|
|
||||||
|
|
||||||
>>> setVar('TEST', 'original', d)
|
keys = set(key for key in d.keys() if not key.startswith("__"))
|
||||||
>>> update_data(d)
|
shelldeps = set(key for key in keys if d.getVarFlag(key, "export") and not d.getVarFlag(key, "unexport"))
|
||||||
>>> print getVar('TEST', d)
|
|
||||||
target
|
|
||||||
|
|
||||||
>>> setVar('OVERRIDES', 'arm:ramses:local', d)
|
deps = {}
|
||||||
>>> setVar('TEST', 'original', d)
|
taskdeps = {}
|
||||||
>>> update_data(d)
|
|
||||||
>>> print getVar('TEST', d)
|
|
||||||
local
|
|
||||||
|
|
||||||
CopyMonster:
|
tasklist = bb.data.getVar('__BBTASKS', d) or []
|
||||||
>>> e = d.createCopy()
|
for task in tasklist:
|
||||||
>>> setVar('TEST_foo', 'foo', e)
|
deps[task] = build_dependencies(task, keys, shelldeps, d)
|
||||||
>>> update_data(e)
|
|
||||||
>>> print getVar('TEST', e)
|
|
||||||
local
|
|
||||||
|
|
||||||
>>> setVar('OVERRIDES', 'arm:ramses:local:foo', e)
|
|
||||||
>>> update_data(e)
|
|
||||||
>>> print getVar('TEST', e)
|
|
||||||
foo
|
|
||||||
|
|
||||||
>>> f = d.createCopy()
|
|
||||||
>>> setVar('TEST_moo', 'something', f)
|
|
||||||
>>> setVar('OVERRIDES', 'moo:arm:ramses:local:foo', e)
|
|
||||||
>>> update_data(e)
|
|
||||||
>>> print getVar('TEST', e)
|
|
||||||
foo
|
|
||||||
|
|
||||||
|
|
||||||
>>> h = init()
|
|
||||||
>>> setVar('SRC_URI', 'file://append.foo;patch=1 ', h)
|
|
||||||
>>> g = h.createCopy()
|
|
||||||
>>> setVar('SRC_URI_append_arm', 'file://other.foo;patch=1', g)
|
|
||||||
>>> setVar('OVERRIDES', 'arm:moo', g)
|
|
||||||
>>> update_data(g)
|
|
||||||
>>> print getVar('SRC_URI', g)
|
|
||||||
file://append.foo;patch=1 file://other.foo;patch=1
|
|
||||||
|
|
||||||
"""
|
|
||||||
bb.msg.debug(2, bb.msg.domain.Data, "update_data()")
|
|
||||||
|
|
||||||
# now ask the cookie monster for help
|
|
||||||
#print "Cookie Monster"
|
|
||||||
#print "Append/Prepend %s" % d._special_values
|
|
||||||
#print "Overrides %s" % d._seen_overrides
|
|
||||||
|
|
||||||
overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
|
|
||||||
|
|
||||||
#
|
|
||||||
# Well let us see what breaks here. We used to iterate
|
|
||||||
# over each variable and apply the override and then
|
|
||||||
# do the line expanding.
|
|
||||||
# If we have bad luck - which we will have - the keys
|
|
||||||
# where in some order that is so important for this
|
|
||||||
# method which we don't have anymore.
|
|
||||||
# Anyway we will fix that and write test cases this
|
|
||||||
# time.
|
|
||||||
|
|
||||||
#
|
|
||||||
# First we apply all overrides
|
|
||||||
# Then we will handle _append and _prepend
|
|
||||||
#
|
|
||||||
|
|
||||||
for o in overrides:
|
|
||||||
# calculate '_'+override
|
|
||||||
l = len(o)+1
|
|
||||||
|
|
||||||
# see if one should even try
|
|
||||||
if not d._seen_overrides.has_key(o):
|
|
||||||
continue
|
|
||||||
|
|
||||||
vars = d._seen_overrides[o]
|
|
||||||
for var in vars:
|
|
||||||
name = var[:-l]
|
|
||||||
try:
|
|
||||||
d[name] = d[var]
|
|
||||||
except:
|
|
||||||
bb.msg.note(1, bb.msg.domain.Data, "Untracked delVar")
|
|
||||||
|
|
||||||
# now on to the appends and prepends
|
|
||||||
if d._special_values.has_key('_append'):
|
|
||||||
appends = d._special_values['_append'] or []
|
|
||||||
for append in appends:
|
|
||||||
for (a, o) in getVarFlag(append, '_append', d) or []:
|
|
||||||
# maybe the OVERRIDE was not yet added so keep the append
|
|
||||||
if (o and o in overrides) or not o:
|
|
||||||
delVarFlag(append, '_append', d)
|
|
||||||
if o and not o in overrides:
|
|
||||||
continue
|
|
||||||
|
|
||||||
sval = getVar(append,d) or ""
|
|
||||||
sval+=a
|
|
||||||
setVar(append, sval, d)
|
|
||||||
|
|
||||||
|
|
||||||
if d._special_values.has_key('_prepend'):
|
|
||||||
prepends = d._special_values['_prepend'] or []
|
|
||||||
|
|
||||||
for prepend in prepends:
|
|
||||||
for (a, o) in getVarFlag(prepend, '_prepend', d) or []:
|
|
||||||
# maybe the OVERRIDE was not yet added so keep the prepend
|
|
||||||
if (o and o in overrides) or not o:
|
|
||||||
delVarFlag(prepend, '_prepend', d)
|
|
||||||
if o and not o in overrides:
|
|
||||||
continue
|
|
||||||
|
|
||||||
sval = a + (getVar(prepend,d) or "")
|
|
||||||
setVar(prepend, sval, d)
|
|
||||||
|
|
||||||
|
newdeps = deps[task]
|
||||||
|
seen = set()
|
||||||
|
while newdeps:
|
||||||
|
nextdeps = newdeps
|
||||||
|
seen |= nextdeps
|
||||||
|
newdeps = set()
|
||||||
|
for dep in nextdeps:
|
||||||
|
if dep not in deps:
|
||||||
|
deps[dep] = build_dependencies(dep, keys, shelldeps, d)
|
||||||
|
newdeps |= deps[dep]
|
||||||
|
newdeps -= seen
|
||||||
|
taskdeps[task] = seen | newdeps
|
||||||
|
#print "For %s: %s" % (task, str(taskdeps[task]))
|
||||||
|
return taskdeps, deps
|
||||||
|
|
||||||
def inherits_class(klass, d):
|
def inherits_class(klass, d):
|
||||||
val = getVar('__inherit_cache', d) or []
|
val = getVar('__inherit_cache', d) or []
|
||||||
if os.path.join('classes', '%s.bbclass' % klass) in val:
|
if os.path.join('classes', '%s.bbclass' % klass) in val:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _test():
|
|
||||||
"""Start a doctest run on this module"""
|
|
||||||
import doctest
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
bb.msg.set_debug_level(0)
|
|
||||||
doctest.testmod(data)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
_test()
|
|
||||||
|
|||||||
@@ -28,22 +28,49 @@ BitBake build tools.
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
import copy, os, re, sys, time, types
|
import copy, re, sys
|
||||||
import bb
|
import bb
|
||||||
from bb import utils, methodpool
|
from bb import utils
|
||||||
from COW import COWDictBase
|
from bb.COW import COWDictBase
|
||||||
from new import classobj
|
|
||||||
|
|
||||||
|
|
||||||
__setvar_keyword__ = ["_append","_prepend"]
|
__setvar_keyword__ = ["_append", "_prepend"]
|
||||||
__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?')
|
__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?')
|
||||||
__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
|
__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
|
||||||
__expand_python_regexp__ = re.compile(r"\${@.+?}")
|
__expand_python_regexp__ = re.compile(r"\${@.+?}")
|
||||||
_expand_globals = {
|
|
||||||
"os": os,
|
class VariableParse:
|
||||||
"bb": bb,
|
def __init__(self, varname, d, val = None):
|
||||||
"time": time,
|
self.varname = varname
|
||||||
}
|
self.d = d
|
||||||
|
self.value = val
|
||||||
|
|
||||||
|
self.references = set()
|
||||||
|
self.execs = set()
|
||||||
|
|
||||||
|
def var_sub(self, match):
|
||||||
|
key = match.group()[2:-1]
|
||||||
|
if self.varname and key:
|
||||||
|
if self.varname == key:
|
||||||
|
raise Exception("variable %s references itself!" % self.varname)
|
||||||
|
var = self.d.getVar(key, 1)
|
||||||
|
if var is not None:
|
||||||
|
self.references.add(key)
|
||||||
|
return var
|
||||||
|
else:
|
||||||
|
return match.group()
|
||||||
|
|
||||||
|
def python_sub(self, match):
|
||||||
|
code = match.group()[3:-1]
|
||||||
|
codeobj = compile(code.strip(), self.varname or "<expansion>", "eval")
|
||||||
|
|
||||||
|
parser = bb.codeparser.PythonParser()
|
||||||
|
parser.parse_python(code)
|
||||||
|
self.references |= parser.references
|
||||||
|
self.execs |= parser.execs
|
||||||
|
|
||||||
|
value = utils.better_eval(codeobj, {"d": self.d})
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
class DataSmart:
|
class DataSmart:
|
||||||
@@ -55,69 +82,121 @@ class DataSmart:
|
|||||||
self._seen_overrides = seen
|
self._seen_overrides = seen
|
||||||
|
|
||||||
self.expand_cache = {}
|
self.expand_cache = {}
|
||||||
self.expand_locals = {"d": self}
|
|
||||||
|
|
||||||
def expand(self,s, varname):
|
def expandWithRefs(self, s, varname):
|
||||||
def var_sub(match):
|
|
||||||
key = match.group()[2:-1]
|
|
||||||
if varname and key:
|
|
||||||
if varname == key:
|
|
||||||
raise Exception("variable %s references itself!" % varname)
|
|
||||||
var = self.getVar(key, 1)
|
|
||||||
if var is not None:
|
|
||||||
return var
|
|
||||||
else:
|
|
||||||
return match.group()
|
|
||||||
|
|
||||||
def python_sub(match):
|
if not isinstance(s, basestring): # sanity check
|
||||||
import bb
|
return VariableParse(varname, self, s)
|
||||||
code = match.group()[3:-1]
|
|
||||||
s = eval(code, _expand_globals, self.expand_locals)
|
|
||||||
if type(s) == types.IntType: s = str(s)
|
|
||||||
return s
|
|
||||||
|
|
||||||
if type(s) is not types.StringType: # sanity check
|
|
||||||
return s
|
|
||||||
|
|
||||||
if varname and varname in self.expand_cache:
|
if varname and varname in self.expand_cache:
|
||||||
return self.expand_cache[varname]
|
return self.expand_cache[varname]
|
||||||
|
|
||||||
|
varparse = VariableParse(varname, self)
|
||||||
|
|
||||||
while s.find('${') != -1:
|
while s.find('${') != -1:
|
||||||
olds = s
|
olds = s
|
||||||
try:
|
try:
|
||||||
s = __expand_var_regexp__.sub(var_sub, s)
|
s = __expand_var_regexp__.sub(varparse.var_sub, s)
|
||||||
s = __expand_python_regexp__.sub(python_sub, s)
|
s = __expand_python_regexp__.sub(varparse.python_sub, s)
|
||||||
if s == olds: break
|
if s == olds:
|
||||||
if type(s) is not types.StringType: # sanity check
|
break
|
||||||
bb.msg.error(bb.msg.domain.Data, 'expansion of %s returned non-string %s' % (olds, s))
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
bb.msg.note(1, bb.msg.domain.Data, "%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
|
bb.msg.note(1, bb.msg.domain.Data, "%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if varname:
|
varparse.value = s
|
||||||
self.expand_cache[varname] = s
|
|
||||||
|
|
||||||
return s
|
if varname:
|
||||||
|
self.expand_cache[varname] = varparse
|
||||||
|
|
||||||
|
return varparse
|
||||||
|
|
||||||
|
def expand(self, s, varname):
|
||||||
|
return self.expandWithRefs(s, varname).value
|
||||||
|
|
||||||
|
|
||||||
|
def finalize(self):
|
||||||
|
"""Performs final steps upon the datastore, including application of overrides"""
|
||||||
|
|
||||||
|
overrides = (self.getVar("OVERRIDES", True) or "").split(":") or []
|
||||||
|
|
||||||
|
#
|
||||||
|
# Well let us see what breaks here. We used to iterate
|
||||||
|
# over each variable and apply the override and then
|
||||||
|
# do the line expanding.
|
||||||
|
# If we have bad luck - which we will have - the keys
|
||||||
|
# where in some order that is so important for this
|
||||||
|
# method which we don't have anymore.
|
||||||
|
# Anyway we will fix that and write test cases this
|
||||||
|
# time.
|
||||||
|
|
||||||
|
#
|
||||||
|
# First we apply all overrides
|
||||||
|
# Then we will handle _append and _prepend
|
||||||
|
#
|
||||||
|
|
||||||
|
for o in overrides:
|
||||||
|
# calculate '_'+override
|
||||||
|
l = len(o) + 1
|
||||||
|
|
||||||
|
# see if one should even try
|
||||||
|
if o not in self._seen_overrides:
|
||||||
|
continue
|
||||||
|
|
||||||
|
vars = self._seen_overrides[o]
|
||||||
|
for var in vars:
|
||||||
|
name = var[:-l]
|
||||||
|
try:
|
||||||
|
self[name] = self[var]
|
||||||
|
except Exception:
|
||||||
|
bb.msg.note(1, bb.msg.domain.Data, "Untracked delVar")
|
||||||
|
|
||||||
|
# now on to the appends and prepends
|
||||||
|
if "_append" in self._special_values:
|
||||||
|
appends = self._special_values["_append"] or []
|
||||||
|
for append in appends:
|
||||||
|
for (a, o) in self.getVarFlag(append, "_append") or []:
|
||||||
|
# maybe the OVERRIDE was not yet added so keep the append
|
||||||
|
if (o and o in overrides) or not o:
|
||||||
|
self.delVarFlag(append, "_append")
|
||||||
|
if o and not o in overrides:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sval = self.getVar(append, False) or ""
|
||||||
|
sval += a
|
||||||
|
self.setVar(append, sval)
|
||||||
|
|
||||||
|
|
||||||
|
if "_prepend" in self._special_values:
|
||||||
|
prepends = self._special_values["_prepend"] or []
|
||||||
|
|
||||||
|
for prepend in prepends:
|
||||||
|
for (a, o) in self.getVarFlag(prepend, "_prepend") or []:
|
||||||
|
# maybe the OVERRIDE was not yet added so keep the prepend
|
||||||
|
if (o and o in overrides) or not o:
|
||||||
|
self.delVarFlag(prepend, "_prepend")
|
||||||
|
if o and not o in overrides:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sval = a + (self.getVar(prepend, False) or "")
|
||||||
|
self.setVar(prepend, sval)
|
||||||
|
|
||||||
def initVar(self, var):
|
def initVar(self, var):
|
||||||
self.expand_cache = {}
|
self.expand_cache = {}
|
||||||
if not var in self.dict:
|
if not var in self.dict:
|
||||||
self.dict[var] = {}
|
self.dict[var] = {}
|
||||||
|
|
||||||
def _findVar(self,var):
|
def _findVar(self, var):
|
||||||
_dest = self.dict
|
dest = self.dict
|
||||||
|
while dest:
|
||||||
|
if var in dest:
|
||||||
|
return dest[var]
|
||||||
|
|
||||||
while (_dest and var not in _dest):
|
if "_data" not in dest:
|
||||||
if not "_data" in _dest:
|
|
||||||
_dest = None
|
|
||||||
break
|
break
|
||||||
_dest = _dest["_data"]
|
dest = dest["_data"]
|
||||||
|
|
||||||
if _dest and var in _dest:
|
|
||||||
return _dest[var]
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _makeShadowCopy(self, var):
|
def _makeShadowCopy(self, var):
|
||||||
if var in self.dict:
|
if var in self.dict:
|
||||||
@@ -130,7 +209,7 @@ class DataSmart:
|
|||||||
else:
|
else:
|
||||||
self.initVar(var)
|
self.initVar(var)
|
||||||
|
|
||||||
def setVar(self,var,value):
|
def setVar(self, var, value):
|
||||||
self.expand_cache = {}
|
self.expand_cache = {}
|
||||||
match = __setvar_regexp__.match(var)
|
match = __setvar_regexp__.match(var)
|
||||||
if match and match.group("keyword") in __setvar_keyword__:
|
if match and match.group("keyword") in __setvar_keyword__:
|
||||||
@@ -145,7 +224,7 @@ class DataSmart:
|
|||||||
# pay the cookie monster
|
# pay the cookie monster
|
||||||
try:
|
try:
|
||||||
self._special_values[keyword].add( base )
|
self._special_values[keyword].add( base )
|
||||||
except:
|
except KeyError:
|
||||||
self._special_values[keyword] = set()
|
self._special_values[keyword] = set()
|
||||||
self._special_values[keyword].add( base )
|
self._special_values[keyword].add( base )
|
||||||
|
|
||||||
@@ -157,23 +236,23 @@ class DataSmart:
|
|||||||
# more cookies for the cookie monster
|
# more cookies for the cookie monster
|
||||||
if '_' in var:
|
if '_' in var:
|
||||||
override = var[var.rfind('_')+1:]
|
override = var[var.rfind('_')+1:]
|
||||||
if not self._seen_overrides.has_key(override):
|
if override not in self._seen_overrides:
|
||||||
self._seen_overrides[override] = set()
|
self._seen_overrides[override] = set()
|
||||||
self._seen_overrides[override].add( var )
|
self._seen_overrides[override].add( var )
|
||||||
|
|
||||||
# setting var
|
# setting var
|
||||||
self.dict[var]["content"] = value
|
self.dict[var]["content"] = value
|
||||||
|
|
||||||
def getVar(self,var,exp):
|
def getVar(self, var, exp):
|
||||||
value = self.getVarFlag(var,"content")
|
value = self.getVarFlag(var, "content")
|
||||||
|
|
||||||
if exp and value:
|
if exp and value:
|
||||||
return self.expand(value,var)
|
return self.expand(value, var)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def renameVar(self, key, newkey):
|
def renameVar(self, key, newkey):
|
||||||
"""
|
"""
|
||||||
Rename the variable key to newkey
|
Rename the variable key to newkey
|
||||||
"""
|
"""
|
||||||
val = self.getVar(key, 0)
|
val = self.getVar(key, 0)
|
||||||
if val is not None:
|
if val is not None:
|
||||||
@@ -187,30 +266,30 @@ class DataSmart:
|
|||||||
dest = self.getVarFlag(newkey, i) or []
|
dest = self.getVarFlag(newkey, i) or []
|
||||||
dest.extend(src)
|
dest.extend(src)
|
||||||
self.setVarFlag(newkey, i, dest)
|
self.setVarFlag(newkey, i, dest)
|
||||||
|
|
||||||
if self._special_values.has_key(i) and key in self._special_values[i]:
|
if i in self._special_values and key in self._special_values[i]:
|
||||||
self._special_values[i].remove(key)
|
self._special_values[i].remove(key)
|
||||||
self._special_values[i].add(newkey)
|
self._special_values[i].add(newkey)
|
||||||
|
|
||||||
self.delVar(key)
|
self.delVar(key)
|
||||||
|
|
||||||
def delVar(self,var):
|
def delVar(self, var):
|
||||||
self.expand_cache = {}
|
self.expand_cache = {}
|
||||||
self.dict[var] = {}
|
self.dict[var] = {}
|
||||||
|
|
||||||
def setVarFlag(self,var,flag,flagvalue):
|
def setVarFlag(self, var, flag, flagvalue):
|
||||||
if not var in self.dict:
|
if not var in self.dict:
|
||||||
self._makeShadowCopy(var)
|
self._makeShadowCopy(var)
|
||||||
self.dict[var][flag] = flagvalue
|
self.dict[var][flag] = flagvalue
|
||||||
|
|
||||||
def getVarFlag(self,var,flag):
|
def getVarFlag(self, var, flag):
|
||||||
local_var = self._findVar(var)
|
local_var = self._findVar(var)
|
||||||
if local_var:
|
if local_var:
|
||||||
if flag in local_var:
|
if flag in local_var:
|
||||||
return copy.copy(local_var[flag])
|
return copy.copy(local_var[flag])
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def delVarFlag(self,var,flag):
|
def delVarFlag(self, var, flag):
|
||||||
local_var = self._findVar(var)
|
local_var = self._findVar(var)
|
||||||
if not local_var:
|
if not local_var:
|
||||||
return
|
return
|
||||||
@@ -220,7 +299,7 @@ class DataSmart:
|
|||||||
if var in self.dict and flag in self.dict[var]:
|
if var in self.dict and flag in self.dict[var]:
|
||||||
del self.dict[var][flag]
|
del self.dict[var][flag]
|
||||||
|
|
||||||
def setVarFlags(self,var,flags):
|
def setVarFlags(self, var, flags):
|
||||||
if not var in self.dict:
|
if not var in self.dict:
|
||||||
self._makeShadowCopy(var)
|
self._makeShadowCopy(var)
|
||||||
|
|
||||||
@@ -229,7 +308,7 @@ class DataSmart:
|
|||||||
continue
|
continue
|
||||||
self.dict[var][i] = flags[i]
|
self.dict[var][i] = flags[i]
|
||||||
|
|
||||||
def getVarFlags(self,var):
|
def getVarFlags(self, var):
|
||||||
local_var = self._findVar(var)
|
local_var = self._findVar(var)
|
||||||
flags = {}
|
flags = {}
|
||||||
|
|
||||||
@@ -244,7 +323,7 @@ class DataSmart:
|
|||||||
return flags
|
return flags
|
||||||
|
|
||||||
|
|
||||||
def delVarFlags(self,var):
|
def delVarFlags(self, var):
|
||||||
if not var in self.dict:
|
if not var in self.dict:
|
||||||
self._makeShadowCopy(var)
|
self._makeShadowCopy(var)
|
||||||
|
|
||||||
@@ -274,21 +353,19 @@ class DataSmart:
|
|||||||
def keys(self):
|
def keys(self):
|
||||||
def _keys(d, mykey):
|
def _keys(d, mykey):
|
||||||
if "_data" in d:
|
if "_data" in d:
|
||||||
_keys(d["_data"],mykey)
|
_keys(d["_data"], mykey)
|
||||||
|
|
||||||
for key in d.keys():
|
for key in d.keys():
|
||||||
if key != "_data":
|
if key != "_data":
|
||||||
mykey[key] = None
|
mykey[key] = None
|
||||||
keytab = {}
|
keytab = {}
|
||||||
_keys(self.dict,keytab)
|
_keys(self.dict, keytab)
|
||||||
return keytab.keys()
|
return keytab.keys()
|
||||||
|
|
||||||
def __getitem__(self,item):
|
def __getitem__(self, item):
|
||||||
#print "Warning deprecated"
|
#print "Warning deprecated"
|
||||||
return self.getVar(item, False)
|
return self.getVar(item, False)
|
||||||
|
|
||||||
def __setitem__(self,var,data):
|
def __setitem__(self, var, data):
|
||||||
#print "Warning deprecated"
|
#print "Warning deprecated"
|
||||||
self.setVar(var,data)
|
self.setVar(var, data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ BitBake build tools.
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import os, re, sys
|
import os, sys
|
||||||
|
import warnings
|
||||||
import bb.utils
|
import bb.utils
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ import pickle
|
|||||||
# the runqueue forks off.
|
# the runqueue forks off.
|
||||||
worker_pid = 0
|
worker_pid = 0
|
||||||
worker_pipe = None
|
worker_pipe = None
|
||||||
|
useStdout = True
|
||||||
|
|
||||||
class Event:
|
class Event:
|
||||||
"""Base class for events"""
|
"""Base class for events"""
|
||||||
@@ -38,7 +40,7 @@ class Event:
|
|||||||
self.pid = worker_pid
|
self.pid = worker_pid
|
||||||
|
|
||||||
NotHandled = 0
|
NotHandled = 0
|
||||||
Handled = 1
|
Handled = 1
|
||||||
|
|
||||||
Registered = 10
|
Registered = 10
|
||||||
AlreadyRegistered = 14
|
AlreadyRegistered = 14
|
||||||
@@ -48,13 +50,25 @@ _handlers = {}
|
|||||||
_ui_handlers = {}
|
_ui_handlers = {}
|
||||||
_ui_handler_seq = 0
|
_ui_handler_seq = 0
|
||||||
|
|
||||||
|
# For compatibility
|
||||||
|
bb.utils._context["NotHandled"] = NotHandled
|
||||||
|
bb.utils._context["Handled"] = Handled
|
||||||
|
|
||||||
def fire_class_handlers(event, d):
|
def fire_class_handlers(event, d):
|
||||||
|
import bb.msg
|
||||||
|
if isinstance(event, bb.msg.MsgBase):
|
||||||
|
return
|
||||||
|
|
||||||
for handler in _handlers:
|
for handler in _handlers:
|
||||||
h = _handlers[handler]
|
h = _handlers[handler]
|
||||||
event.data = d
|
event.data = d
|
||||||
if type(h).__name__ == "code":
|
if type(h).__name__ == "code":
|
||||||
exec(h)
|
locals = {"e": event}
|
||||||
tmpHandler(event)
|
bb.utils.simple_exec(h, locals)
|
||||||
|
ret = bb.utils.better_eval("tmpHandler(e)", locals)
|
||||||
|
if ret is not None:
|
||||||
|
warnings.warn("Using Handled/NotHandled in event handlers is deprecated",
|
||||||
|
DeprecationWarning, stacklevel = 2)
|
||||||
else:
|
else:
|
||||||
h(event)
|
h(event)
|
||||||
del event.data
|
del event.data
|
||||||
@@ -76,9 +90,9 @@ def fire_ui_handlers(event, d):
|
|||||||
def fire(event, d):
|
def fire(event, d):
|
||||||
"""Fire off an Event"""
|
"""Fire off an Event"""
|
||||||
|
|
||||||
# We can fire class handlers in the worker process context and this is
|
# We can fire class handlers in the worker process context and this is
|
||||||
# desired so they get the task based datastore.
|
# desired so they get the task based datastore.
|
||||||
# UI handlers need to be fired in the server context so we defer this. They
|
# UI handlers need to be fired in the server context so we defer this. They
|
||||||
# don't have a datastore so the datastore context isn't a problem.
|
# don't have a datastore so the datastore context isn't a problem.
|
||||||
|
|
||||||
fire_class_handlers(event, d)
|
fire_class_handlers(event, d)
|
||||||
@@ -89,16 +103,14 @@ def fire(event, d):
|
|||||||
|
|
||||||
def worker_fire(event, d):
|
def worker_fire(event, d):
|
||||||
data = "<event>" + pickle.dumps(event) + "</event>"
|
data = "<event>" + pickle.dumps(event) + "</event>"
|
||||||
try:
|
worker_pipe.write(data)
|
||||||
if os.write(worker_pipe, data) != len (data):
|
worker_pipe.flush()
|
||||||
print "Error sending event to server (short write)"
|
|
||||||
except OSError:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def fire_from_worker(event, d):
|
def fire_from_worker(event, d):
|
||||||
if not event.startswith("<event>") or not event.endswith("</event>"):
|
if not event.startswith("<event>") or not event.endswith("</event>"):
|
||||||
print "Error, not an event"
|
print("Error, not an event %s" % event)
|
||||||
return
|
return
|
||||||
|
#print "Got event %s" % event
|
||||||
event = pickle.loads(event[7:-8])
|
event = pickle.loads(event[7:-8])
|
||||||
fire_ui_handlers(event, d)
|
fire_ui_handlers(event, d)
|
||||||
|
|
||||||
@@ -127,6 +139,7 @@ def remove(name, handler):
|
|||||||
def register_UIHhandler(handler):
|
def register_UIHhandler(handler):
|
||||||
bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
|
bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
|
||||||
_ui_handlers[_ui_handler_seq] = handler
|
_ui_handlers[_ui_handler_seq] = handler
|
||||||
|
bb.event.useStdout = False
|
||||||
return _ui_handler_seq
|
return _ui_handler_seq
|
||||||
|
|
||||||
def unregister_UIHhandler(handlerNum):
|
def unregister_UIHhandler(handlerNum):
|
||||||
@@ -222,10 +235,11 @@ class BuildCompleted(BuildBase):
|
|||||||
class NoProvider(Event):
|
class NoProvider(Event):
|
||||||
"""No Provider for an Event"""
|
"""No Provider for an Event"""
|
||||||
|
|
||||||
def __init__(self, item, runtime=False):
|
def __init__(self, item, runtime=False, dependees=None):
|
||||||
Event.__init__(self)
|
Event.__init__(self)
|
||||||
self._item = item
|
self._item = item
|
||||||
self._runtime = runtime
|
self._runtime = runtime
|
||||||
|
self._dependees = dependees
|
||||||
|
|
||||||
def getItem(self):
|
def getItem(self):
|
||||||
return self._item
|
return self._item
|
||||||
@@ -284,4 +298,3 @@ class DepTreeGenerated(Event):
|
|||||||
def __init__(self, depgraph):
|
def __init__(self, depgraph):
|
||||||
Event.__init__(self)
|
Event.__init__(self)
|
||||||
self._depgraph = depgraph
|
self._depgraph = depgraph
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ BitBake build tools.
|
|||||||
#
|
#
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import print_function
|
||||||
import os, re
|
import os, re
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
@@ -53,24 +55,6 @@ class InvalidSRCREV(Exception):
|
|||||||
def decodeurl(url):
|
def decodeurl(url):
|
||||||
"""Decodes an URL into the tokens (scheme, network location, path,
|
"""Decodes an URL into the tokens (scheme, network location, path,
|
||||||
user, password, parameters).
|
user, password, parameters).
|
||||||
|
|
||||||
>>> decodeurl("http://www.google.com/index.html")
|
|
||||||
('http', 'www.google.com', '/index.html', '', '', {})
|
|
||||||
|
|
||||||
>>> decodeurl("file://gas/COPYING")
|
|
||||||
('file', '', 'gas/COPYING', '', '', {})
|
|
||||||
|
|
||||||
CVS url with username, host and cvsroot. The cvs module to check out is in the
|
|
||||||
parameters:
|
|
||||||
|
|
||||||
>>> decodeurl("cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg")
|
|
||||||
('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', '', {'module': 'familiar/dist/ipkg'})
|
|
||||||
|
|
||||||
Dito, but this time the username has a password part. And we also request a special tag
|
|
||||||
to check out.
|
|
||||||
|
|
||||||
>>> decodeurl("cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;module=familiar/dist/ipkg;tag=V0-99-81")
|
|
||||||
('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'})
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
m = re.compile('(?P<type>[^:]*)://((?P<user>.+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url)
|
m = re.compile('(?P<type>[^:]*)://((?P<user>.+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url)
|
||||||
@@ -103,7 +87,7 @@ def decodeurl(url):
|
|||||||
p = {}
|
p = {}
|
||||||
if parm:
|
if parm:
|
||||||
for s in parm.split(';'):
|
for s in parm.split(';'):
|
||||||
s1,s2 = s.split('=')
|
s1, s2 = s.split('=')
|
||||||
p[s1] = s2
|
p[s1] = s2
|
||||||
|
|
||||||
return (type, host, path, user, pswd, p)
|
return (type, host, path, user, pswd, p)
|
||||||
@@ -111,27 +95,12 @@ def decodeurl(url):
|
|||||||
def encodeurl(decoded):
|
def encodeurl(decoded):
|
||||||
"""Encodes a URL from tokens (scheme, network location, path,
|
"""Encodes a URL from tokens (scheme, network location, path,
|
||||||
user, password, parameters).
|
user, password, parameters).
|
||||||
|
|
||||||
>>> encodeurl(['http', 'www.google.com', '/index.html', '', '', {}])
|
|
||||||
'http://www.google.com/index.html'
|
|
||||||
|
|
||||||
CVS with username, host and cvsroot. The cvs module to check out is in the
|
|
||||||
parameters:
|
|
||||||
|
|
||||||
>>> encodeurl(['cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', '', {'module': 'familiar/dist/ipkg'}])
|
|
||||||
'cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg'
|
|
||||||
|
|
||||||
Dito, but this time the username has a password part. And we also request a special tag
|
|
||||||
to check out.
|
|
||||||
|
|
||||||
>>> encodeurl(['cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'}])
|
|
||||||
'cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;tag=V0-99-81;module=familiar/dist/ipkg'
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
(type, host, path, user, pswd, p) = decoded
|
(type, host, path, user, pswd, p) = decoded
|
||||||
|
|
||||||
if not type or not path:
|
if not type or not path:
|
||||||
bb.msg.fatal(bb.msg.domain.Fetcher, "invalid or missing parameters for url encoding")
|
raise MissingParameterError("Type or path url components missing when encoding %s" % decoded)
|
||||||
url = '%s://' % type
|
url = '%s://' % type
|
||||||
if user:
|
if user:
|
||||||
url += "%s" % user
|
url += "%s" % user
|
||||||
@@ -151,15 +120,14 @@ def uri_replace(uri, uri_find, uri_replace, d):
|
|||||||
# bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: operating on %s" % uri)
|
# bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: operating on %s" % uri)
|
||||||
if not uri or not uri_find or not uri_replace:
|
if not uri or not uri_find or not uri_replace:
|
||||||
bb.msg.debug(1, bb.msg.domain.Fetcher, "uri_replace: passed an undefined value, not replacing")
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "uri_replace: passed an undefined value, not replacing")
|
||||||
uri_decoded = list(bb.decodeurl(uri))
|
uri_decoded = list(decodeurl(uri))
|
||||||
uri_find_decoded = list(bb.decodeurl(uri_find))
|
uri_find_decoded = list(decodeurl(uri_find))
|
||||||
uri_replace_decoded = list(bb.decodeurl(uri_replace))
|
uri_replace_decoded = list(decodeurl(uri_replace))
|
||||||
result_decoded = ['','','','','',{}]
|
result_decoded = ['', '', '', '', '', {}]
|
||||||
for i in uri_find_decoded:
|
for i in uri_find_decoded:
|
||||||
loc = uri_find_decoded.index(i)
|
loc = uri_find_decoded.index(i)
|
||||||
result_decoded[loc] = uri_decoded[loc]
|
result_decoded[loc] = uri_decoded[loc]
|
||||||
import types
|
if isinstance(i, basestring):
|
||||||
if type(i) == types.StringType:
|
|
||||||
if (re.match(i, uri_decoded[loc])):
|
if (re.match(i, uri_decoded[loc])):
|
||||||
result_decoded[loc] = re.sub(i, uri_replace_decoded[loc], uri_decoded[loc])
|
result_decoded[loc] = re.sub(i, uri_replace_decoded[loc], uri_decoded[loc])
|
||||||
if uri_find_decoded.index(i) == 2:
|
if uri_find_decoded.index(i) == 2:
|
||||||
@@ -174,19 +142,20 @@ def uri_replace(uri, uri_find, uri_replace, d):
|
|||||||
# else:
|
# else:
|
||||||
# for j in i:
|
# for j in i:
|
||||||
# FIXME: apply replacements against options
|
# FIXME: apply replacements against options
|
||||||
return bb.encodeurl(result_decoded)
|
return encodeurl(result_decoded)
|
||||||
|
|
||||||
methods = []
|
methods = []
|
||||||
urldata_cache = {}
|
urldata_cache = {}
|
||||||
saved_headrevs = {}
|
saved_headrevs = {}
|
||||||
|
persistent_database_connection = {}
|
||||||
|
|
||||||
def fetcher_init(d):
|
def fetcher_init(d):
|
||||||
"""
|
"""
|
||||||
Called to initilize the fetchers once the configuration data is known
|
Called to initialize the fetchers once the configuration data is known.
|
||||||
Calls before this must not hit the cache.
|
Calls before this must not hit the cache.
|
||||||
"""
|
"""
|
||||||
pd = persist_data.PersistData(d)
|
pd = persist_data.PersistData(d, persistent_database_connection)
|
||||||
# When to drop SCM head revisions controled by user policy
|
# When to drop SCM head revisions controlled by user policy
|
||||||
srcrev_policy = bb.data.getVar('BB_SRCREV_POLICY', d, 1) or "clear"
|
srcrev_policy = bb.data.getVar('BB_SRCREV_POLICY', d, 1) or "clear"
|
||||||
if srcrev_policy == "cache":
|
if srcrev_policy == "cache":
|
||||||
bb.msg.debug(1, bb.msg.domain.Fetcher, "Keeping SRCREV cache due to cache policy of: %s" % srcrev_policy)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Keeping SRCREV cache due to cache policy of: %s" % srcrev_policy)
|
||||||
@@ -198,7 +167,7 @@ def fetcher_init(d):
|
|||||||
pass
|
pass
|
||||||
pd.delDomain("BB_URI_HEADREVS")
|
pd.delDomain("BB_URI_HEADREVS")
|
||||||
else:
|
else:
|
||||||
bb.msg.fatal(bb.msg.domain.Fetcher, "Invalid SRCREV cache policy of: %s" % srcrev_policy)
|
raise FetchError("Invalid SRCREV cache policy of: %s" % srcrev_policy)
|
||||||
|
|
||||||
for m in methods:
|
for m in methods:
|
||||||
if hasattr(m, "init"):
|
if hasattr(m, "init"):
|
||||||
@@ -214,7 +183,7 @@ def fetcher_compare_revisons(d):
|
|||||||
return true/false on whether they've changed.
|
return true/false on whether they've changed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pd = persist_data.PersistData(d)
|
pd = persist_data.PersistData(d, persistent_database_connection)
|
||||||
data = pd.getKeyValues("BB_URI_HEADREVS")
|
data = pd.getKeyValues("BB_URI_HEADREVS")
|
||||||
data2 = bb.fetch.saved_headrevs
|
data2 = bb.fetch.saved_headrevs
|
||||||
|
|
||||||
@@ -236,6 +205,7 @@ def fetcher_compare_revisons(d):
|
|||||||
|
|
||||||
def init(urls, d, setup = True):
|
def init(urls, d, setup = True):
|
||||||
urldata = {}
|
urldata = {}
|
||||||
|
|
||||||
fn = bb.data.getVar('FILE', d, 1)
|
fn = bb.data.getVar('FILE', d, 1)
|
||||||
if fn in urldata_cache:
|
if fn in urldata_cache:
|
||||||
urldata = urldata_cache[fn]
|
urldata = urldata_cache[fn]
|
||||||
@@ -247,11 +217,20 @@ def init(urls, d, setup = True):
|
|||||||
if setup:
|
if setup:
|
||||||
for url in urldata:
|
for url in urldata:
|
||||||
if not urldata[url].setup:
|
if not urldata[url].setup:
|
||||||
urldata[url].setup_localpath(d)
|
urldata[url].setup_localpath(d)
|
||||||
|
|
||||||
urldata_cache[fn] = urldata
|
urldata_cache[fn] = urldata
|
||||||
return urldata
|
return urldata
|
||||||
|
|
||||||
|
def mirror_from_string(data):
|
||||||
|
return [ i.split() for i in (data or "").replace('\\n','\n').split('\n') if i ]
|
||||||
|
|
||||||
|
def removefile(f):
|
||||||
|
try:
|
||||||
|
os.remove(f)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
def go(d, urls = None):
|
def go(d, urls = None):
|
||||||
"""
|
"""
|
||||||
Fetch all urls
|
Fetch all urls
|
||||||
@@ -264,49 +243,47 @@ def go(d, urls = None):
|
|||||||
for u in urls:
|
for u in urls:
|
||||||
ud = urldata[u]
|
ud = urldata[u]
|
||||||
m = ud.method
|
m = ud.method
|
||||||
if ud.localfile:
|
localpath = ""
|
||||||
if not m.forcefetch(u, ud, d) and os.path.exists(ud.md5):
|
|
||||||
# File already present along with md5 stamp file
|
|
||||||
# Touch md5 file to show activity
|
|
||||||
try:
|
|
||||||
os.utime(ud.md5, None)
|
|
||||||
except:
|
|
||||||
# Errors aren't fatal here
|
|
||||||
pass
|
|
||||||
continue
|
|
||||||
lf = bb.utils.lockfile(ud.lockfile)
|
|
||||||
if not m.forcefetch(u, ud, d) and os.path.exists(ud.md5):
|
|
||||||
# If someone else fetched this before we got the lock,
|
|
||||||
# notice and don't try again
|
|
||||||
try:
|
|
||||||
os.utime(ud.md5, None)
|
|
||||||
except:
|
|
||||||
# Errors aren't fatal here
|
|
||||||
pass
|
|
||||||
bb.utils.unlockfile(lf)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# First try fetching uri, u, from PREMIRRORS
|
if not ud.localfile:
|
||||||
mirrors = [ i.split() for i in (bb.data.getVar('PREMIRRORS', d, 1) or "").split('\n') if i ]
|
continue
|
||||||
localpath = try_mirrors(d, u, mirrors)
|
|
||||||
if not localpath:
|
lf = bb.utils.lockfile(ud.lockfile)
|
||||||
|
|
||||||
|
if m.try_premirror(u, ud, d):
|
||||||
|
# First try fetching uri, u, from PREMIRRORS
|
||||||
|
mirrors = mirror_from_string(bb.data.getVar('PREMIRRORS', d, True))
|
||||||
|
localpath = try_mirrors(d, u, mirrors, False, m.forcefetch(u, ud, d))
|
||||||
|
elif os.path.exists(ud.localfile):
|
||||||
|
localpath = ud.localfile
|
||||||
|
|
||||||
|
# Need to re-test forcefetch() which will return true if our copy is too old
|
||||||
|
if m.forcefetch(u, ud, d) or not localpath:
|
||||||
# Next try fetching from the original uri, u
|
# Next try fetching from the original uri, u
|
||||||
try:
|
try:
|
||||||
m.go(u, ud, d)
|
m.go(u, ud, d)
|
||||||
localpath = ud.localpath
|
localpath = ud.localpath
|
||||||
except:
|
except FetchError:
|
||||||
|
# Remove any incomplete file
|
||||||
|
removefile(ud.localpath)
|
||||||
# Finally, try fetching uri, u, from MIRRORS
|
# Finally, try fetching uri, u, from MIRRORS
|
||||||
mirrors = [ i.split() for i in (bb.data.getVar('MIRRORS', d, 1) or "").split('\n') if i ]
|
mirrors = mirror_from_string(bb.data.getVar('MIRRORS', d, True))
|
||||||
localpath = try_mirrors (d, u, mirrors)
|
localpath = try_mirrors (d, u, mirrors)
|
||||||
|
if not localpath or not os.path.exists(localpath):
|
||||||
|
raise FetchError("Unable to fetch URL %s from any source." % u)
|
||||||
|
|
||||||
if localpath:
|
ud.localpath = localpath
|
||||||
ud.localpath = localpath
|
if os.path.exists(ud.md5):
|
||||||
|
# Touch the md5 file to show active use of the download
|
||||||
if ud.localfile:
|
try:
|
||||||
if not m.forcefetch(u, ud, d):
|
os.utime(ud.md5, None)
|
||||||
Fetch.write_md5sum(u, ud, d)
|
except:
|
||||||
bb.utils.unlockfile(lf)
|
# Errors aren't fatal here
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
Fetch.write_md5sum(u, ud, d)
|
||||||
|
|
||||||
|
bb.utils.unlockfile(lf)
|
||||||
|
|
||||||
def checkstatus(d):
|
def checkstatus(d):
|
||||||
"""
|
"""
|
||||||
@@ -318,9 +295,9 @@ def checkstatus(d):
|
|||||||
for u in urldata:
|
for u in urldata:
|
||||||
ud = urldata[u]
|
ud = urldata[u]
|
||||||
m = ud.method
|
m = ud.method
|
||||||
bb.msg.note(1, bb.msg.domain.Fetcher, "Testing URL %s" % u)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Testing URL %s" % u)
|
||||||
# First try checking uri, u, from PREMIRRORS
|
# First try checking uri, u, from PREMIRRORS
|
||||||
mirrors = [ i.split() for i in (bb.data.getVar('PREMIRRORS', d, 1) or "").split('\n') if i ]
|
mirrors = mirror_from_string(bb.data.getVar('PREMIRRORS', d, True))
|
||||||
ret = try_mirrors(d, u, mirrors, True)
|
ret = try_mirrors(d, u, mirrors, True)
|
||||||
if not ret:
|
if not ret:
|
||||||
# Next try checking from the original uri, u
|
# Next try checking from the original uri, u
|
||||||
@@ -328,11 +305,11 @@ def checkstatus(d):
|
|||||||
ret = m.checkstatus(u, ud, d)
|
ret = m.checkstatus(u, ud, d)
|
||||||
except:
|
except:
|
||||||
# Finally, try checking uri, u, from MIRRORS
|
# Finally, try checking uri, u, from MIRRORS
|
||||||
mirrors = [ i.split() for i in (bb.data.getVar('MIRRORS', d, 1) or "").split('\n') if i ]
|
mirrors = mirror_from_string(bb.data.getVar('MIRRORS', d, True))
|
||||||
ret = try_mirrors (d, u, mirrors, True)
|
ret = try_mirrors (d, u, mirrors, True)
|
||||||
|
|
||||||
if not ret:
|
if not ret:
|
||||||
bb.msg.error(bb.msg.domain.Fetcher, "URL %s doesn't work" % u)
|
raise FetchError("URL %s doesn't work" % u)
|
||||||
|
|
||||||
def localpaths(d):
|
def localpaths(d):
|
||||||
"""
|
"""
|
||||||
@@ -342,7 +319,7 @@ def localpaths(d):
|
|||||||
urldata = init([], d, True)
|
urldata = init([], d, True)
|
||||||
|
|
||||||
for u in urldata:
|
for u in urldata:
|
||||||
ud = urldata[u]
|
ud = urldata[u]
|
||||||
local.append(ud.localpath)
|
local.append(ud.localpath)
|
||||||
|
|
||||||
return local
|
return local
|
||||||
@@ -354,15 +331,15 @@ def get_srcrev(d):
|
|||||||
Return the version string for the current package
|
Return the version string for the current package
|
||||||
(usually to be used as PV)
|
(usually to be used as PV)
|
||||||
Most packages usually only have one SCM so we just pass on the call.
|
Most packages usually only have one SCM so we just pass on the call.
|
||||||
In the multi SCM case, we build a value based on SRCREV_FORMAT which must
|
In the multi SCM case, we build a value based on SRCREV_FORMAT which must
|
||||||
have been set.
|
have been set.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# Ugly code alert. localpath in the fetchers will try to evaluate SRCREV which
|
# Ugly code alert. localpath in the fetchers will try to evaluate SRCREV which
|
||||||
# could translate into a call to here. If it does, we need to catch this
|
# could translate into a call to here. If it does, we need to catch this
|
||||||
# and provide some way so it knows get_srcrev is active instead of being
|
# and provide some way so it knows get_srcrev is active instead of being
|
||||||
# some number etc. hence the srcrev_internal_call tracking and the magic
|
# some number etc. hence the srcrev_internal_call tracking and the magic
|
||||||
# "SRCREVINACTION" return value.
|
# "SRCREVINACTION" return value.
|
||||||
#
|
#
|
||||||
# Neater solutions welcome!
|
# Neater solutions welcome!
|
||||||
@@ -372,7 +349,7 @@ def get_srcrev(d):
|
|||||||
|
|
||||||
scms = []
|
scms = []
|
||||||
|
|
||||||
# Only call setup_localpath on URIs which suppports_srcrev()
|
# Only call setup_localpath on URIs which suppports_srcrev()
|
||||||
urldata = init(bb.data.getVar('SRC_URI', d, 1).split(), d, False)
|
urldata = init(bb.data.getVar('SRC_URI', d, 1).split(), d, False)
|
||||||
for u in urldata:
|
for u in urldata:
|
||||||
ud = urldata[u]
|
ud = urldata[u]
|
||||||
@@ -385,7 +362,8 @@ def get_srcrev(d):
|
|||||||
bb.msg.error(bb.msg.domain.Fetcher, "SRCREV was used yet no valid SCM was found in SRC_URI")
|
bb.msg.error(bb.msg.domain.Fetcher, "SRCREV was used yet no valid SCM was found in SRC_URI")
|
||||||
raise ParameterError
|
raise ParameterError
|
||||||
|
|
||||||
bb.data.setVar('__BB_DONT_CACHE','1', d)
|
if bb.data.getVar('BB_SRCREV_POLICY', d, True) != "cache":
|
||||||
|
bb.data.setVar('__BB_DONT_CACHE', '1', d)
|
||||||
|
|
||||||
if len(scms) == 1:
|
if len(scms) == 1:
|
||||||
return urldata[scms[0]].method.sortable_revision(scms[0], urldata[scms[0]], d)
|
return urldata[scms[0]].method.sortable_revision(scms[0], urldata[scms[0]], d)
|
||||||
@@ -408,7 +386,7 @@ def get_srcrev(d):
|
|||||||
|
|
||||||
def localpath(url, d, cache = True):
|
def localpath(url, d, cache = True):
|
||||||
"""
|
"""
|
||||||
Called from the parser with cache=False since the cache isn't ready
|
Called from the parser with cache=False since the cache isn't ready
|
||||||
at this point. Also called from classed in OE e.g. patch.bbclass
|
at this point. Also called from classed in OE e.g. patch.bbclass
|
||||||
"""
|
"""
|
||||||
ud = init([url], d)
|
ud = init([url], d)
|
||||||
@@ -427,12 +405,15 @@ def runfetchcmd(cmd, d, quiet = False):
|
|||||||
# rather than host provided
|
# rather than host provided
|
||||||
# Also include some other variables.
|
# Also include some other variables.
|
||||||
# FIXME: Should really include all export varaiables?
|
# FIXME: Should really include all export varaiables?
|
||||||
exportvars = ['PATH', 'GIT_PROXY_COMMAND', 'GIT_PROXY_HOST', 'GIT_PROXY_PORT', 'GIT_CONFIG', 'http_proxy', 'ftp_proxy', 'SSH_AUTH_SOCK', 'SSH_AGENT_PID', 'HOME']
|
exportvars = ['PATH', 'GIT_PROXY_COMMAND', 'GIT_PROXY_HOST',
|
||||||
|
'GIT_PROXY_PORT', 'GIT_CONFIG', 'http_proxy', 'ftp_proxy',
|
||||||
|
'https_proxy', 'no_proxy', 'ALL_PROXY', 'all_proxy',
|
||||||
|
'SSH_AUTH_SOCK', 'SSH_AGENT_PID', 'HOME']
|
||||||
|
|
||||||
for var in exportvars:
|
for var in exportvars:
|
||||||
val = data.getVar(var, d, True)
|
val = data.getVar(var, d, True)
|
||||||
if val:
|
if val:
|
||||||
cmd = 'export ' + var + '=%s; %s' % (val, cmd)
|
cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
|
||||||
|
|
||||||
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % cmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % cmd)
|
||||||
|
|
||||||
@@ -440,15 +421,15 @@ def runfetchcmd(cmd, d, quiet = False):
|
|||||||
stdout_handle = os.popen(cmd + " 2>&1", "r")
|
stdout_handle = os.popen(cmd + " 2>&1", "r")
|
||||||
output = ""
|
output = ""
|
||||||
|
|
||||||
while 1:
|
while True:
|
||||||
line = stdout_handle.readline()
|
line = stdout_handle.readline()
|
||||||
if not line:
|
if not line:
|
||||||
break
|
break
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print line,
|
print(line, end=' ')
|
||||||
output += line
|
output += line
|
||||||
|
|
||||||
status = stdout_handle.close() or 0
|
status = stdout_handle.close() or 0
|
||||||
signal = status >> 8
|
signal = status >> 8
|
||||||
exitstatus = status & 0xff
|
exitstatus = status & 0xff
|
||||||
|
|
||||||
@@ -459,7 +440,7 @@ def runfetchcmd(cmd, d, quiet = False):
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def try_mirrors(d, uri, mirrors, check = False):
|
def try_mirrors(d, uri, mirrors, check = False, force = False):
|
||||||
"""
|
"""
|
||||||
Try to use a mirrored version of the sources.
|
Try to use a mirrored version of the sources.
|
||||||
This method will be automatically called before the fetchers go.
|
This method will be automatically called before the fetchers go.
|
||||||
@@ -469,7 +450,7 @@ def try_mirrors(d, uri, mirrors, check = False):
|
|||||||
mirrors is the list of mirrors we're going to try
|
mirrors is the list of mirrors we're going to try
|
||||||
"""
|
"""
|
||||||
fpath = os.path.join(data.getVar("DL_DIR", d, 1), os.path.basename(uri))
|
fpath = os.path.join(data.getVar("DL_DIR", d, 1), os.path.basename(uri))
|
||||||
if not check and os.access(fpath, os.R_OK):
|
if not check and os.access(fpath, os.R_OK) and not force:
|
||||||
bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists, skipping checkout." % fpath)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists, skipping checkout." % fpath)
|
||||||
return fpath
|
return fpath
|
||||||
|
|
||||||
@@ -497,6 +478,7 @@ def try_mirrors(d, uri, mirrors, check = False):
|
|||||||
import sys
|
import sys
|
||||||
(type, value, traceback) = sys.exc_info()
|
(type, value, traceback) = sys.exc_info()
|
||||||
bb.msg.debug(2, bb.msg.domain.Fetcher, "Mirror fetch failure: %s" % value)
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "Mirror fetch failure: %s" % value)
|
||||||
|
removefile(ud.localpath)
|
||||||
continue
|
continue
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -507,7 +489,7 @@ class FetchData(object):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, url, d):
|
def __init__(self, url, d):
|
||||||
self.localfile = ""
|
self.localfile = ""
|
||||||
(self.type, self.host, self.path, self.user, self.pswd, self.parm) = bb.decodeurl(data.expand(url, d))
|
(self.type, self.host, self.path, self.user, self.pswd, self.parm) = decodeurl(data.expand(url, d))
|
||||||
self.date = Fetch.getSRCDate(self, d)
|
self.date = Fetch.getSRCDate(self, d)
|
||||||
self.url = url
|
self.url = url
|
||||||
if not self.user and "user" in self.parm:
|
if not self.user and "user" in self.parm:
|
||||||
@@ -526,12 +508,13 @@ class FetchData(object):
|
|||||||
if "localpath" in self.parm:
|
if "localpath" in self.parm:
|
||||||
# if user sets localpath for file, use it instead.
|
# if user sets localpath for file, use it instead.
|
||||||
self.localpath = self.parm["localpath"]
|
self.localpath = self.parm["localpath"]
|
||||||
|
self.basename = os.path.basename(self.localpath)
|
||||||
else:
|
else:
|
||||||
premirrors = bb.data.getVar('PREMIRRORS', d, True)
|
premirrors = bb.data.getVar('PREMIRRORS', d, True)
|
||||||
local = ""
|
local = ""
|
||||||
if premirrors and self.url:
|
if premirrors and self.url:
|
||||||
aurl = self.url.split(";")[0]
|
aurl = self.url.split(";")[0]
|
||||||
mirrors = [ i.split() for i in (premirrors or "").split('\n') if i ]
|
mirrors = mirror_from_string(premirrors)
|
||||||
for (find, replace) in mirrors:
|
for (find, replace) in mirrors:
|
||||||
if replace.startswith("file://"):
|
if replace.startswith("file://"):
|
||||||
path = aurl.split("://")[1]
|
path = aurl.split("://")[1]
|
||||||
@@ -550,10 +533,11 @@ class FetchData(object):
|
|||||||
# Horrible...
|
# Horrible...
|
||||||
bb.data.delVar("ISHOULDNEVEREXIST", d)
|
bb.data.delVar("ISHOULDNEVEREXIST", d)
|
||||||
|
|
||||||
# Note: These files should always be in DL_DIR whereas localpath may not be.
|
if self.localpath is not None:
|
||||||
basepath = bb.data.expand("${DL_DIR}/%s" % os.path.basename(self.localpath), d)
|
# Note: These files should always be in DL_DIR whereas localpath may not be.
|
||||||
self.md5 = basepath + '.md5'
|
basepath = bb.data.expand("${DL_DIR}/%s" % os.path.basename(self.localpath), d)
|
||||||
self.lockfile = basepath + '.lock'
|
self.md5 = basepath + '.md5'
|
||||||
|
self.lockfile = basepath + '.lock'
|
||||||
|
|
||||||
|
|
||||||
class Fetch(object):
|
class Fetch(object):
|
||||||
@@ -571,7 +555,7 @@ class Fetch(object):
|
|||||||
def localpath(self, url, urldata, d):
|
def localpath(self, url, urldata, d):
|
||||||
"""
|
"""
|
||||||
Return the local filename of a given url assuming a successful fetch.
|
Return the local filename of a given url assuming a successful fetch.
|
||||||
Can also setup variables in urldata for use in go (saving code duplication
|
Can also setup variables in urldata for use in go (saving code duplication
|
||||||
and duplicate code execution)
|
and duplicate code execution)
|
||||||
"""
|
"""
|
||||||
return url
|
return url
|
||||||
@@ -603,6 +587,17 @@ class Fetch(object):
|
|||||||
"""
|
"""
|
||||||
raise NoMethodError("Missing implementation for url")
|
raise NoMethodError("Missing implementation for url")
|
||||||
|
|
||||||
|
def try_premirror(self, url, urldata, d):
|
||||||
|
"""
|
||||||
|
Should premirrors be used?
|
||||||
|
"""
|
||||||
|
if urldata.method.forcefetch(url, urldata, d):
|
||||||
|
return True
|
||||||
|
elif os.path.exists(urldata.md5) and os.path.exists(urldata.localfile):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
def checkstatus(self, url, urldata, d):
|
def checkstatus(self, url, urldata, d):
|
||||||
"""
|
"""
|
||||||
Check the status of a URL
|
Check the status of a URL
|
||||||
@@ -632,8 +627,8 @@ class Fetch(object):
|
|||||||
"""
|
"""
|
||||||
Return:
|
Return:
|
||||||
a) a source revision if specified
|
a) a source revision if specified
|
||||||
b) True if auto srcrev is in action
|
b) True if auto srcrev is in action
|
||||||
c) False otherwise
|
c) False otherwise
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if 'rev' in ud.parm:
|
if 'rev' in ud.parm:
|
||||||
@@ -645,7 +640,11 @@ class Fetch(object):
|
|||||||
rev = None
|
rev = None
|
||||||
if 'name' in ud.parm:
|
if 'name' in ud.parm:
|
||||||
pn = data.getVar("PN", d, 1)
|
pn = data.getVar("PN", d, 1)
|
||||||
rev = data.getVar("SRCREV_pn-" + pn + "_" + ud.parm['name'], d, 1)
|
rev = data.getVar("SRCREV_%s_pn-%s" % (ud.parm['name'], pn), d, 1)
|
||||||
|
if not rev:
|
||||||
|
rev = data.getVar("SRCREV_pn-%s_%s" % (pn, ud.parm['name']), d, 1)
|
||||||
|
if not rev:
|
||||||
|
rev = data.getVar("SRCREV_%s" % (ud.parm['name']), d, 1)
|
||||||
if not rev:
|
if not rev:
|
||||||
rev = data.getVar("SRCREV", d, 1)
|
rev = data.getVar("SRCREV", d, 1)
|
||||||
if rev == "INVALID":
|
if rev == "INVALID":
|
||||||
@@ -665,7 +664,7 @@ class Fetch(object):
|
|||||||
b) None otherwise
|
b) None otherwise
|
||||||
"""
|
"""
|
||||||
|
|
||||||
localcount= None
|
localcount = None
|
||||||
if 'name' in ud.parm:
|
if 'name' in ud.parm:
|
||||||
pn = data.getVar("PN", d, 1)
|
pn = data.getVar("PN", d, 1)
|
||||||
localcount = data.getVar("LOCALCOUNT_" + ud.parm['name'], d, 1)
|
localcount = data.getVar("LOCALCOUNT_" + ud.parm['name'], d, 1)
|
||||||
@@ -706,7 +705,7 @@ class Fetch(object):
|
|||||||
if not hasattr(self, "_latest_revision"):
|
if not hasattr(self, "_latest_revision"):
|
||||||
raise ParameterError
|
raise ParameterError
|
||||||
|
|
||||||
pd = persist_data.PersistData(d)
|
pd = persist_data.PersistData(d, persistent_database_connection)
|
||||||
key = self.generate_revision_key(url, ud, d)
|
key = self.generate_revision_key(url, ud, d)
|
||||||
rev = pd.getValue("BB_URI_HEADREVS", key)
|
rev = pd.getValue("BB_URI_HEADREVS", key)
|
||||||
if rev != None:
|
if rev != None:
|
||||||
@@ -718,12 +717,12 @@ class Fetch(object):
|
|||||||
|
|
||||||
def sortable_revision(self, url, ud, d):
|
def sortable_revision(self, url, ud, d):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if hasattr(self, "_sortable_revision"):
|
if hasattr(self, "_sortable_revision"):
|
||||||
return self._sortable_revision(url, ud, d)
|
return self._sortable_revision(url, ud, d)
|
||||||
|
|
||||||
pd = persist_data.PersistData(d)
|
pd = persist_data.PersistData(d, persistent_database_connection)
|
||||||
key = self.generate_revision_key(url, ud, d)
|
key = self.generate_revision_key(url, ud, d)
|
||||||
|
|
||||||
latest_rev = self._build_revision(url, ud, d)
|
latest_rev = self._build_revision(url, ud, d)
|
||||||
@@ -758,18 +757,18 @@ class Fetch(object):
|
|||||||
key = self._revision_key(url, ud, d)
|
key = self._revision_key(url, ud, d)
|
||||||
return "%s-%s" % (key, bb.data.getVar("PN", d, True) or "")
|
return "%s-%s" % (key, bb.data.getVar("PN", d, True) or "")
|
||||||
|
|
||||||
import cvs
|
from . import cvs
|
||||||
import git
|
from . import git
|
||||||
import local
|
from . import local
|
||||||
import svn
|
from . import svn
|
||||||
import wget
|
from . import wget
|
||||||
import svk
|
from . import svk
|
||||||
import ssh
|
from . import ssh
|
||||||
import perforce
|
from . import perforce
|
||||||
import bzr
|
from . import bzr
|
||||||
import hg
|
from . import hg
|
||||||
import osc
|
from . import osc
|
||||||
import repo
|
from . import repo
|
||||||
|
|
||||||
methods.append(local.Local())
|
methods.append(local.Local())
|
||||||
methods.append(wget.Wget())
|
methods.append(wget.Wget())
|
||||||
|
|||||||
@@ -46,15 +46,15 @@ class Bzr(Fetch):
|
|||||||
|
|
||||||
revision = Fetch.srcrev_internal_helper(ud, d)
|
revision = Fetch.srcrev_internal_helper(ud, d)
|
||||||
if revision is True:
|
if revision is True:
|
||||||
ud.revision = self.latest_revision(url, ud, d)
|
ud.revision = self.latest_revision(url, ud, d)
|
||||||
elif revision:
|
elif revision:
|
||||||
ud.revision = revision
|
ud.revision = revision
|
||||||
|
|
||||||
if not ud.revision:
|
if not ud.revision:
|
||||||
ud.revision = self.latest_revision(url, ud, d)
|
ud.revision = self.latest_revision(url, ud, d)
|
||||||
|
|
||||||
ud.localfile = data.expand('bzr_%s_%s_%s.tar.gz' % (ud.host, ud.path.replace('/', '.'), ud.revision), d)
|
ud.localfile = data.expand('bzr_%s_%s_%s.tar.gz' % (ud.host, ud.path.replace('/', '.'), ud.revision), d)
|
||||||
|
|
||||||
return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
|
return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
|
||||||
|
|
||||||
def _buildbzrcommand(self, ud, d, command):
|
def _buildbzrcommand(self, ud, d, command):
|
||||||
@@ -145,4 +145,3 @@ class Bzr(Fetch):
|
|||||||
|
|
||||||
def _build_revision(self, url, ud, d):
|
def _build_revision(self, url, ud, d):
|
||||||
return ud.revision
|
return ud.revision
|
||||||
|
|
||||||
|
|||||||
@@ -139,8 +139,8 @@ class Cvs(Fetch):
|
|||||||
bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory")
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory")
|
||||||
pkg = data.expand('${PN}', d)
|
pkg = data.expand('${PN}', d)
|
||||||
pkgdir = os.path.join(data.expand('${CVSDIR}', localdata), pkg)
|
pkgdir = os.path.join(data.expand('${CVSDIR}', localdata), pkg)
|
||||||
moddir = os.path.join(pkgdir,localdir)
|
moddir = os.path.join(pkgdir, localdir)
|
||||||
if os.access(os.path.join(moddir,'CVS'), os.R_OK):
|
if os.access(os.path.join(moddir, 'CVS'), os.R_OK):
|
||||||
bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc)
|
||||||
# update sources there
|
# update sources there
|
||||||
os.chdir(moddir)
|
os.chdir(moddir)
|
||||||
@@ -157,7 +157,7 @@ class Cvs(Fetch):
|
|||||||
try:
|
try:
|
||||||
os.rmdir(moddir)
|
os.rmdir(moddir)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
raise FetchError(ud.module)
|
raise FetchError(ud.module)
|
||||||
|
|
||||||
# tar them up to a defined filename
|
# tar them up to a defined filename
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ class Git(Fetch):
|
|||||||
|
|
||||||
tag = Fetch.srcrev_internal_helper(ud, d)
|
tag = Fetch.srcrev_internal_helper(ud, d)
|
||||||
if tag is True:
|
if tag is True:
|
||||||
ud.tag = self.latest_revision(url, ud, d)
|
ud.tag = self.latest_revision(url, ud, d)
|
||||||
elif tag:
|
elif tag:
|
||||||
ud.tag = tag
|
ud.tag = tag
|
||||||
|
|
||||||
if not ud.tag or ud.tag == "master":
|
if not ud.tag or ud.tag == "master":
|
||||||
ud.tag = self.latest_revision(url, ud, d)
|
ud.tag = self.latest_revision(url, ud, d)
|
||||||
|
|
||||||
subdir = ud.parm.get("subpath", "")
|
subdir = ud.parm.get("subpath", "")
|
||||||
if subdir != "":
|
if subdir != "":
|
||||||
@@ -79,8 +79,33 @@ class Git(Fetch):
|
|||||||
|
|
||||||
ud.basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
|
ud.basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
|
||||||
|
|
||||||
|
if 'noclone' in ud.parm:
|
||||||
|
ud.localfile = None
|
||||||
|
return None
|
||||||
|
|
||||||
return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
|
return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
|
||||||
|
|
||||||
|
def forcefetch(self, url, ud, d):
|
||||||
|
if 'fullclone' in ud.parm:
|
||||||
|
return True
|
||||||
|
if 'noclone' in ud.parm:
|
||||||
|
return False
|
||||||
|
if os.path.exists(ud.localpath):
|
||||||
|
return False
|
||||||
|
if not self._contains_ref(ud.tag, d):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def try_premirror(self, u, ud, d):
|
||||||
|
if 'noclone' in ud.parm:
|
||||||
|
return False
|
||||||
|
if os.path.exists(ud.clonedir):
|
||||||
|
return False
|
||||||
|
if os.path.exists(ud.localpath):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def go(self, loc, ud, d):
|
def go(self, loc, ud, d):
|
||||||
"""Fetch url"""
|
"""Fetch url"""
|
||||||
|
|
||||||
@@ -94,27 +119,40 @@ class Git(Fetch):
|
|||||||
coname = '%s' % (ud.tag)
|
coname = '%s' % (ud.tag)
|
||||||
codir = os.path.join(ud.clonedir, coname)
|
codir = os.path.join(ud.clonedir, coname)
|
||||||
|
|
||||||
if not os.path.exists(ud.clonedir):
|
# If we have no existing clone and no mirror tarball, try and obtain one
|
||||||
|
if not os.path.exists(ud.clonedir) and not os.path.exists(repofile):
|
||||||
try:
|
try:
|
||||||
Fetch.try_mirrors(ud.mirrortarball)
|
Fetch.try_mirrors(ud.mirrortarball)
|
||||||
bb.mkdirhier(ud.clonedir)
|
|
||||||
os.chdir(ud.clonedir)
|
|
||||||
runfetchcmd("tar -xzf %s" % (repofile), d)
|
|
||||||
except:
|
except:
|
||||||
runfetchcmd("%s clone -n %s://%s%s%s %s" % (ud.basecmd, ud.proto, username, ud.host, ud.path, ud.clonedir), d)
|
pass
|
||||||
|
|
||||||
|
# If the checkout doesn't exist and the mirror tarball does, extract it
|
||||||
|
if not os.path.exists(ud.clonedir) and os.path.exists(repofile):
|
||||||
|
bb.mkdirhier(ud.clonedir)
|
||||||
|
os.chdir(ud.clonedir)
|
||||||
|
runfetchcmd("tar -xzf %s" % (repofile), d)
|
||||||
|
|
||||||
|
# If the repo still doesn't exist, fallback to cloning it
|
||||||
|
if not os.path.exists(ud.clonedir):
|
||||||
|
runfetchcmd("%s clone -n %s://%s%s%s %s" % (ud.basecmd, ud.proto, username, ud.host, ud.path, ud.clonedir), d)
|
||||||
|
|
||||||
os.chdir(ud.clonedir)
|
os.chdir(ud.clonedir)
|
||||||
# Remove all but the .git directory
|
# Update the checkout if needed
|
||||||
if not self._contains_ref(ud.tag, d):
|
if not self._contains_ref(ud.tag, d) or 'fullclone' in ud.parm:
|
||||||
|
# Remove all but the .git directory
|
||||||
runfetchcmd("rm * -Rf", d)
|
runfetchcmd("rm * -Rf", d)
|
||||||
runfetchcmd("%s fetch %s://%s%s%s %s" % (ud.basecmd, ud.proto, username, ud.host, ud.path, ud.branch), d)
|
if 'fullclone' in ud.parm:
|
||||||
|
runfetchcmd("%s fetch --all" % (ud.basecmd), d)
|
||||||
|
else:
|
||||||
|
runfetchcmd("%s fetch %s://%s%s%s %s" % (ud.basecmd, ud.proto, username, ud.host, ud.path, ud.branch), d)
|
||||||
runfetchcmd("%s fetch --tags %s://%s%s%s" % (ud.basecmd, ud.proto, username, ud.host, ud.path), d)
|
runfetchcmd("%s fetch --tags %s://%s%s%s" % (ud.basecmd, ud.proto, username, ud.host, ud.path), d)
|
||||||
runfetchcmd("%s prune-packed" % ud.basecmd, d)
|
runfetchcmd("%s prune-packed" % ud.basecmd, d)
|
||||||
runfetchcmd("%s pack-redundant --all | xargs -r rm" % ud.basecmd, d)
|
runfetchcmd("%s pack-redundant --all | xargs -r rm" % ud.basecmd, d)
|
||||||
|
|
||||||
|
# Generate a mirror tarball if needed
|
||||||
os.chdir(ud.clonedir)
|
os.chdir(ud.clonedir)
|
||||||
mirror_tarballs = data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True)
|
mirror_tarballs = data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True)
|
||||||
if mirror_tarballs != "0" or 'fullclone' in ud.parm:
|
if mirror_tarballs != "0" or 'fullclone' in ud.parm:
|
||||||
bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git repository")
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git repository")
|
||||||
runfetchcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ), d)
|
runfetchcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ), d)
|
||||||
|
|
||||||
@@ -165,7 +203,7 @@ class Git(Fetch):
|
|||||||
"""
|
"""
|
||||||
Return a unique key for the url
|
Return a unique key for the url
|
||||||
"""
|
"""
|
||||||
return "git:" + ud.host + ud.path.replace('/', '.')
|
return "git:" + ud.host + ud.path.replace('/', '.') + ud.branch
|
||||||
|
|
||||||
def _latest_revision(self, url, ud, d):
|
def _latest_revision(self, url, ud, d):
|
||||||
"""
|
"""
|
||||||
@@ -188,7 +226,7 @@ class Git(Fetch):
|
|||||||
|
|
||||||
def _sortable_buildindex_disabled(self, url, ud, d, rev):
|
def _sortable_buildindex_disabled(self, url, ud, d, rev):
|
||||||
"""
|
"""
|
||||||
Return a suitable buildindex for the revision specified. This is done by counting revisions
|
Return a suitable buildindex for the revision specified. This is done by counting revisions
|
||||||
using "git rev-list" which may or may not work in different circumstances.
|
using "git rev-list" which may or may not work in different circumstances.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -197,7 +235,7 @@ class Git(Fetch):
|
|||||||
# Check if we have the rev already
|
# Check if we have the rev already
|
||||||
|
|
||||||
if not os.path.exists(ud.clonedir):
|
if not os.path.exists(ud.clonedir):
|
||||||
print "no repo"
|
print("no repo")
|
||||||
self.go(None, ud, d)
|
self.go(None, ud, d)
|
||||||
if not os.path.exists(ud.clonedir):
|
if not os.path.exists(ud.clonedir):
|
||||||
bb.msg.error(bb.msg.domain.Fetcher, "GIT repository for %s doesn't exist in %s, cannot get sortable buildnumber, using old value" % (url, ud.clonedir))
|
bb.msg.error(bb.msg.domain.Fetcher, "GIT repository for %s doesn't exist in %s, cannot get sortable buildnumber, using old value" % (url, ud.clonedir))
|
||||||
@@ -213,5 +251,4 @@ class Git(Fetch):
|
|||||||
|
|
||||||
buildindex = "%s" % output.split()[0]
|
buildindex = "%s" % output.split()[0]
|
||||||
bb.msg.debug(1, bb.msg.domain.Fetcher, "GIT repository for %s in %s is returning %s revisions in rev-list before %s" % (url, ud.clonedir, buildindex, rev))
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "GIT repository for %s in %s is returning %s revisions in rev-list before %s" % (url, ud.clonedir, buildindex, rev))
|
||||||
return buildindex
|
return buildindex
|
||||||
|
|
||||||
|
|||||||
@@ -134,9 +134,9 @@ class Hg(Fetch):
|
|||||||
os.chdir(ud.pkgdir)
|
os.chdir(ud.pkgdir)
|
||||||
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % fetchcmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % fetchcmd)
|
||||||
runfetchcmd(fetchcmd, d)
|
runfetchcmd(fetchcmd, d)
|
||||||
|
|
||||||
# Even when we clone (fetch), we still need to update as hg's clone
|
# Even when we clone (fetch), we still need to update as hg's clone
|
||||||
# won't checkout the specified revision if its on a branch
|
# won't checkout the specified revision if its on a branch
|
||||||
updatecmd = self._buildhgcommand(ud, d, "update")
|
updatecmd = self._buildhgcommand(ud, d, "update")
|
||||||
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % updatecmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % updatecmd)
|
||||||
runfetchcmd(updatecmd, d)
|
runfetchcmd(updatecmd, d)
|
||||||
@@ -170,4 +170,3 @@ class Hg(Fetch):
|
|||||||
Return a unique key for the url
|
Return a unique key for the url
|
||||||
"""
|
"""
|
||||||
return "hg:" + ud.moddir
|
return "hg:" + ud.moddir
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ BitBake build tools.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import bb
|
import bb
|
||||||
|
import bb.utils
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch
|
from bb.fetch import Fetch
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ class Local(Fetch):
|
|||||||
if path[0] != "/":
|
if path[0] != "/":
|
||||||
filespath = data.getVar('FILESPATH', d, 1)
|
filespath = data.getVar('FILESPATH', d, 1)
|
||||||
if filespath:
|
if filespath:
|
||||||
newpath = bb.which(filespath, path)
|
newpath = bb.utils.which(filespath, path)
|
||||||
if not newpath:
|
if not newpath:
|
||||||
filesdir = data.getVar('FILESDIR', d, 1)
|
filesdir = data.getVar('FILESDIR', d, 1)
|
||||||
if filesdir:
|
if filesdir:
|
||||||
@@ -65,8 +66,8 @@ class Local(Fetch):
|
|||||||
Check the status of the url
|
Check the status of the url
|
||||||
"""
|
"""
|
||||||
if urldata.localpath.find("*") != -1:
|
if urldata.localpath.find("*") != -1:
|
||||||
bb.msg.note(1, bb.msg.domain.Fetcher, "URL %s looks like a glob and was therefore not checked." % url)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "URL %s looks like a glob and was therefore not checked." % url)
|
||||||
return True
|
return True
|
||||||
if os.path.exists(urldata.localpath):
|
if os.path.exists(urldata.localpath):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from bb.fetch import MissingParameterError
|
|||||||
from bb.fetch import runfetchcmd
|
from bb.fetch import runfetchcmd
|
||||||
|
|
||||||
class Osc(Fetch):
|
class Osc(Fetch):
|
||||||
"""Class to fetch a module or modules from Opensuse build server
|
"""Class to fetch a module or modules from Opensuse build server
|
||||||
repositories."""
|
repositories."""
|
||||||
|
|
||||||
def supports(self, url, ud, d):
|
def supports(self, url, ud, d):
|
||||||
@@ -64,7 +64,7 @@ class Osc(Fetch):
|
|||||||
proto = "ocs"
|
proto = "ocs"
|
||||||
if "proto" in ud.parm:
|
if "proto" in ud.parm:
|
||||||
proto = ud.parm["proto"]
|
proto = ud.parm["proto"]
|
||||||
|
|
||||||
options = []
|
options = []
|
||||||
|
|
||||||
config = "-c %s" % self.generate_config(ud, d)
|
config = "-c %s" % self.generate_config(ud, d)
|
||||||
@@ -108,7 +108,7 @@ class Osc(Fetch):
|
|||||||
os.chdir(ud.pkgdir)
|
os.chdir(ud.pkgdir)
|
||||||
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % oscfetchcmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % oscfetchcmd)
|
||||||
runfetchcmd(oscfetchcmd, d)
|
runfetchcmd(oscfetchcmd, d)
|
||||||
|
|
||||||
os.chdir(os.path.join(ud.pkgdir + ud.path))
|
os.chdir(os.path.join(ud.pkgdir + ud.path))
|
||||||
# tar them up to a defined filename
|
# tar them up to a defined filename
|
||||||
try:
|
try:
|
||||||
@@ -131,7 +131,7 @@ class Osc(Fetch):
|
|||||||
|
|
||||||
config_path = "%s/oscrc" % data.expand('${OSCDIR}', d)
|
config_path = "%s/oscrc" % data.expand('${OSCDIR}', d)
|
||||||
if (os.path.exists(config_path)):
|
if (os.path.exists(config_path)):
|
||||||
os.remove(config_path)
|
os.remove(config_path)
|
||||||
|
|
||||||
f = open(config_path, 'w')
|
f = open(config_path, 'w')
|
||||||
f.write("[general]\n")
|
f.write("[general]\n")
|
||||||
@@ -146,5 +146,5 @@ class Osc(Fetch):
|
|||||||
f.write("user = %s\n" % ud.parm["user"])
|
f.write("user = %s\n" % ud.parm["user"])
|
||||||
f.write("pass = %s\n" % ud.parm["pswd"])
|
f.write("pass = %s\n" % ud.parm["pswd"])
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
return config_path
|
return config_path
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ BitBake build tools.
|
|||||||
#
|
#
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
|
from future_builtins import zip
|
||||||
import os
|
import os
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
@@ -35,15 +36,15 @@ class Perforce(Fetch):
|
|||||||
def supports(self, url, ud, d):
|
def supports(self, url, ud, d):
|
||||||
return ud.type in ['p4']
|
return ud.type in ['p4']
|
||||||
|
|
||||||
def doparse(url,d):
|
def doparse(url, d):
|
||||||
parm = {}
|
parm = {}
|
||||||
path = url.split("://")[1]
|
path = url.split("://")[1]
|
||||||
delim = path.find("@");
|
delim = path.find("@");
|
||||||
if delim != -1:
|
if delim != -1:
|
||||||
(user,pswd,host,port) = path.split('@')[0].split(":")
|
(user, pswd, host, port) = path.split('@')[0].split(":")
|
||||||
path = path.split('@')[1]
|
path = path.split('@')[1]
|
||||||
else:
|
else:
|
||||||
(host,port) = data.getVar('P4PORT', d).split(':')
|
(host, port) = data.getVar('P4PORT', d).split(':')
|
||||||
user = ""
|
user = ""
|
||||||
pswd = ""
|
pswd = ""
|
||||||
|
|
||||||
@@ -53,19 +54,19 @@ class Perforce(Fetch):
|
|||||||
plist = path.split(';')
|
plist = path.split(';')
|
||||||
for item in plist:
|
for item in plist:
|
||||||
if item.count('='):
|
if item.count('='):
|
||||||
(key,value) = item.split('=')
|
(key, value) = item.split('=')
|
||||||
keys.append(key)
|
keys.append(key)
|
||||||
values.append(value)
|
values.append(value)
|
||||||
|
|
||||||
parm = dict(zip(keys,values))
|
parm = dict(zip(keys, values))
|
||||||
path = "//" + path.split(';')[0]
|
path = "//" + path.split(';')[0]
|
||||||
host += ":%s" % (port)
|
host += ":%s" % (port)
|
||||||
parm["cset"] = Perforce.getcset(d, path, host, user, pswd, parm)
|
parm["cset"] = Perforce.getcset(d, path, host, user, pswd, parm)
|
||||||
|
|
||||||
return host,path,user,pswd,parm
|
return host, path, user, pswd, parm
|
||||||
doparse = staticmethod(doparse)
|
doparse = staticmethod(doparse)
|
||||||
|
|
||||||
def getcset(d, depot,host,user,pswd,parm):
|
def getcset(d, depot, host, user, pswd, parm):
|
||||||
p4opt = ""
|
p4opt = ""
|
||||||
if "cset" in parm:
|
if "cset" in parm:
|
||||||
return parm["cset"];
|
return parm["cset"];
|
||||||
@@ -95,9 +96,9 @@ class Perforce(Fetch):
|
|||||||
return cset.split(' ')[1]
|
return cset.split(' ')[1]
|
||||||
getcset = staticmethod(getcset)
|
getcset = staticmethod(getcset)
|
||||||
|
|
||||||
def localpath(self, url, ud, d):
|
def localpath(self, url, ud, d):
|
||||||
|
|
||||||
(host,path,user,pswd,parm) = Perforce.doparse(url,d)
|
(host, path, user, pswd, parm) = Perforce.doparse(url, d)
|
||||||
|
|
||||||
# If a label is specified, we use that as our filename
|
# If a label is specified, we use that as our filename
|
||||||
|
|
||||||
@@ -115,7 +116,7 @@ class Perforce(Fetch):
|
|||||||
|
|
||||||
cset = Perforce.getcset(d, path, host, user, pswd, parm)
|
cset = Perforce.getcset(d, path, host, user, pswd, parm)
|
||||||
|
|
||||||
ud.localfile = data.expand('%s+%s+%s.tar.gz' % (host,base.replace('/', '.'), cset), d)
|
ud.localfile = data.expand('%s+%s+%s.tar.gz' % (host, base.replace('/', '.'), cset), d)
|
||||||
|
|
||||||
return os.path.join(data.getVar("DL_DIR", d, 1), ud.localfile)
|
return os.path.join(data.getVar("DL_DIR", d, 1), ud.localfile)
|
||||||
|
|
||||||
@@ -124,7 +125,7 @@ class Perforce(Fetch):
|
|||||||
Fetch urls
|
Fetch urls
|
||||||
"""
|
"""
|
||||||
|
|
||||||
(host,depot,user,pswd,parm) = Perforce.doparse(loc, d)
|
(host, depot, user, pswd, parm) = Perforce.doparse(loc, d)
|
||||||
|
|
||||||
if depot.find('/...') != -1:
|
if depot.find('/...') != -1:
|
||||||
path = depot[:depot.find('/...')]
|
path = depot[:depot.find('/...')]
|
||||||
@@ -160,14 +161,14 @@ class Perforce(Fetch):
|
|||||||
tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
|
tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
|
||||||
tmpfile = tmppipe.readline().strip()
|
tmpfile = tmppipe.readline().strip()
|
||||||
if not tmpfile:
|
if not tmpfile:
|
||||||
bb.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
|
bb.msg.error(bb.msg.domain.Fetcher, "Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
|
||||||
raise FetchError(module)
|
raise FetchError(module)
|
||||||
|
|
||||||
if "label" in parm:
|
if "label" in parm:
|
||||||
depot = "%s@%s" % (depot,parm["label"])
|
depot = "%s@%s" % (depot, parm["label"])
|
||||||
else:
|
else:
|
||||||
cset = Perforce.getcset(d, depot, host, user, pswd, parm)
|
cset = Perforce.getcset(d, depot, host, user, pswd, parm)
|
||||||
depot = "%s@%s" % (depot,cset)
|
depot = "%s@%s" % (depot, cset)
|
||||||
|
|
||||||
os.chdir(tmpfile)
|
os.chdir(tmpfile)
|
||||||
bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
|
||||||
@@ -175,12 +176,12 @@ class Perforce(Fetch):
|
|||||||
p4file = os.popen("%s%s files %s" % (p4cmd, p4opt, depot))
|
p4file = os.popen("%s%s files %s" % (p4cmd, p4opt, depot))
|
||||||
|
|
||||||
if not p4file:
|
if not p4file:
|
||||||
bb.error("Fetch: unable to get the P4 files from %s" % (depot))
|
bb.msg.error(bb.msg.domain.Fetcher, "Fetch: unable to get the P4 files from %s" % (depot))
|
||||||
raise FetchError(module)
|
raise FetchError(module)
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
for file in p4file:
|
for file in p4file:
|
||||||
list = file.split()
|
list = file.split()
|
||||||
|
|
||||||
if list[2] == "delete":
|
if list[2] == "delete":
|
||||||
@@ -189,11 +190,11 @@ class Perforce(Fetch):
|
|||||||
dest = list[0][len(path)+1:]
|
dest = list[0][len(path)+1:]
|
||||||
where = dest.find("#")
|
where = dest.find("#")
|
||||||
|
|
||||||
os.system("%s%s print -o %s/%s %s" % (p4cmd, p4opt, module,dest[:where],list[0]))
|
os.system("%s%s print -o %s/%s %s" % (p4cmd, p4opt, module, dest[:where], list[0]))
|
||||||
count = count + 1
|
count = count + 1
|
||||||
|
|
||||||
if count == 0:
|
if count == 0:
|
||||||
bb.error("Fetch: No files gathered from the P4 fetch")
|
bb.msg.error(bb.msg.domain.Fetcher, "Fetch: No files gathered from the P4 fetch")
|
||||||
raise FetchError(module)
|
raise FetchError(module)
|
||||||
|
|
||||||
myret = os.system("tar -czf %s %s" % (ud.localpath, module))
|
myret = os.system("tar -czf %s %s" % (ud.localpath, module))
|
||||||
@@ -205,5 +206,3 @@ class Perforce(Fetch):
|
|||||||
raise FetchError(module)
|
raise FetchError(module)
|
||||||
# cleanup
|
# cleanup
|
||||||
os.system('rm -rf %s' % tmpfile)
|
os.system('rm -rf %s' % tmpfile)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,10 @@ BitBake "Fetch" repo (git) implementation
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import os, re
|
import os
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch
|
from bb.fetch import Fetch
|
||||||
from bb.fetch import FetchError
|
|
||||||
from bb.fetch import runfetchcmd
|
from bb.fetch import runfetchcmd
|
||||||
|
|
||||||
class Repo(Fetch):
|
class Repo(Fetch):
|
||||||
|
|||||||
@@ -114,5 +114,5 @@ class SSH(Fetch):
|
|||||||
|
|
||||||
(exitstatus, output) = commands.getstatusoutput(cmd)
|
(exitstatus, output) = commands.getstatusoutput(cmd)
|
||||||
if exitstatus != 0:
|
if exitstatus != 0:
|
||||||
print output
|
print(output)
|
||||||
raise FetchError('Unable to fetch %s' % url)
|
raise FetchError('Unable to fetch %s' % url)
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class Svn(Fetch):
|
|||||||
ud.revision = rev
|
ud.revision = rev
|
||||||
ud.date = ""
|
ud.date = ""
|
||||||
else:
|
else:
|
||||||
ud.revision = ""
|
ud.revision = ""
|
||||||
|
|
||||||
ud.localfile = data.expand('%s_%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision, ud.date), d)
|
ud.localfile = data.expand('%s_%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision, ud.date), d)
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import bb
|
|||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch
|
from bb.fetch import Fetch
|
||||||
from bb.fetch import FetchError
|
from bb.fetch import FetchError
|
||||||
|
from bb.fetch import encodeurl, decodeurl
|
||||||
|
from bb.fetch import runfetchcmd
|
||||||
|
|
||||||
class Wget(Fetch):
|
class Wget(Fetch):
|
||||||
"""Class to fetch urls via 'wget'"""
|
"""Class to fetch urls via 'wget'"""
|
||||||
@@ -37,11 +39,11 @@ class Wget(Fetch):
|
|||||||
"""
|
"""
|
||||||
Check to see if a given url can be fetched with wget.
|
Check to see if a given url can be fetched with wget.
|
||||||
"""
|
"""
|
||||||
return ud.type in ['http','https','ftp']
|
return ud.type in ['http', 'https', 'ftp']
|
||||||
|
|
||||||
def localpath(self, url, ud, d):
|
def localpath(self, url, ud, d):
|
||||||
|
|
||||||
url = bb.encodeurl([ud.type, ud.host, ud.path, ud.user, ud.pswd, {}])
|
url = encodeurl([ud.type, ud.host, ud.path, ud.user, ud.pswd, {}])
|
||||||
ud.basename = os.path.basename(ud.path)
|
ud.basename = os.path.basename(ud.path)
|
||||||
ud.localfile = data.expand(os.path.basename(url), d)
|
ud.localfile = data.expand(os.path.basename(url), d)
|
||||||
|
|
||||||
@@ -60,37 +62,16 @@ class Wget(Fetch):
|
|||||||
fetchcmd = data.getVar("FETCHCOMMAND", d, 1)
|
fetchcmd = data.getVar("FETCHCOMMAND", d, 1)
|
||||||
|
|
||||||
uri = uri.split(";")[0]
|
uri = uri.split(";")[0]
|
||||||
uri_decoded = list(bb.decodeurl(uri))
|
uri_decoded = list(decodeurl(uri))
|
||||||
uri_type = uri_decoded[0]
|
uri_type = uri_decoded[0]
|
||||||
uri_host = uri_decoded[1]
|
uri_host = uri_decoded[1]
|
||||||
|
|
||||||
bb.msg.note(1, bb.msg.domain.Fetcher, "fetch " + uri)
|
|
||||||
fetchcmd = fetchcmd.replace("${URI}", uri.split(";")[0])
|
fetchcmd = fetchcmd.replace("${URI}", uri.split(";")[0])
|
||||||
fetchcmd = fetchcmd.replace("${FILE}", ud.basename)
|
fetchcmd = fetchcmd.replace("${FILE}", ud.basename)
|
||||||
httpproxy = None
|
|
||||||
ftpproxy = None
|
bb.msg.note(1, bb.msg.domain.Fetcher, "fetch " + uri)
|
||||||
if uri_type == 'http':
|
|
||||||
httpproxy = data.getVar("HTTP_PROXY", d, True)
|
|
||||||
httpproxy_ignore = (data.getVar("HTTP_PROXY_IGNORE", d, True) or "").split()
|
|
||||||
for p in httpproxy_ignore:
|
|
||||||
if uri_host.endswith(p):
|
|
||||||
httpproxy = None
|
|
||||||
break
|
|
||||||
if uri_type == 'ftp':
|
|
||||||
ftpproxy = data.getVar("FTP_PROXY", d, True)
|
|
||||||
ftpproxy_ignore = (data.getVar("HTTP_PROXY_IGNORE", d, True) or "").split()
|
|
||||||
for p in ftpproxy_ignore:
|
|
||||||
if uri_host.endswith(p):
|
|
||||||
ftpproxy = None
|
|
||||||
break
|
|
||||||
if httpproxy:
|
|
||||||
fetchcmd = "http_proxy=" + httpproxy + " " + fetchcmd
|
|
||||||
if ftpproxy:
|
|
||||||
fetchcmd = "ftp_proxy=" + ftpproxy + " " + fetchcmd
|
|
||||||
bb.msg.debug(2, bb.msg.domain.Fetcher, "executing " + fetchcmd)
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "executing " + fetchcmd)
|
||||||
ret = os.system(fetchcmd)
|
runfetchcmd(fetchcmd, d)
|
||||||
if ret != 0:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Sanity check since wget can pretend it succeed when it didn't
|
# Sanity check since wget can pretend it succeed when it didn't
|
||||||
# Also, this used to happen if sourceforge sent us to the mirror page
|
# Also, this used to happen if sourceforge sent us to the mirror page
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
a method pool to do this task.
|
a method pool to do this task.
|
||||||
|
|
||||||
This pool will be used to compile and execute the functions. It
|
This pool will be used to compile and execute the functions. It
|
||||||
will be smart enough to
|
will be smart enough to
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from bb.utils import better_compile, better_exec
|
from bb.utils import better_compile, better_exec
|
||||||
@@ -43,8 +43,8 @@ def insert_method(modulename, code, fn):
|
|||||||
Add code of a module should be added. The methods
|
Add code of a module should be added. The methods
|
||||||
will be simply added, no checking will be done
|
will be simply added, no checking will be done
|
||||||
"""
|
"""
|
||||||
comp = better_compile(code, "<bb>", fn )
|
comp = better_compile(code, modulename, fn )
|
||||||
better_exec(comp, __builtins__, code, fn)
|
better_exec(comp, None, code, fn)
|
||||||
|
|
||||||
# now some instrumentation
|
# now some instrumentation
|
||||||
code = comp.co_names
|
code = comp.co_names
|
||||||
@@ -59,7 +59,7 @@ def insert_method(modulename, code, fn):
|
|||||||
def check_insert_method(modulename, code, fn):
|
def check_insert_method(modulename, code, fn):
|
||||||
"""
|
"""
|
||||||
Add the code if it wasnt added before. The module
|
Add the code if it wasnt added before. The module
|
||||||
name will be used for that
|
name will be used for that
|
||||||
|
|
||||||
Variables:
|
Variables:
|
||||||
@modulename a short name e.g. base.bbclass
|
@modulename a short name e.g. base.bbclass
|
||||||
@@ -81,4 +81,4 @@ def get_parsed_dict():
|
|||||||
"""
|
"""
|
||||||
shortcut
|
shortcut
|
||||||
"""
|
"""
|
||||||
return _parsed_methods
|
return _parsed_methods
|
||||||
|
|||||||
@@ -22,26 +22,32 @@ Message handling infrastructure for bitbake
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import sys, bb
|
import sys
|
||||||
from bb import event
|
import collections
|
||||||
|
import bb
|
||||||
debug_level = {}
|
import bb.event
|
||||||
|
|
||||||
|
debug_level = collections.defaultdict(lambda: 0)
|
||||||
verbose = False
|
verbose = False
|
||||||
|
|
||||||
domain = bb.utils.Enum(
|
def _NamedTuple(name, fields):
|
||||||
'Build',
|
Tuple = collections.namedtuple(name, " ".join(fields))
|
||||||
'Cache',
|
return Tuple(*range(len(fields)))
|
||||||
'Collection',
|
|
||||||
'Data',
|
domain = _NamedTuple("Domain", (
|
||||||
'Depends',
|
"Default",
|
||||||
'Fetcher',
|
"Build",
|
||||||
'Parsing',
|
"Cache",
|
||||||
'PersistData',
|
"Collection",
|
||||||
'Provider',
|
"Data",
|
||||||
'RunQueue',
|
"Depends",
|
||||||
'TaskData',
|
"Fetcher",
|
||||||
'Util')
|
"Parsing",
|
||||||
|
"PersistData",
|
||||||
|
"Provider",
|
||||||
|
"RunQueue",
|
||||||
|
"TaskData",
|
||||||
|
"Util"))
|
||||||
|
|
||||||
|
|
||||||
class MsgBase(bb.event.Event):
|
class MsgBase(bb.event.Event):
|
||||||
@@ -49,7 +55,7 @@ class MsgBase(bb.event.Event):
|
|||||||
|
|
||||||
def __init__(self, msg):
|
def __init__(self, msg):
|
||||||
self._message = msg
|
self._message = msg
|
||||||
event.Event.__init__(self)
|
bb.event.Event.__init__(self)
|
||||||
|
|
||||||
class MsgDebug(MsgBase):
|
class MsgDebug(MsgBase):
|
||||||
"""Debug Message"""
|
"""Debug Message"""
|
||||||
@@ -74,52 +80,65 @@ class MsgPlain(MsgBase):
|
|||||||
#
|
#
|
||||||
|
|
||||||
def set_debug_level(level):
|
def set_debug_level(level):
|
||||||
bb.msg.debug_level = {}
|
for d in domain:
|
||||||
for domain in bb.msg.domain:
|
debug_level[d] = level
|
||||||
bb.msg.debug_level[domain] = level
|
debug_level[domain.Default] = level
|
||||||
bb.msg.debug_level['default'] = level
|
|
||||||
|
def get_debug_level(msgdomain = domain.Default):
|
||||||
|
return debug_level[msgdomain]
|
||||||
|
|
||||||
def set_verbose(level):
|
def set_verbose(level):
|
||||||
bb.msg.verbose = level
|
verbose = level
|
||||||
|
|
||||||
def set_debug_domains(domains):
|
def set_debug_domains(strdomains):
|
||||||
for domain in domains:
|
for domainstr in strdomains:
|
||||||
found = False
|
for d in domain:
|
||||||
for ddomain in bb.msg.domain:
|
if domain._fields[d] == domainstr:
|
||||||
if domain == str(ddomain):
|
debug_level[d] += 1
|
||||||
bb.msg.debug_level[ddomain] = bb.msg.debug_level[ddomain] + 1
|
break
|
||||||
found = True
|
else:
|
||||||
if not found:
|
warn(None, "Logging domain %s is not valid, ignoring" % domainstr)
|
||||||
bb.msg.warn(None, "Logging domain %s is not valid, ignoring" % domain)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Message handling functions
|
# Message handling functions
|
||||||
#
|
#
|
||||||
|
|
||||||
def debug(level, domain, msg, fn = None):
|
def debug(level, msgdomain, msg, fn = None):
|
||||||
if not domain:
|
if not msgdomain:
|
||||||
domain = 'default'
|
msgdomain = domain.Default
|
||||||
if debug_level[domain] >= level:
|
|
||||||
|
if debug_level[msgdomain] >= level:
|
||||||
bb.event.fire(MsgDebug(msg), None)
|
bb.event.fire(MsgDebug(msg), None)
|
||||||
|
if bb.event.useStdout:
|
||||||
|
print('DEBUG: %s' % (msg))
|
||||||
|
|
||||||
def note(level, domain, msg, fn = None):
|
def note(level, msgdomain, msg, fn = None):
|
||||||
if not domain:
|
if not msgdomain:
|
||||||
domain = 'default'
|
msgdomain = domain.Default
|
||||||
if level == 1 or verbose or debug_level[domain] >= 1:
|
|
||||||
|
if level == 1 or verbose or debug_level[msgdomain] >= 1:
|
||||||
bb.event.fire(MsgNote(msg), None)
|
bb.event.fire(MsgNote(msg), None)
|
||||||
|
if bb.event.useStdout:
|
||||||
|
print('NOTE: %s' % (msg))
|
||||||
|
|
||||||
def warn(domain, msg, fn = None):
|
def warn(msgdomain, msg, fn = None):
|
||||||
bb.event.fire(MsgWarn(msg), None)
|
bb.event.fire(MsgWarn(msg), None)
|
||||||
|
if bb.event.useStdout:
|
||||||
|
print('WARNING: %s' % (msg))
|
||||||
|
|
||||||
def error(domain, msg, fn = None):
|
def error(msgdomain, msg, fn = None):
|
||||||
bb.event.fire(MsgError(msg), None)
|
bb.event.fire(MsgError(msg), None)
|
||||||
print 'ERROR: ' + msg
|
if bb.event.useStdout:
|
||||||
|
print('ERROR: %s' % (msg))
|
||||||
|
|
||||||
def fatal(domain, msg, fn = None):
|
def fatal(msgdomain, msg, fn = None):
|
||||||
bb.event.fire(MsgFatal(msg), None)
|
bb.event.fire(MsgFatal(msg), None)
|
||||||
print 'FATAL: ' + msg
|
|
||||||
|
if bb.event.useStdout:
|
||||||
|
print('FATAL: %s' % (msg))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def plain(msg, fn = None):
|
def plain(msg, fn = None):
|
||||||
bb.event.fire(MsgPlain(msg), None)
|
bb.event.fire(MsgPlain(msg), None)
|
||||||
|
if bb.event.useStdout:
|
||||||
|
print(msg)
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ File parsers for the BitBake build tools.
|
|||||||
#
|
#
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
__all__ = [ 'ParseError', 'SkipPackage', 'cached_mtime', 'mark_dependency',
|
|
||||||
'supports', 'handle', 'init' ]
|
|
||||||
handlers = []
|
handlers = []
|
||||||
|
|
||||||
import bb, os
|
import bb, os
|
||||||
|
import bb.utils
|
||||||
|
import bb.siggen
|
||||||
|
|
||||||
class ParseError(Exception):
|
class ParseError(Exception):
|
||||||
"""Exception raised when parsing fails"""
|
"""Exception raised when parsing fails"""
|
||||||
@@ -38,12 +38,12 @@ class SkipPackage(Exception):
|
|||||||
|
|
||||||
__mtime_cache = {}
|
__mtime_cache = {}
|
||||||
def cached_mtime(f):
|
def cached_mtime(f):
|
||||||
if not __mtime_cache.has_key(f):
|
if f not in __mtime_cache:
|
||||||
__mtime_cache[f] = os.stat(f)[8]
|
__mtime_cache[f] = os.stat(f)[8]
|
||||||
return __mtime_cache[f]
|
return __mtime_cache[f]
|
||||||
|
|
||||||
def cached_mtime_noerror(f):
|
def cached_mtime_noerror(f):
|
||||||
if not __mtime_cache.has_key(f):
|
if f not in __mtime_cache:
|
||||||
try:
|
try:
|
||||||
__mtime_cache[f] = os.stat(f)[8]
|
__mtime_cache[f] = os.stat(f)[8]
|
||||||
except OSError:
|
except OSError:
|
||||||
@@ -57,8 +57,8 @@ def update_mtime(f):
|
|||||||
def mark_dependency(d, f):
|
def mark_dependency(d, f):
|
||||||
if f.startswith('./'):
|
if f.startswith('./'):
|
||||||
f = "%s/%s" % (os.getcwd(), f[2:])
|
f = "%s/%s" % (os.getcwd(), f[2:])
|
||||||
deps = bb.data.getVar('__depends', d) or []
|
deps = bb.data.getVar('__depends', d) or set()
|
||||||
deps.append( (f, cached_mtime(f)) )
|
deps.update([(f, cached_mtime(f))])
|
||||||
bb.data.setVar('__depends', deps, d)
|
bb.data.setVar('__depends', deps, d)
|
||||||
|
|
||||||
def supports(fn, data):
|
def supports(fn, data):
|
||||||
@@ -80,11 +80,16 @@ def init(fn, data):
|
|||||||
if h['supports'](fn):
|
if h['supports'](fn):
|
||||||
return h['init'](data)
|
return h['init'](data)
|
||||||
|
|
||||||
|
def init_parser(d, dumpsigs):
|
||||||
|
bb.parse.siggen = bb.siggen.init(d, dumpsigs)
|
||||||
|
|
||||||
def resolve_file(fn, d):
|
def resolve_file(fn, d):
|
||||||
if not os.path.isabs(fn):
|
if not os.path.isabs(fn):
|
||||||
fn = bb.which(bb.data.getVar("BBPATH", d, 1), fn)
|
bbpath = bb.data.getVar("BBPATH", d, True)
|
||||||
if not fn:
|
newfn = bb.which(bbpath, fn)
|
||||||
raise IOError("file %s not found" % fn)
|
if not newfn:
|
||||||
|
raise IOError("file %s not found in %s" % (fn, bbpath))
|
||||||
|
fn = newfn
|
||||||
|
|
||||||
bb.msg.debug(2, bb.msg.domain.Parsing, "LOAD %s" % fn)
|
bb.msg.debug(2, bb.msg.domain.Parsing, "LOAD %s" % fn)
|
||||||
return fn
|
return fn
|
||||||
|
|||||||
@@ -21,8 +21,11 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from future_builtins import filter
|
||||||
import bb, re, string
|
import bb, re, string
|
||||||
from itertools import chain
|
from bb import methodpool
|
||||||
|
import itertools
|
||||||
|
|
||||||
__word__ = re.compile(r"\S+")
|
__word__ = re.compile(r"\S+")
|
||||||
__parsed_methods__ = bb.methodpool.get_parsed_dict()
|
__parsed_methods__ = bb.methodpool.get_parsed_dict()
|
||||||
@@ -30,7 +33,8 @@ _bbversions_re = re.compile(r"\[(?P<from>[0-9]+)-(?P<to>[0-9]+)\]")
|
|||||||
|
|
||||||
class StatementGroup(list):
|
class StatementGroup(list):
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
map(lambda x: x.eval(data), self)
|
for statement in self:
|
||||||
|
statement.eval(data)
|
||||||
|
|
||||||
class AstNode(object):
|
class AstNode(object):
|
||||||
pass
|
pass
|
||||||
@@ -103,7 +107,6 @@ class DataNode(AstNode):
|
|||||||
val = groupd["value"]
|
val = groupd["value"]
|
||||||
|
|
||||||
if 'flag' in groupd and groupd['flag'] != None:
|
if 'flag' in groupd and groupd['flag'] != None:
|
||||||
bb.msg.debug(3, bb.msg.domain.Parsing, "setVarFlag(%s, %s, %s, data)" % (key, groupd['flag'], val))
|
|
||||||
bb.data.setVarFlag(key, groupd['flag'], val, data)
|
bb.data.setVarFlag(key, groupd['flag'], val, data)
|
||||||
elif groupd["lazyques"]:
|
elif groupd["lazyques"]:
|
||||||
assigned = bb.data.getVar("__lazy_assigned", data) or []
|
assigned = bb.data.getVar("__lazy_assigned", data) or []
|
||||||
@@ -134,7 +137,8 @@ class MethodNode:
|
|||||||
bb.data.setVar(self.func_name, '\n'.join(self.body), data)
|
bb.data.setVar(self.func_name, '\n'.join(self.body), data)
|
||||||
|
|
||||||
class PythonMethodNode(AstNode):
|
class PythonMethodNode(AstNode):
|
||||||
def __init__(self, root, body, fn):
|
def __init__(self, funcname, root, body, fn):
|
||||||
|
self.func_name = funcname
|
||||||
self.root = root
|
self.root = root
|
||||||
self.body = body
|
self.body = body
|
||||||
self.fn = fn
|
self.fn = fn
|
||||||
@@ -143,9 +147,12 @@ class PythonMethodNode(AstNode):
|
|||||||
# Note we will add root to parsedmethods after having parse
|
# Note we will add root to parsedmethods after having parse
|
||||||
# 'this' file. This means we will not parse methods from
|
# 'this' file. This means we will not parse methods from
|
||||||
# bb classes twice
|
# bb classes twice
|
||||||
if not self.root in __parsed_methods__:
|
text = '\n'.join(self.body)
|
||||||
text = '\n'.join(self.body)
|
if not bb.methodpool.parsed_module(self.root):
|
||||||
bb.methodpool.insert_method(self.root, text, self.fn)
|
bb.methodpool.insert_method(self.root, text, self.fn)
|
||||||
|
bb.data.setVarFlag(self.func_name, "func", 1, data)
|
||||||
|
bb.data.setVarFlag(self.func_name, "python", 1, data)
|
||||||
|
bb.data.setVar(self.func_name, text, data)
|
||||||
|
|
||||||
class MethodFlagsNode(AstNode):
|
class MethodFlagsNode(AstNode):
|
||||||
def __init__(self, key, m):
|
def __init__(self, key, m):
|
||||||
@@ -254,7 +261,7 @@ class InheritNode(AstNode):
|
|||||||
|
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
bb.parse.BBHandler.inherit(self.n, data)
|
bb.parse.BBHandler.inherit(self.n, data)
|
||||||
|
|
||||||
def handleInclude(statements, m, fn, lineno, force):
|
def handleInclude(statements, m, fn, lineno, force):
|
||||||
statements.append(IncludeNode(m.group(1), fn, lineno, force))
|
statements.append(IncludeNode(m.group(1), fn, lineno, force))
|
||||||
|
|
||||||
@@ -267,8 +274,8 @@ def handleData(statements, groupd):
|
|||||||
def handleMethod(statements, func_name, lineno, fn, body):
|
def handleMethod(statements, func_name, lineno, fn, body):
|
||||||
statements.append(MethodNode(func_name, body, lineno, fn))
|
statements.append(MethodNode(func_name, body, lineno, fn))
|
||||||
|
|
||||||
def handlePythonMethod(statements, root, body, fn):
|
def handlePythonMethod(statements, funcname, root, body, fn):
|
||||||
statements.append(PythonMethodNode(root, body, fn))
|
statements.append(PythonMethodNode(funcname, root, body, fn))
|
||||||
|
|
||||||
def handleMethodFlags(statements, key, m):
|
def handleMethodFlags(statements, key, m):
|
||||||
statements.append(MethodFlagsNode(key, m))
|
statements.append(MethodFlagsNode(key, m))
|
||||||
@@ -293,7 +300,7 @@ def handleInherit(statements, m):
|
|||||||
n = __word__.findall(files)
|
n = __word__.findall(files)
|
||||||
statements.append(InheritNode(m.group(1)))
|
statements.append(InheritNode(m.group(1)))
|
||||||
|
|
||||||
def finalise(fn, d):
|
def finalize(fn, d, variant = None):
|
||||||
for lazykey in bb.data.getVar("__lazy_assigned", d) or ():
|
for lazykey in bb.data.getVar("__lazy_assigned", d) or ():
|
||||||
if bb.data.getVar(lazykey, d) is None:
|
if bb.data.getVar(lazykey, d) is None:
|
||||||
val = bb.data.getVarFlag(lazykey, "defaultval", d)
|
val = bb.data.getVarFlag(lazykey, "defaultval", d)
|
||||||
@@ -301,40 +308,23 @@ def finalise(fn, d):
|
|||||||
|
|
||||||
bb.data.expandKeys(d)
|
bb.data.expandKeys(d)
|
||||||
bb.data.update_data(d)
|
bb.data.update_data(d)
|
||||||
anonqueue = bb.data.getVar("__anonqueue", d, 1) or []
|
code = []
|
||||||
body = [x['content'] for x in anonqueue]
|
for funcname in bb.data.getVar("__BBANONFUNCS", d) or []:
|
||||||
flag = { 'python' : 1, 'func' : 1 }
|
code.append("%s(d)" % funcname)
|
||||||
bb.data.setVar("__anonfunc", "\n".join(body), d)
|
bb.utils.simple_exec("\n".join(code), {"d": d})
|
||||||
bb.data.setVarFlags("__anonfunc", flag, d)
|
|
||||||
from bb import build
|
|
||||||
try:
|
|
||||||
t = bb.data.getVar('T', d)
|
|
||||||
bb.data.setVar('T', '${TMPDIR}/anonfunc/', d)
|
|
||||||
anonfuncs = bb.data.getVar('__BBANONFUNCS', d) or []
|
|
||||||
code = ""
|
|
||||||
for f in anonfuncs:
|
|
||||||
code = code + " %s(d)\n" % f
|
|
||||||
bb.data.setVar("__anonfunc", code, d)
|
|
||||||
build.exec_func("__anonfunc", d)
|
|
||||||
bb.data.delVar('T', d)
|
|
||||||
if t:
|
|
||||||
bb.data.setVar('T', t, d)
|
|
||||||
except Exception, e:
|
|
||||||
bb.msg.debug(1, bb.msg.domain.Parsing, "Exception when executing anonymous function: %s" % e)
|
|
||||||
raise
|
|
||||||
bb.data.delVar("__anonqueue", d)
|
|
||||||
bb.data.delVar("__anonfunc", d)
|
|
||||||
bb.data.update_data(d)
|
bb.data.update_data(d)
|
||||||
|
|
||||||
all_handlers = {}
|
all_handlers = {}
|
||||||
for var in bb.data.getVar('__BBHANDLERS', d) or []:
|
for var in bb.data.getVar('__BBHANDLERS', d) or []:
|
||||||
# try to add the handler
|
# try to add the handler
|
||||||
handler = bb.data.getVar(var,d)
|
handler = bb.data.getVar(var, d)
|
||||||
bb.event.register(var, handler)
|
bb.event.register(var, handler)
|
||||||
|
|
||||||
tasklist = bb.data.getVar('__BBTASKS', d) or []
|
tasklist = bb.data.getVar('__BBTASKS', d) or []
|
||||||
bb.build.add_tasks(tasklist, d)
|
bb.build.add_tasks(tasklist, d)
|
||||||
|
|
||||||
|
bb.parse.siggen.finalise(fn, d, variant)
|
||||||
|
|
||||||
bb.event.fire(bb.event.RecipeParsed(fn), d)
|
bb.event.fire(bb.event.RecipeParsed(fn), d)
|
||||||
|
|
||||||
def _create_variants(datastores, names, function):
|
def _create_variants(datastores, names, function):
|
||||||
@@ -360,7 +350,7 @@ def _expand_versions(versions):
|
|||||||
versions = iter(versions)
|
versions = iter(versions)
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
version = versions.next()
|
version = next(versions)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -370,14 +360,18 @@ def _expand_versions(versions):
|
|||||||
else:
|
else:
|
||||||
newversions = expand_one(version, int(range_ver.group("from")),
|
newversions = expand_one(version, int(range_ver.group("from")),
|
||||||
int(range_ver.group("to")))
|
int(range_ver.group("to")))
|
||||||
versions = chain(newversions, versions)
|
versions = itertools.chain(newversions, versions)
|
||||||
|
|
||||||
def multi_finalize(fn, d):
|
def multi_finalize(fn, d):
|
||||||
safe_d = d
|
appends = (d.getVar("__BBAPPEND", True) or "").split()
|
||||||
|
for append in appends:
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Parsing, "Appending .bbappend file " + append + " to " + fn)
|
||||||
|
bb.parse.BBHandler.handle(append, d, True)
|
||||||
|
|
||||||
|
safe_d = d
|
||||||
d = bb.data.createCopy(safe_d)
|
d = bb.data.createCopy(safe_d)
|
||||||
try:
|
try:
|
||||||
finalise(fn, d)
|
finalize(fn, d)
|
||||||
except bb.parse.SkipPackage:
|
except bb.parse.SkipPackage:
|
||||||
bb.data.setVar("__SKIPPED", True, d)
|
bb.data.setVar("__SKIPPED", True, d)
|
||||||
datastores = {"": safe_d}
|
datastores = {"": safe_d}
|
||||||
@@ -420,7 +414,7 @@ def multi_finalize(fn, d):
|
|||||||
d = bb.data.createCopy(safe_d)
|
d = bb.data.createCopy(safe_d)
|
||||||
verfunc(pv, d, safe_d)
|
verfunc(pv, d, safe_d)
|
||||||
try:
|
try:
|
||||||
finalise(fn, d)
|
finalize(fn, d)
|
||||||
except bb.parse.SkipPackage:
|
except bb.parse.SkipPackage:
|
||||||
bb.data.setVar("__SKIPPED", True, d)
|
bb.data.setVar("__SKIPPED", True, d)
|
||||||
|
|
||||||
@@ -436,15 +430,15 @@ def multi_finalize(fn, d):
|
|||||||
safe_d.setVar("BBCLASSEXTEND", extended)
|
safe_d.setVar("BBCLASSEXTEND", extended)
|
||||||
_create_variants(datastores, extended.split(), extendfunc)
|
_create_variants(datastores, extended.split(), extendfunc)
|
||||||
|
|
||||||
for variant, variant_d in datastores.items():
|
for variant, variant_d in datastores.iteritems():
|
||||||
if variant:
|
if variant:
|
||||||
try:
|
try:
|
||||||
finalise(fn, variant_d)
|
finalize(fn, variant_d, variant)
|
||||||
except bb.parse.SkipPackage:
|
except bb.parse.SkipPackage:
|
||||||
bb.data.setVar("__SKIPPED", True, variant_d)
|
bb.data.setVar("__SKIPPED", True, variant_d)
|
||||||
|
|
||||||
if len(datastores) > 1:
|
if len(datastores) > 1:
|
||||||
variants = filter(None, datastores.keys())
|
variants = filter(None, datastores.iterkeys())
|
||||||
safe_d.setVar("__VARIANTS", " ".join(variants))
|
safe_d.setVar("__VARIANTS", " ".join(variants))
|
||||||
|
|
||||||
datastores[""] = d
|
datastores[""] = d
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
# Copyright (C) 2003, 2004 Chris Larson
|
||||||
# Copyright (C) 2003, 2004 Phil Blundell
|
# Copyright (C) 2003, 2004 Phil Blundell
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License version 2 as
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
# published by the Free Software Foundation.
|
# published by the Free Software Foundation.
|
||||||
@@ -25,15 +25,17 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import re, bb, os, sys, time, string
|
from __future__ import absolute_import
|
||||||
|
import re, bb, os
|
||||||
import bb.fetch, bb.build, bb.utils
|
import bb.fetch, bb.build, bb.utils
|
||||||
from bb import data, fetch
|
from bb import data
|
||||||
|
|
||||||
from ConfHandler import include, init
|
from . import ConfHandler
|
||||||
from bb.parse import ParseError, resolve_file, ast
|
from .. import resolve_file, ast
|
||||||
|
from .ConfHandler import include, init
|
||||||
|
|
||||||
# For compatibility
|
# For compatibility
|
||||||
from bb.parse import vars_from_file
|
bb.deprecate_import(__name__, "bb.parse", ["vars_from_file"])
|
||||||
|
|
||||||
__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
|
__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
|
||||||
__inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
|
__inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
|
||||||
@@ -68,8 +70,8 @@ def inherit(files, d):
|
|||||||
__inherit_cache = data.getVar('__inherit_cache', d) or []
|
__inherit_cache = data.getVar('__inherit_cache', d) or []
|
||||||
fn = ""
|
fn = ""
|
||||||
lineno = 0
|
lineno = 0
|
||||||
files = data.expand(files, d)
|
|
||||||
for file in files:
|
for file in files:
|
||||||
|
file = data.expand(file, d)
|
||||||
if file[0] != "/" and file[-8:] != ".bbclass":
|
if file[0] != "/" and file[-8:] != ".bbclass":
|
||||||
file = os.path.join('classes', '%s.bbclass' % file)
|
file = os.path.join('classes', '%s.bbclass' % file)
|
||||||
|
|
||||||
@@ -80,17 +82,17 @@ def inherit(files, d):
|
|||||||
include(fn, file, d, "inherit")
|
include(fn, file, d, "inherit")
|
||||||
__inherit_cache = data.getVar('__inherit_cache', d) or []
|
__inherit_cache = data.getVar('__inherit_cache', d) or []
|
||||||
|
|
||||||
def get_statements(filename, absolsute_filename, base_name):
|
def get_statements(filename, absolute_filename, base_name):
|
||||||
global cached_statements
|
global cached_statements
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return cached_statements[absolsute_filename]
|
return cached_statements[absolute_filename]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
file = open(absolsute_filename, 'r')
|
file = open(absolute_filename, 'r')
|
||||||
statements = ast.StatementGroup()
|
statements = ast.StatementGroup()
|
||||||
|
|
||||||
lineno = 0
|
lineno = 0
|
||||||
while 1:
|
while True:
|
||||||
lineno = lineno + 1
|
lineno = lineno + 1
|
||||||
s = file.readline()
|
s = file.readline()
|
||||||
if not s: break
|
if not s: break
|
||||||
@@ -101,7 +103,7 @@ def get_statements(filename, absolsute_filename, base_name):
|
|||||||
feeder(IN_PYTHON_EOF, "", filename, base_name, statements)
|
feeder(IN_PYTHON_EOF, "", filename, base_name, statements)
|
||||||
|
|
||||||
if filename.endswith(".bbclass") or filename.endswith(".inc"):
|
if filename.endswith(".bbclass") or filename.endswith(".inc"):
|
||||||
cached_statements[absolsute_filename] = statements
|
cached_statements[absolute_filename] = statements
|
||||||
return statements
|
return statements
|
||||||
|
|
||||||
def handle(fn, d, include):
|
def handle(fn, d, include):
|
||||||
@@ -118,7 +120,7 @@ def handle(fn, d, include):
|
|||||||
bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data, include)")
|
bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data, include)")
|
||||||
|
|
||||||
(root, ext) = os.path.splitext(os.path.basename(fn))
|
(root, ext) = os.path.splitext(os.path.basename(fn))
|
||||||
base_name = "%s%s" % (root,ext)
|
base_name = "%s%s" % (root, ext)
|
||||||
init(d)
|
init(d)
|
||||||
|
|
||||||
if ext == ".bbclass":
|
if ext == ".bbclass":
|
||||||
@@ -164,7 +166,7 @@ def handle(fn, d, include):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
def feeder(lineno, s, fn, root, statements):
|
def feeder(lineno, s, fn, root, statements):
|
||||||
global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, classes, bb, __residue__
|
global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__, __infunc__, __body__, classes, bb, __residue__
|
||||||
if __infunc__:
|
if __infunc__:
|
||||||
if s == '}':
|
if s == '}':
|
||||||
__body__.append('')
|
__body__.append('')
|
||||||
@@ -181,7 +183,7 @@ def feeder(lineno, s, fn, root, statements):
|
|||||||
__body__.append(s)
|
__body__.append(s)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
ast.handlePythonMethod(statements, root, __body__, fn)
|
ast.handlePythonMethod(statements, __inpython__, root, __body__, fn)
|
||||||
__body__ = []
|
__body__ = []
|
||||||
__inpython__ = False
|
__inpython__ = False
|
||||||
|
|
||||||
@@ -208,7 +210,8 @@ def feeder(lineno, s, fn, root, statements):
|
|||||||
m = __def_regexp__.match(s)
|
m = __def_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
__body__.append(s)
|
__body__.append(s)
|
||||||
__inpython__ = True
|
__inpython__ = m.group(1)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
m = __export_func_regexp__.match(s)
|
m = __export_func_regexp__.match(s)
|
||||||
@@ -231,10 +234,9 @@ def feeder(lineno, s, fn, root, statements):
|
|||||||
ast.handleInherit(statements, m)
|
ast.handleInherit(statements, m)
|
||||||
return
|
return
|
||||||
|
|
||||||
from bb.parse import ConfHandler
|
|
||||||
return ConfHandler.feeder(lineno, s, fn, statements)
|
return ConfHandler.feeder(lineno, s, fn, statements)
|
||||||
|
|
||||||
# Add us to the handlers list
|
# Add us to the handlers list
|
||||||
from bb.parse import handlers
|
from .. import handlers
|
||||||
handlers.append({'supports': supports, 'handle': handle, 'init': init})
|
handlers.append({'supports': supports, 'handle': handle, 'init': init})
|
||||||
del handlers
|
del handlers
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
# Copyright (C) 2003, 2004 Chris Larson
|
||||||
# Copyright (C) 2003, 2004 Phil Blundell
|
# Copyright (C) 2003, 2004 Phil Blundell
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License version 2 as
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
# published by the Free Software Foundation.
|
# published by the Free Software Foundation.
|
||||||
@@ -24,7 +24,8 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import re, bb.data, os, sys
|
import re, bb.data, os
|
||||||
|
import bb.utils
|
||||||
from bb.parse import ParseError, resolve_file, ast
|
from bb.parse import ParseError, resolve_file, ast
|
||||||
|
|
||||||
#__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}]+)\s*(?P<colon>:)?(?P<ques>\?)?=\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
|
#__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}]+)\s*(?P<colon>:)?(?P<ques>\?)?=\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
|
||||||
@@ -36,10 +37,7 @@ __export_regexp__ = re.compile( r"export\s+(.+)" )
|
|||||||
def init(data):
|
def init(data):
|
||||||
topdir = bb.data.getVar('TOPDIR', data)
|
topdir = bb.data.getVar('TOPDIR', data)
|
||||||
if not topdir:
|
if not topdir:
|
||||||
topdir = os.getcwd()
|
bb.data.setVar('TOPDIR', os.getcwd(), data)
|
||||||
bb.data.setVar('TOPDIR', topdir, data)
|
|
||||||
if not bb.data.getVar('BBPATH', data):
|
|
||||||
bb.fatal("The BBPATH environment variable must be set")
|
|
||||||
|
|
||||||
|
|
||||||
def supports(fn, d):
|
def supports(fn, d):
|
||||||
@@ -60,7 +58,7 @@ def include(oldfn, fn, data, error_out):
|
|||||||
if not os.path.isabs(fn):
|
if not os.path.isabs(fn):
|
||||||
dname = os.path.dirname(oldfn)
|
dname = os.path.dirname(oldfn)
|
||||||
bbpath = "%s:%s" % (dname, bb.data.getVar("BBPATH", data, 1))
|
bbpath = "%s:%s" % (dname, bb.data.getVar("BBPATH", data, 1))
|
||||||
abs_fn = bb.which(bbpath, fn)
|
abs_fn = bb.utils.which(bbpath, fn)
|
||||||
if abs_fn:
|
if abs_fn:
|
||||||
fn = abs_fn
|
fn = abs_fn
|
||||||
|
|
||||||
@@ -88,7 +86,7 @@ def handle(fn, data, include):
|
|||||||
|
|
||||||
statements = ast.StatementGroup()
|
statements = ast.StatementGroup()
|
||||||
lineno = 0
|
lineno = 0
|
||||||
while 1:
|
while True:
|
||||||
lineno = lineno + 1
|
lineno = lineno + 1
|
||||||
s = f.readline()
|
s = f.readline()
|
||||||
if not s: break
|
if not s: break
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ File parsers for the BitBake build tools.
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
#
|
#
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from . import ConfHandler
|
||||||
|
from . import BBHandler
|
||||||
|
|
||||||
__version__ = '1.0'
|
__version__ = '1.0'
|
||||||
|
|
||||||
__all__ = [ 'ConfHandler', 'BBHandler']
|
|
||||||
|
|
||||||
import ConfHandler
|
|
||||||
import BBHandler
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import bb, os
|
import bb, os
|
||||||
|
import bb.utils
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import sqlite3
|
import sqlite3
|
||||||
@@ -33,58 +34,63 @@ class PersistData:
|
|||||||
"""
|
"""
|
||||||
BitBake Persistent Data Store
|
BitBake Persistent Data Store
|
||||||
|
|
||||||
Used to store data in a central location such that other threads/tasks can
|
Used to store data in a central location such that other threads/tasks can
|
||||||
access them at some future date.
|
access them at some future date.
|
||||||
|
|
||||||
The "domain" is used as a key to isolate each data pool and in this
|
The "domain" is used as a key to isolate each data pool and in this
|
||||||
implementation corresponds to an SQL table. The SQL table consists of a
|
implementation corresponds to an SQL table. The SQL table consists of a
|
||||||
simple key and value pair.
|
simple key and value pair.
|
||||||
|
|
||||||
Why sqlite? It handles all the locking issues for us.
|
Why sqlite? It handles all the locking issues for us.
|
||||||
"""
|
"""
|
||||||
def __init__(self, d):
|
def __init__(self, d, persistent_database_connection):
|
||||||
|
if "connection" in persistent_database_connection:
|
||||||
|
self.cursor = persistent_database_connection["connection"].cursor()
|
||||||
|
return
|
||||||
self.cachedir = bb.data.getVar("PERSISTENT_DIR", d, True) or bb.data.getVar("CACHE", d, True)
|
self.cachedir = bb.data.getVar("PERSISTENT_DIR", d, True) or bb.data.getVar("CACHE", d, True)
|
||||||
if self.cachedir in [None, '']:
|
if self.cachedir in [None, '']:
|
||||||
bb.msg.fatal(bb.msg.domain.PersistData, "Please set the 'PERSISTENT_DIR' or 'CACHE' variable.")
|
bb.msg.fatal(bb.msg.domain.PersistData, "Please set the 'PERSISTENT_DIR' or 'CACHE' variable.")
|
||||||
try:
|
try:
|
||||||
os.stat(self.cachedir)
|
os.stat(self.cachedir)
|
||||||
except OSError:
|
except OSError:
|
||||||
bb.mkdirhier(self.cachedir)
|
bb.utils.mkdirhier(self.cachedir)
|
||||||
|
|
||||||
self.cachefile = os.path.join(self.cachedir,"bb_persist_data.sqlite3")
|
self.cachefile = os.path.join(self.cachedir, "bb_persist_data.sqlite3")
|
||||||
bb.msg.debug(1, bb.msg.domain.PersistData, "Using '%s' as the persistent data cache" % self.cachefile)
|
bb.msg.debug(1, bb.msg.domain.PersistData, "Using '%s' as the persistent data cache" % self.cachefile)
|
||||||
|
|
||||||
self.connection = sqlite3.connect(self.cachefile, timeout=5, isolation_level=None)
|
connection = sqlite3.connect(self.cachefile, timeout=5, isolation_level=None)
|
||||||
|
persistent_database_connection["connection"] = connection
|
||||||
|
self.cursor = persistent_database_connection["connection"].cursor()
|
||||||
|
|
||||||
def addDomain(self, domain):
|
def addDomain(self, domain):
|
||||||
"""
|
"""
|
||||||
Should be called before any domain is used
|
Should be called before any domain is used
|
||||||
Creates it if it doesn't exist.
|
Creates it if it doesn't exist.
|
||||||
"""
|
"""
|
||||||
self.connection.execute("CREATE TABLE IF NOT EXISTS %s(key TEXT, value TEXT);" % domain)
|
self._execute("CREATE TABLE IF NOT EXISTS %s(key TEXT, value TEXT);" % domain)
|
||||||
|
|
||||||
def delDomain(self, domain):
|
def delDomain(self, domain):
|
||||||
"""
|
"""
|
||||||
Removes a domain and all the data it contains
|
Removes a domain and all the data it contains
|
||||||
"""
|
"""
|
||||||
self.connection.execute("DROP TABLE IF EXISTS %s;" % domain)
|
self._execute("DROP TABLE IF EXISTS %s;" % domain)
|
||||||
|
|
||||||
def getKeyValues(self, domain):
|
def getKeyValues(self, domain):
|
||||||
"""
|
"""
|
||||||
Return a list of key + value pairs for a domain
|
Return a list of key + value pairs for a domain
|
||||||
"""
|
"""
|
||||||
ret = {}
|
ret = {}
|
||||||
data = self.connection.execute("SELECT key, value from %s;" % domain)
|
data = self._execute("SELECT key, value from %s;" % domain)
|
||||||
for row in data:
|
for row in data:
|
||||||
ret[str(row[0])] = str(row[1])
|
ret[str(row[0])] = str(row[1])
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def getValue(self, domain, key):
|
def getValue(self, domain, key):
|
||||||
"""
|
"""
|
||||||
Return the value of a key for a domain
|
Return the value of a key for a domain
|
||||||
"""
|
"""
|
||||||
data = self.connection.execute("SELECT * from %s where key=?;" % domain, [key])
|
data = self._execute("SELECT * from %s where key=?;" % domain, [key])
|
||||||
for row in data:
|
for row in data:
|
||||||
return row[1]
|
return row[1]
|
||||||
|
|
||||||
@@ -92,7 +98,7 @@ class PersistData:
|
|||||||
"""
|
"""
|
||||||
Sets the value of a key for a domain
|
Sets the value of a key for a domain
|
||||||
"""
|
"""
|
||||||
data = self.connection.execute("SELECT * from %s where key=?;" % domain, [key])
|
data = self._execute("SELECT * from %s where key=?;" % domain, [key])
|
||||||
rows = 0
|
rows = 0
|
||||||
for row in data:
|
for row in data:
|
||||||
rows = rows + 1
|
rows = rows + 1
|
||||||
@@ -107,15 +113,21 @@ class PersistData:
|
|||||||
"""
|
"""
|
||||||
self._execute("DELETE from %s where key=?;" % domain, [key])
|
self._execute("DELETE from %s where key=?;" % domain, [key])
|
||||||
|
|
||||||
|
#
|
||||||
|
# We wrap the sqlite execute calls as on contended machines or single threaded
|
||||||
|
# systems we can have multiple processes trying to access the DB at once and it seems
|
||||||
|
# sqlite sometimes doesn't wait for the timeout. We therefore loop but put in an
|
||||||
|
# emergency brake too
|
||||||
|
#
|
||||||
def _execute(self, *query):
|
def _execute(self, *query):
|
||||||
while True:
|
count = 0
|
||||||
|
while True:
|
||||||
try:
|
try:
|
||||||
self.connection.execute(*query)
|
ret = self.cursor.execute(*query)
|
||||||
return
|
#print "Had to retry %s times" % count
|
||||||
except sqlite3.OperationalError, e:
|
return ret
|
||||||
if 'database is locked' in str(e):
|
except sqlite3.OperationalError as e:
|
||||||
|
if 'database is locked' in str(e) and count < 500:
|
||||||
|
count = count + 1
|
||||||
continue
|
continue
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ def sortPriorities(pn, dataCache, pkg_pn = None):
|
|||||||
def preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r):
|
def preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r):
|
||||||
"""
|
"""
|
||||||
Check if the version pe,pv,pr is the preferred one.
|
Check if the version pe,pv,pr is the preferred one.
|
||||||
If there is preferred version defined and ends with '%', then pv has to start with that version after removing the '%'
|
If there is preferred version defined and ends with '%', then pv has to start with that version after removing the '%'
|
||||||
"""
|
"""
|
||||||
if (pr == preferred_r or preferred_r == None):
|
if (pr == preferred_r or preferred_r == None):
|
||||||
if (pe == preferred_e or preferred_e == None):
|
if (pe == preferred_e or preferred_e == None):
|
||||||
@@ -103,7 +103,7 @@ def findPreferredProvider(pn, cfgData, dataCache, pkg_pn = None, item = None):
|
|||||||
|
|
||||||
for file_set in pkg_pn:
|
for file_set in pkg_pn:
|
||||||
for f in file_set:
|
for f in file_set:
|
||||||
pe,pv,pr = dataCache.pkg_pepvpr[f]
|
pe, pv, pr = dataCache.pkg_pepvpr[f]
|
||||||
if preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r):
|
if preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r):
|
||||||
preferred_file = f
|
preferred_file = f
|
||||||
preferred_ver = (pe, pv, pr)
|
preferred_ver = (pe, pv, pr)
|
||||||
@@ -136,7 +136,7 @@ def findLatestProvider(pn, cfgData, dataCache, file_set):
|
|||||||
latest_p = 0
|
latest_p = 0
|
||||||
latest_f = None
|
latest_f = None
|
||||||
for file_name in file_set:
|
for file_name in file_set:
|
||||||
pe,pv,pr = dataCache.pkg_pepvpr[file_name]
|
pe, pv, pr = dataCache.pkg_pepvpr[file_name]
|
||||||
dp = dataCache.pkg_dp[file_name]
|
dp = dataCache.pkg_dp[file_name]
|
||||||
|
|
||||||
if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pe, pv, pr)) < 0)) or (dp > latest_p):
|
if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pe, pv, pr)) < 0)) or (dp > latest_p):
|
||||||
@@ -169,14 +169,14 @@ def findBestProvider(pn, cfgData, dataCache, pkg_pn = None, item = None):
|
|||||||
|
|
||||||
def _filterProviders(providers, item, cfgData, dataCache):
|
def _filterProviders(providers, item, cfgData, dataCache):
|
||||||
"""
|
"""
|
||||||
Take a list of providers and filter/reorder according to the
|
Take a list of providers and filter/reorder according to the
|
||||||
environment variables and previous build results
|
environment variables and previous build results
|
||||||
"""
|
"""
|
||||||
eligible = []
|
eligible = []
|
||||||
preferred_versions = {}
|
preferred_versions = {}
|
||||||
sortpkg_pn = {}
|
sortpkg_pn = {}
|
||||||
|
|
||||||
# The order of providers depends on the order of the files on the disk
|
# The order of providers depends on the order of the files on the disk
|
||||||
# up to here. Sort pkg_pn to make dependency issues reproducible rather
|
# up to here. Sort pkg_pn to make dependency issues reproducible rather
|
||||||
# than effectively random.
|
# than effectively random.
|
||||||
providers.sort()
|
providers.sort()
|
||||||
@@ -198,7 +198,7 @@ def _filterProviders(providers, item, cfgData, dataCache):
|
|||||||
if preferred_versions[pn][1]:
|
if preferred_versions[pn][1]:
|
||||||
eligible.append(preferred_versions[pn][1])
|
eligible.append(preferred_versions[pn][1])
|
||||||
|
|
||||||
# Now add latest verisons
|
# Now add latest versions
|
||||||
for pn in sortpkg_pn:
|
for pn in sortpkg_pn:
|
||||||
if pn in preferred_versions and preferred_versions[pn][1]:
|
if pn in preferred_versions and preferred_versions[pn][1]:
|
||||||
continue
|
continue
|
||||||
@@ -226,7 +226,7 @@ def _filterProviders(providers, item, cfgData, dataCache):
|
|||||||
|
|
||||||
def filterProviders(providers, item, cfgData, dataCache):
|
def filterProviders(providers, item, cfgData, dataCache):
|
||||||
"""
|
"""
|
||||||
Take a list of providers and filter/reorder according to the
|
Take a list of providers and filter/reorder according to the
|
||||||
environment variables and previous build results
|
environment variables and previous build results
|
||||||
Takes a "normal" target item
|
Takes a "normal" target item
|
||||||
"""
|
"""
|
||||||
@@ -254,7 +254,7 @@ def filterProviders(providers, item, cfgData, dataCache):
|
|||||||
|
|
||||||
def filterProvidersRunTime(providers, item, cfgData, dataCache):
|
def filterProvidersRunTime(providers, item, cfgData, dataCache):
|
||||||
"""
|
"""
|
||||||
Take a list of providers and filter/reorder according to the
|
Take a list of providers and filter/reorder according to the
|
||||||
environment variables and previous build results
|
environment variables and previous build results
|
||||||
Takes a "runtime" target item
|
Takes a "runtime" target item
|
||||||
"""
|
"""
|
||||||
@@ -297,7 +297,7 @@ def getRuntimeProviders(dataCache, rdepend):
|
|||||||
rproviders = []
|
rproviders = []
|
||||||
|
|
||||||
if rdepend in dataCache.rproviders:
|
if rdepend in dataCache.rproviders:
|
||||||
rproviders += dataCache.rproviders[rdepend]
|
rproviders += dataCache.rproviders[rdepend]
|
||||||
|
|
||||||
if rdepend in dataCache.packages:
|
if rdepend in dataCache.packages:
|
||||||
rproviders += dataCache.packages[rdepend]
|
rproviders += dataCache.packages[rdepend]
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ class BBUIEventQueue:
|
|||||||
def queue_event(self, event):
|
def queue_event(self, event):
|
||||||
self.eventQueue.append(event)
|
self.eventQueue.append(event)
|
||||||
|
|
||||||
def system_quit( self ):
|
def system_quit( self ):
|
||||||
bb.event.unregister_UIHhandler(self.EventHandle)
|
bb.event.unregister_UIHhandler(self.EventHandle)
|
||||||
|
|
||||||
class BitBakeServer():
|
class BitBakeServer():
|
||||||
@@ -115,7 +115,7 @@ class BitBakeServer():
|
|||||||
|
|
||||||
def register_idle_function(self, function, data):
|
def register_idle_function(self, function, data):
|
||||||
"""Register a function to be called while the server is idle"""
|
"""Register a function to be called while the server is idle"""
|
||||||
assert callable(function)
|
assert hasattr(function, '__call__')
|
||||||
self._idlefuns[function] = data
|
self._idlefuns[function] = data
|
||||||
|
|
||||||
def idle_commands(self, delay):
|
def idle_commands(self, delay):
|
||||||
@@ -140,6 +140,7 @@ class BitBakeServer():
|
|||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
self.commands.runCommand(["stateShutdown"])
|
||||||
pass
|
pass
|
||||||
if nextsleep is not None:
|
if nextsleep is not None:
|
||||||
#print "Sleeping for %s (%s)" % (nextsleep, delay)
|
#print "Sleeping for %s (%s)" % (nextsleep, delay)
|
||||||
@@ -178,4 +179,3 @@ class BitBakeServerConnection():
|
|||||||
self.connection.terminateServer()
|
self.connection.terminateServer()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
|
|||||||
import inspect, select
|
import inspect, select
|
||||||
|
|
||||||
if sys.hexversion < 0x020600F0:
|
if sys.hexversion < 0x020600F0:
|
||||||
print "Sorry, python 2.6 or later is required for bitbake's XMLRPC mode"
|
print("Sorry, python 2.6 or later is required for bitbake's XMLRPC mode")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
class BitBakeServerCommands():
|
class BitBakeServerCommands():
|
||||||
@@ -74,7 +74,7 @@ class BitBakeServerCommands():
|
|||||||
Trigger the server to quit
|
Trigger the server to quit
|
||||||
"""
|
"""
|
||||||
self.server.quit = True
|
self.server.quit = True
|
||||||
print "Server (cooker) exitting"
|
print("Server (cooker) exitting")
|
||||||
return
|
return
|
||||||
|
|
||||||
def ping(self):
|
def ping(self):
|
||||||
@@ -89,8 +89,8 @@ class BitBakeServer(SimpleXMLRPCServer):
|
|||||||
|
|
||||||
def __init__(self, cooker, interface = ("localhost", 0)):
|
def __init__(self, cooker, interface = ("localhost", 0)):
|
||||||
"""
|
"""
|
||||||
Constructor
|
Constructor
|
||||||
"""
|
"""
|
||||||
SimpleXMLRPCServer.__init__(self, interface,
|
SimpleXMLRPCServer.__init__(self, interface,
|
||||||
requestHandler=SimpleXMLRPCRequestHandler,
|
requestHandler=SimpleXMLRPCRequestHandler,
|
||||||
logRequests=False, allow_none=True)
|
logRequests=False, allow_none=True)
|
||||||
@@ -112,7 +112,7 @@ class BitBakeServer(SimpleXMLRPCServer):
|
|||||||
|
|
||||||
def register_idle_function(self, function, data):
|
def register_idle_function(self, function, data):
|
||||||
"""Register a function to be called while the server is idle"""
|
"""Register a function to be called while the server is idle"""
|
||||||
assert callable(function)
|
assert hasattr(function, '__call__')
|
||||||
self._idlefuns[function] = data
|
self._idlefuns[function] = data
|
||||||
|
|
||||||
def serve_forever(self):
|
def serve_forever(self):
|
||||||
@@ -146,7 +146,7 @@ class BitBakeServer(SimpleXMLRPCServer):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
pass
|
pass
|
||||||
if nextsleep is None and len(self._idlefuns) > 0:
|
if nextsleep is None and len(self._idlefuns) > 0:
|
||||||
nextsleep = 0
|
nextsleep = 0
|
||||||
self.timeout = nextsleep
|
self.timeout = nextsleep
|
||||||
# Tell idle functions we're exiting
|
# Tell idle functions we're exiting
|
||||||
for function, data in self._idlefuns.items():
|
for function, data in self._idlefuns.items():
|
||||||
@@ -175,7 +175,7 @@ class BitBakeServerConnection():
|
|||||||
def terminate(self):
|
def terminate(self):
|
||||||
# Don't wait for server indefinitely
|
# Don't wait for server indefinitely
|
||||||
import socket
|
import socket
|
||||||
socket.setdefaulttimeout(2)
|
socket.setdefaulttimeout(2)
|
||||||
try:
|
try:
|
||||||
self.events.system_quit()
|
self.events.system_quit()
|
||||||
except:
|
except:
|
||||||
@@ -184,4 +184,3 @@ class BitBakeServerConnection():
|
|||||||
self.connection.terminateServer()
|
self.connection.terminateServer()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -52,12 +52,14 @@ PROBLEMS:
|
|||||||
# Import and setup global variables
|
# Import and setup global variables
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from functools import reduce
|
||||||
try:
|
try:
|
||||||
set
|
set
|
||||||
except NameError:
|
except NameError:
|
||||||
from sets import Set as set
|
from sets import Set as set
|
||||||
import sys, os, readline, socket, httplib, urllib, commands, popen2, copy, shlex, Queue, fnmatch
|
import sys, os, readline, socket, httplib, urllib, commands, popen2, shlex, Queue, fnmatch
|
||||||
from bb import data, parse, build, fatal, cache, taskdata, runqueue, providers as Providers
|
from bb import data, parse, build, cache, taskdata, runqueue, providers as Providers
|
||||||
|
|
||||||
__version__ = "0.5.3.1"
|
__version__ = "0.5.3.1"
|
||||||
__credits__ = """BitBake Shell Version %s (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
|
__credits__ = """BitBake Shell Version %s (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
|
||||||
@@ -98,7 +100,7 @@ class BitBakeShellCommands:
|
|||||||
|
|
||||||
def _checkParsed( self ):
|
def _checkParsed( self ):
|
||||||
if not parsed:
|
if not parsed:
|
||||||
print "SHELL: This command needs to parse bbfiles..."
|
print("SHELL: This command needs to parse bbfiles...")
|
||||||
self.parse( None )
|
self.parse( None )
|
||||||
|
|
||||||
def _findProvider( self, item ):
|
def _findProvider( self, item ):
|
||||||
@@ -119,28 +121,28 @@ class BitBakeShellCommands:
|
|||||||
"""Register a new name for a command"""
|
"""Register a new name for a command"""
|
||||||
new, old = params
|
new, old = params
|
||||||
if not old in cmds:
|
if not old in cmds:
|
||||||
print "ERROR: Command '%s' not known" % old
|
print("ERROR: Command '%s' not known" % old)
|
||||||
else:
|
else:
|
||||||
cmds[new] = cmds[old]
|
cmds[new] = cmds[old]
|
||||||
print "OK"
|
print("OK")
|
||||||
alias.usage = "<alias> <command>"
|
alias.usage = "<alias> <command>"
|
||||||
|
|
||||||
def buffer( self, params ):
|
def buffer( self, params ):
|
||||||
"""Dump specified output buffer"""
|
"""Dump specified output buffer"""
|
||||||
index = params[0]
|
index = params[0]
|
||||||
print self._shell.myout.buffer( int( index ) )
|
print(self._shell.myout.buffer( int( index ) ))
|
||||||
buffer.usage = "<index>"
|
buffer.usage = "<index>"
|
||||||
|
|
||||||
def buffers( self, params ):
|
def buffers( self, params ):
|
||||||
"""Show the available output buffers"""
|
"""Show the available output buffers"""
|
||||||
commands = self._shell.myout.bufferedCommands()
|
commands = self._shell.myout.bufferedCommands()
|
||||||
if not commands:
|
if not commands:
|
||||||
print "SHELL: No buffered commands available yet. Start doing something."
|
print("SHELL: No buffered commands available yet. Start doing something.")
|
||||||
else:
|
else:
|
||||||
print "="*35, "Available Output Buffers", "="*27
|
print("="*35, "Available Output Buffers", "="*27)
|
||||||
for index, cmd in enumerate( commands ):
|
for index, cmd in enumerate( commands ):
|
||||||
print "| %s %s" % ( str( index ).ljust( 3 ), cmd )
|
print("| %s %s" % ( str( index ).ljust( 3 ), cmd ))
|
||||||
print "="*88
|
print("="*88)
|
||||||
|
|
||||||
def build( self, params, cmd = "build" ):
|
def build( self, params, cmd = "build" ):
|
||||||
"""Build a providee"""
|
"""Build a providee"""
|
||||||
@@ -149,7 +151,7 @@ class BitBakeShellCommands:
|
|||||||
self._checkParsed()
|
self._checkParsed()
|
||||||
names = globfilter( cooker.status.pkg_pn, globexpr )
|
names = globfilter( cooker.status.pkg_pn, globexpr )
|
||||||
if len( names ) == 0: names = [ globexpr ]
|
if len( names ) == 0: names = [ globexpr ]
|
||||||
print "SHELL: Building %s" % ' '.join( names )
|
print("SHELL: Building %s" % ' '.join( names ))
|
||||||
|
|
||||||
td = taskdata.TaskData(cooker.configuration.abort)
|
td = taskdata.TaskData(cooker.configuration.abort)
|
||||||
localdata = data.createCopy(cooker.configuration.data)
|
localdata = data.createCopy(cooker.configuration.data)
|
||||||
@@ -168,22 +170,22 @@ class BitBakeShellCommands:
|
|||||||
tasks.append([name, "do_%s" % cmd])
|
tasks.append([name, "do_%s" % cmd])
|
||||||
|
|
||||||
td.add_unresolved(localdata, cooker.status)
|
td.add_unresolved(localdata, cooker.status)
|
||||||
|
|
||||||
rq = runqueue.RunQueue(cooker, localdata, cooker.status, td, tasks)
|
rq = runqueue.RunQueue(cooker, localdata, cooker.status, td, tasks)
|
||||||
rq.prepare_runqueue()
|
rq.prepare_runqueue()
|
||||||
rq.execute_runqueue()
|
rq.execute_runqueue()
|
||||||
|
|
||||||
except Providers.NoProvider:
|
except Providers.NoProvider:
|
||||||
print "ERROR: No Provider"
|
print("ERROR: No Provider")
|
||||||
last_exception = Providers.NoProvider
|
last_exception = Providers.NoProvider
|
||||||
|
|
||||||
except runqueue.TaskFailure, fnids:
|
except runqueue.TaskFailure as fnids:
|
||||||
for fnid in fnids:
|
for fnid in fnids:
|
||||||
print "ERROR: '%s' failed" % td.fn_index[fnid]
|
print("ERROR: '%s' failed" % td.fn_index[fnid])
|
||||||
last_exception = runqueue.TaskFailure
|
last_exception = runqueue.TaskFailure
|
||||||
|
|
||||||
except build.EventException, e:
|
except build.EventException as e:
|
||||||
print "ERROR: Couldn't build '%s'" % names
|
print("ERROR: Couldn't build '%s'" % names)
|
||||||
last_exception = e
|
last_exception = e
|
||||||
|
|
||||||
|
|
||||||
@@ -216,7 +218,7 @@ class BitBakeShellCommands:
|
|||||||
if bbfile is not None:
|
if bbfile is not None:
|
||||||
os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), bbfile ) )
|
os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), bbfile ) )
|
||||||
else:
|
else:
|
||||||
print "ERROR: Nothing provides '%s'" % name
|
print("ERROR: Nothing provides '%s'" % name)
|
||||||
edit.usage = "<providee>"
|
edit.usage = "<providee>"
|
||||||
|
|
||||||
def environment( self, params ):
|
def environment( self, params ):
|
||||||
@@ -239,14 +241,14 @@ class BitBakeShellCommands:
|
|||||||
global last_exception
|
global last_exception
|
||||||
name = params[0]
|
name = params[0]
|
||||||
bf = completeFilePath( name )
|
bf = completeFilePath( name )
|
||||||
print "SHELL: Calling '%s' on '%s'" % ( cmd, bf )
|
print("SHELL: Calling '%s' on '%s'" % ( cmd, bf ))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cooker.buildFile(bf, cmd)
|
cooker.buildFile(bf, cmd)
|
||||||
except parse.ParseError:
|
except parse.ParseError:
|
||||||
print "ERROR: Unable to open or parse '%s'" % bf
|
print("ERROR: Unable to open or parse '%s'" % bf)
|
||||||
except build.EventException, e:
|
except build.EventException as e:
|
||||||
print "ERROR: Couldn't build '%s'" % name
|
print("ERROR: Couldn't build '%s'" % name)
|
||||||
last_exception = e
|
last_exception = e
|
||||||
|
|
||||||
fileBuild.usage = "<bbfile>"
|
fileBuild.usage = "<bbfile>"
|
||||||
@@ -270,62 +272,62 @@ class BitBakeShellCommands:
|
|||||||
def fileReparse( self, params ):
|
def fileReparse( self, params ):
|
||||||
"""(re)Parse a bb file"""
|
"""(re)Parse a bb file"""
|
||||||
bbfile = params[0]
|
bbfile = params[0]
|
||||||
print "SHELL: Parsing '%s'" % bbfile
|
print("SHELL: Parsing '%s'" % bbfile)
|
||||||
parse.update_mtime( bbfile )
|
parse.update_mtime( bbfile )
|
||||||
cooker.bb_cache.cacheValidUpdate(bbfile)
|
cooker.bb_cache.cacheValidUpdate(bbfile)
|
||||||
fromCache = cooker.bb_cache.loadData(bbfile, cooker.configuration.data, cooker.status)
|
fromCache = cooker.bb_cache.loadData(bbfile, cooker.configuration.data, cooker.status)
|
||||||
cooker.bb_cache.sync()
|
cooker.bb_cache.sync()
|
||||||
if False: #fromCache:
|
if False: #fromCache:
|
||||||
print "SHELL: File has not been updated, not reparsing"
|
print("SHELL: File has not been updated, not reparsing")
|
||||||
else:
|
else:
|
||||||
print "SHELL: Parsed"
|
print("SHELL: Parsed")
|
||||||
fileReparse.usage = "<bbfile>"
|
fileReparse.usage = "<bbfile>"
|
||||||
|
|
||||||
def abort( self, params ):
|
def abort( self, params ):
|
||||||
"""Toggle abort task execution flag (see bitbake -k)"""
|
"""Toggle abort task execution flag (see bitbake -k)"""
|
||||||
cooker.configuration.abort = not cooker.configuration.abort
|
cooker.configuration.abort = not cooker.configuration.abort
|
||||||
print "SHELL: Abort Flag is now '%s'" % repr( cooker.configuration.abort )
|
print("SHELL: Abort Flag is now '%s'" % repr( cooker.configuration.abort ))
|
||||||
|
|
||||||
def force( self, params ):
|
def force( self, params ):
|
||||||
"""Toggle force task execution flag (see bitbake -f)"""
|
"""Toggle force task execution flag (see bitbake -f)"""
|
||||||
cooker.configuration.force = not cooker.configuration.force
|
cooker.configuration.force = not cooker.configuration.force
|
||||||
print "SHELL: Force Flag is now '%s'" % repr( cooker.configuration.force )
|
print("SHELL: Force Flag is now '%s'" % repr( cooker.configuration.force ))
|
||||||
|
|
||||||
def help( self, params ):
|
def help( self, params ):
|
||||||
"""Show a comprehensive list of commands and their purpose"""
|
"""Show a comprehensive list of commands and their purpose"""
|
||||||
print "="*30, "Available Commands", "="*30
|
print("="*30, "Available Commands", "="*30)
|
||||||
for cmd in sorted(cmds):
|
for cmd in sorted(cmds):
|
||||||
function,numparams,usage,helptext = cmds[cmd]
|
function, numparams, usage, helptext = cmds[cmd]
|
||||||
print "| %s | %s" % (usage.ljust(30), helptext)
|
print("| %s | %s" % (usage.ljust(30), helptext))
|
||||||
print "="*78
|
print("="*78)
|
||||||
|
|
||||||
def lastError( self, params ):
|
def lastError( self, params ):
|
||||||
"""Show the reason or log that was produced by the last BitBake event exception"""
|
"""Show the reason or log that was produced by the last BitBake event exception"""
|
||||||
if last_exception is None:
|
if last_exception is None:
|
||||||
print "SHELL: No Errors yet (Phew)..."
|
print("SHELL: No Errors yet (Phew)...")
|
||||||
else:
|
else:
|
||||||
reason, event = last_exception.args
|
reason, event = last_exception.args
|
||||||
print "SHELL: Reason for the last error: '%s'" % reason
|
print("SHELL: Reason for the last error: '%s'" % reason)
|
||||||
if ':' in reason:
|
if ':' in reason:
|
||||||
msg, filename = reason.split( ':' )
|
msg, filename = reason.split( ':' )
|
||||||
filename = filename.strip()
|
filename = filename.strip()
|
||||||
print "SHELL: Dumping log file for last error:"
|
print("SHELL: Dumping log file for last error:")
|
||||||
try:
|
try:
|
||||||
print open( filename ).read()
|
print(open( filename ).read())
|
||||||
except IOError:
|
except IOError:
|
||||||
print "ERROR: Couldn't open '%s'" % filename
|
print("ERROR: Couldn't open '%s'" % filename)
|
||||||
|
|
||||||
def match( self, params ):
|
def match( self, params ):
|
||||||
"""Dump all files or providers matching a glob expression"""
|
"""Dump all files or providers matching a glob expression"""
|
||||||
what, globexpr = params
|
what, globexpr = params
|
||||||
if what == "files":
|
if what == "files":
|
||||||
self._checkParsed()
|
self._checkParsed()
|
||||||
for key in globfilter( cooker.status.pkg_fn, globexpr ): print key
|
for key in globfilter( cooker.status.pkg_fn, globexpr ): print(key)
|
||||||
elif what == "providers":
|
elif what == "providers":
|
||||||
self._checkParsed()
|
self._checkParsed()
|
||||||
for key in globfilter( cooker.status.pkg_pn, globexpr ): print key
|
for key in globfilter( cooker.status.pkg_pn, globexpr ): print(key)
|
||||||
else:
|
else:
|
||||||
print "Usage: match %s" % self.print_.usage
|
print("Usage: match %s" % self.print_.usage)
|
||||||
match.usage = "<files|providers> <glob>"
|
match.usage = "<files|providers> <glob>"
|
||||||
|
|
||||||
def new( self, params ):
|
def new( self, params ):
|
||||||
@@ -335,15 +337,15 @@ class BitBakeShellCommands:
|
|||||||
fulldirname = "%s/%s" % ( packages, dirname )
|
fulldirname = "%s/%s" % ( packages, dirname )
|
||||||
|
|
||||||
if not os.path.exists( fulldirname ):
|
if not os.path.exists( fulldirname ):
|
||||||
print "SHELL: Creating '%s'" % fulldirname
|
print("SHELL: Creating '%s'" % fulldirname)
|
||||||
os.mkdir( fulldirname )
|
os.mkdir( fulldirname )
|
||||||
if os.path.exists( fulldirname ) and os.path.isdir( fulldirname ):
|
if os.path.exists( fulldirname ) and os.path.isdir( fulldirname ):
|
||||||
if os.path.exists( "%s/%s" % ( fulldirname, filename ) ):
|
if os.path.exists( "%s/%s" % ( fulldirname, filename ) ):
|
||||||
print "SHELL: ERROR: %s/%s already exists" % ( fulldirname, filename )
|
print("SHELL: ERROR: %s/%s already exists" % ( fulldirname, filename ))
|
||||||
return False
|
return False
|
||||||
print "SHELL: Creating '%s/%s'" % ( fulldirname, filename )
|
print("SHELL: Creating '%s/%s'" % ( fulldirname, filename ))
|
||||||
newpackage = open( "%s/%s" % ( fulldirname, filename ), "w" )
|
newpackage = open( "%s/%s" % ( fulldirname, filename ), "w" )
|
||||||
print >>newpackage,"""DESCRIPTION = ""
|
print("""DESCRIPTION = ""
|
||||||
SECTION = ""
|
SECTION = ""
|
||||||
AUTHOR = ""
|
AUTHOR = ""
|
||||||
HOMEPAGE = ""
|
HOMEPAGE = ""
|
||||||
@@ -370,7 +372,7 @@ SRC_URI = ""
|
|||||||
#do_install() {
|
#do_install() {
|
||||||
#
|
#
|
||||||
#}
|
#}
|
||||||
"""
|
""", file=newpackage)
|
||||||
newpackage.close()
|
newpackage.close()
|
||||||
os.system( "%s %s/%s" % ( os.environ.get( "EDITOR" ), fulldirname, filename ) )
|
os.system( "%s %s/%s" % ( os.environ.get( "EDITOR" ), fulldirname, filename ) )
|
||||||
new.usage = "<directory> <filename>"
|
new.usage = "<directory> <filename>"
|
||||||
@@ -390,14 +392,14 @@ SRC_URI = ""
|
|||||||
def pasteLog( self, params ):
|
def pasteLog( self, params ):
|
||||||
"""Send the last event exception error log (if there is one) to http://rafb.net/paste"""
|
"""Send the last event exception error log (if there is one) to http://rafb.net/paste"""
|
||||||
if last_exception is None:
|
if last_exception is None:
|
||||||
print "SHELL: No Errors yet (Phew)..."
|
print("SHELL: No Errors yet (Phew)...")
|
||||||
else:
|
else:
|
||||||
reason, event = last_exception.args
|
reason, event = last_exception.args
|
||||||
print "SHELL: Reason for the last error: '%s'" % reason
|
print("SHELL: Reason for the last error: '%s'" % reason)
|
||||||
if ':' in reason:
|
if ':' in reason:
|
||||||
msg, filename = reason.split( ':' )
|
msg, filename = reason.split( ':' )
|
||||||
filename = filename.strip()
|
filename = filename.strip()
|
||||||
print "SHELL: Pasting log file to pastebin..."
|
print("SHELL: Pasting log file to pastebin...")
|
||||||
|
|
||||||
file = open( filename ).read()
|
file = open( filename ).read()
|
||||||
sendToPastebin( "contents of " + filename, file )
|
sendToPastebin( "contents of " + filename, file )
|
||||||
@@ -419,23 +421,23 @@ SRC_URI = ""
|
|||||||
cooker.buildDepgraph()
|
cooker.buildDepgraph()
|
||||||
global parsed
|
global parsed
|
||||||
parsed = True
|
parsed = True
|
||||||
print
|
print()
|
||||||
|
|
||||||
def reparse( self, params ):
|
def reparse( self, params ):
|
||||||
"""(re)Parse a providee's bb file"""
|
"""(re)Parse a providee's bb file"""
|
||||||
bbfile = self._findProvider( params[0] )
|
bbfile = self._findProvider( params[0] )
|
||||||
if bbfile is not None:
|
if bbfile is not None:
|
||||||
print "SHELL: Found bbfile '%s' for '%s'" % ( bbfile, params[0] )
|
print("SHELL: Found bbfile '%s' for '%s'" % ( bbfile, params[0] ))
|
||||||
self.fileReparse( [ bbfile ] )
|
self.fileReparse( [ bbfile ] )
|
||||||
else:
|
else:
|
||||||
print "ERROR: Nothing provides '%s'" % params[0]
|
print("ERROR: Nothing provides '%s'" % params[0])
|
||||||
reparse.usage = "<providee>"
|
reparse.usage = "<providee>"
|
||||||
|
|
||||||
def getvar( self, params ):
|
def getvar( self, params ):
|
||||||
"""Dump the contents of an outer BitBake environment variable"""
|
"""Dump the contents of an outer BitBake environment variable"""
|
||||||
var = params[0]
|
var = params[0]
|
||||||
value = data.getVar( var, cooker.configuration.data, 1 )
|
value = data.getVar( var, cooker.configuration.data, 1 )
|
||||||
print value
|
print(value)
|
||||||
getvar.usage = "<variable>"
|
getvar.usage = "<variable>"
|
||||||
|
|
||||||
def peek( self, params ):
|
def peek( self, params ):
|
||||||
@@ -445,9 +447,9 @@ SRC_URI = ""
|
|||||||
if bbfile is not None:
|
if bbfile is not None:
|
||||||
the_data = cooker.bb_cache.loadDataFull(bbfile, cooker.configuration.data)
|
the_data = cooker.bb_cache.loadDataFull(bbfile, cooker.configuration.data)
|
||||||
value = the_data.getVar( var, 1 )
|
value = the_data.getVar( var, 1 )
|
||||||
print value
|
print(value)
|
||||||
else:
|
else:
|
||||||
print "ERROR: Nothing provides '%s'" % name
|
print("ERROR: Nothing provides '%s'" % name)
|
||||||
peek.usage = "<providee> <variable>"
|
peek.usage = "<providee> <variable>"
|
||||||
|
|
||||||
def poke( self, params ):
|
def poke( self, params ):
|
||||||
@@ -455,7 +457,7 @@ SRC_URI = ""
|
|||||||
name, var, value = params
|
name, var, value = params
|
||||||
bbfile = self._findProvider( name )
|
bbfile = self._findProvider( name )
|
||||||
if bbfile is not None:
|
if bbfile is not None:
|
||||||
print "ERROR: Sorry, this functionality is currently broken"
|
print("ERROR: Sorry, this functionality is currently broken")
|
||||||
#d = cooker.pkgdata[bbfile]
|
#d = cooker.pkgdata[bbfile]
|
||||||
#data.setVar( var, value, d )
|
#data.setVar( var, value, d )
|
||||||
|
|
||||||
@@ -463,7 +465,7 @@ SRC_URI = ""
|
|||||||
#cooker.pkgdata.setDirty(bbfile, d)
|
#cooker.pkgdata.setDirty(bbfile, d)
|
||||||
#print "OK"
|
#print "OK"
|
||||||
else:
|
else:
|
||||||
print "ERROR: Nothing provides '%s'" % name
|
print("ERROR: Nothing provides '%s'" % name)
|
||||||
poke.usage = "<providee> <variable> <value>"
|
poke.usage = "<providee> <variable> <value>"
|
||||||
|
|
||||||
def print_( self, params ):
|
def print_( self, params ):
|
||||||
@@ -471,12 +473,12 @@ SRC_URI = ""
|
|||||||
what = params[0]
|
what = params[0]
|
||||||
if what == "files":
|
if what == "files":
|
||||||
self._checkParsed()
|
self._checkParsed()
|
||||||
for key in cooker.status.pkg_fn: print key
|
for key in cooker.status.pkg_fn: print(key)
|
||||||
elif what == "providers":
|
elif what == "providers":
|
||||||
self._checkParsed()
|
self._checkParsed()
|
||||||
for key in cooker.status.providers: print key
|
for key in cooker.status.providers: print(key)
|
||||||
else:
|
else:
|
||||||
print "Usage: print %s" % self.print_.usage
|
print("Usage: print %s" % self.print_.usage)
|
||||||
print_.usage = "<files|providers>"
|
print_.usage = "<files|providers>"
|
||||||
|
|
||||||
def python( self, params ):
|
def python( self, params ):
|
||||||
@@ -496,7 +498,7 @@ SRC_URI = ""
|
|||||||
"""Set an outer BitBake environment variable"""
|
"""Set an outer BitBake environment variable"""
|
||||||
var, value = params
|
var, value = params
|
||||||
data.setVar( var, value, cooker.configuration.data )
|
data.setVar( var, value, cooker.configuration.data )
|
||||||
print "OK"
|
print("OK")
|
||||||
setVar.usage = "<variable> <value>"
|
setVar.usage = "<variable> <value>"
|
||||||
|
|
||||||
def rebuild( self, params ):
|
def rebuild( self, params ):
|
||||||
@@ -508,7 +510,7 @@ SRC_URI = ""
|
|||||||
def shell( self, params ):
|
def shell( self, params ):
|
||||||
"""Execute a shell command and dump the output"""
|
"""Execute a shell command and dump the output"""
|
||||||
if params != "":
|
if params != "":
|
||||||
print commands.getoutput( " ".join( params ) )
|
print(commands.getoutput( " ".join( params ) ))
|
||||||
shell.usage = "<...>"
|
shell.usage = "<...>"
|
||||||
|
|
||||||
def stage( self, params ):
|
def stage( self, params ):
|
||||||
@@ -518,17 +520,17 @@ SRC_URI = ""
|
|||||||
|
|
||||||
def status( self, params ):
|
def status( self, params ):
|
||||||
"""<just for testing>"""
|
"""<just for testing>"""
|
||||||
print "-" * 78
|
print("-" * 78)
|
||||||
print "building list = '%s'" % cooker.building_list
|
print("building list = '%s'" % cooker.building_list)
|
||||||
print "build path = '%s'" % cooker.build_path
|
print("build path = '%s'" % cooker.build_path)
|
||||||
print "consider_msgs_cache = '%s'" % cooker.consider_msgs_cache
|
print("consider_msgs_cache = '%s'" % cooker.consider_msgs_cache)
|
||||||
print "build stats = '%s'" % cooker.stats
|
print("build stats = '%s'" % cooker.stats)
|
||||||
if last_exception is not None: print "last_exception = '%s'" % repr( last_exception.args )
|
if last_exception is not None: print("last_exception = '%s'" % repr( last_exception.args ))
|
||||||
print "memory output contents = '%s'" % self._shell.myout._buffer
|
print("memory output contents = '%s'" % self._shell.myout._buffer)
|
||||||
|
|
||||||
def test( self, params ):
|
def test( self, params ):
|
||||||
"""<just for testing>"""
|
"""<just for testing>"""
|
||||||
print "testCommand called with '%s'" % params
|
print("testCommand called with '%s'" % params)
|
||||||
|
|
||||||
def unpack( self, params ):
|
def unpack( self, params ):
|
||||||
"""Execute 'unpack' on a providee"""
|
"""Execute 'unpack' on a providee"""
|
||||||
@@ -553,12 +555,12 @@ SRC_URI = ""
|
|||||||
try:
|
try:
|
||||||
providers = cooker.status.providers[item]
|
providers = cooker.status.providers[item]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print "SHELL: ERROR: Nothing provides", preferred
|
print("SHELL: ERROR: Nothing provides", preferred)
|
||||||
else:
|
else:
|
||||||
for provider in providers:
|
for provider in providers:
|
||||||
if provider == pf: provider = " (***) %s" % provider
|
if provider == pf: provider = " (***) %s" % provider
|
||||||
else: provider = " %s" % provider
|
else: provider = " %s" % provider
|
||||||
print provider
|
print(provider)
|
||||||
which.usage = "<providee>"
|
which.usage = "<providee>"
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
@@ -583,7 +585,7 @@ def sendToPastebin( desc, content ):
|
|||||||
mydata["nick"] = "%s@%s" % ( os.environ.get( "USER", "unknown" ), socket.gethostname() or "unknown" )
|
mydata["nick"] = "%s@%s" % ( os.environ.get( "USER", "unknown" ), socket.gethostname() or "unknown" )
|
||||||
mydata["text"] = content
|
mydata["text"] = content
|
||||||
params = urllib.urlencode( mydata )
|
params = urllib.urlencode( mydata )
|
||||||
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}
|
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
|
||||||
|
|
||||||
host = "rafb.net"
|
host = "rafb.net"
|
||||||
conn = httplib.HTTPConnection( "%s:80" % host )
|
conn = httplib.HTTPConnection( "%s:80" % host )
|
||||||
@@ -594,9 +596,9 @@ def sendToPastebin( desc, content ):
|
|||||||
|
|
||||||
if response.status == 302:
|
if response.status == 302:
|
||||||
location = response.getheader( "location" ) or "unknown"
|
location = response.getheader( "location" ) or "unknown"
|
||||||
print "SHELL: Pasted to http://%s%s" % ( host, location )
|
print("SHELL: Pasted to http://%s%s" % ( host, location ))
|
||||||
else:
|
else:
|
||||||
print "ERROR: %s %s" % ( response.status, response.reason )
|
print("ERROR: %s %s" % ( response.status, response.reason ))
|
||||||
|
|
||||||
def completer( text, state ):
|
def completer( text, state ):
|
||||||
"""Return a possible readline completion"""
|
"""Return a possible readline completion"""
|
||||||
@@ -643,7 +645,7 @@ def columnize( alist, width = 80 ):
|
|||||||
return reduce(lambda line, word, width=width: '%s%s%s' %
|
return reduce(lambda line, word, width=width: '%s%s%s' %
|
||||||
(line,
|
(line,
|
||||||
' \n'[(len(line[line.rfind('\n')+1:])
|
' \n'[(len(line[line.rfind('\n')+1:])
|
||||||
+ len(word.split('\n',1)[0]
|
+ len(word.split('\n', 1)[0]
|
||||||
) >= width)],
|
) >= width)],
|
||||||
word),
|
word),
|
||||||
alist
|
alist
|
||||||
@@ -718,7 +720,7 @@ class BitBakeShell:
|
|||||||
except IOError:
|
except IOError:
|
||||||
pass # It doesn't exist yet.
|
pass # It doesn't exist yet.
|
||||||
|
|
||||||
print __credits__
|
print(__credits__)
|
||||||
|
|
||||||
def cleanup( self ):
|
def cleanup( self ):
|
||||||
"""Write readline history and clean up resources"""
|
"""Write readline history and clean up resources"""
|
||||||
@@ -726,7 +728,7 @@ class BitBakeShell:
|
|||||||
try:
|
try:
|
||||||
readline.write_history_file( self.historyfilename )
|
readline.write_history_file( self.historyfilename )
|
||||||
except:
|
except:
|
||||||
print "SHELL: Unable to save command history"
|
print("SHELL: Unable to save command history")
|
||||||
|
|
||||||
def registerCommand( self, command, function, numparams = 0, usage = "", helptext = "" ):
|
def registerCommand( self, command, function, numparams = 0, usage = "", helptext = "" ):
|
||||||
"""Register a command"""
|
"""Register a command"""
|
||||||
@@ -740,11 +742,11 @@ class BitBakeShell:
|
|||||||
try:
|
try:
|
||||||
function, numparams, usage, helptext = cmds[command]
|
function, numparams, usage, helptext = cmds[command]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print "SHELL: ERROR: '%s' command is not a valid command." % command
|
print("SHELL: ERROR: '%s' command is not a valid command." % command)
|
||||||
self.myout.removeLast()
|
self.myout.removeLast()
|
||||||
else:
|
else:
|
||||||
if (numparams != -1) and (not len( params ) == numparams):
|
if (numparams != -1) and (not len( params ) == numparams):
|
||||||
print "Usage: '%s'" % usage
|
print("Usage: '%s'" % usage)
|
||||||
return
|
return
|
||||||
|
|
||||||
result = function( self.commands, params )
|
result = function( self.commands, params )
|
||||||
@@ -759,7 +761,7 @@ class BitBakeShell:
|
|||||||
if not cmdline:
|
if not cmdline:
|
||||||
continue
|
continue
|
||||||
if "|" in cmdline:
|
if "|" in cmdline:
|
||||||
print "ERROR: '|' in startup file is not allowed. Ignoring line"
|
print("ERROR: '|' in startup file is not allowed. Ignoring line")
|
||||||
continue
|
continue
|
||||||
self.commandQ.put( cmdline.strip() )
|
self.commandQ.put( cmdline.strip() )
|
||||||
|
|
||||||
@@ -801,10 +803,10 @@ class BitBakeShell:
|
|||||||
sys.stdout.write( pipe.fromchild.read() )
|
sys.stdout.write( pipe.fromchild.read() )
|
||||||
#
|
#
|
||||||
except EOFError:
|
except EOFError:
|
||||||
print
|
print()
|
||||||
return
|
return
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print
|
print()
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# Start function - called from the BitBake command line utility
|
# Start function - called from the BitBake command line utility
|
||||||
@@ -819,4 +821,4 @@ def start( aCooker ):
|
|||||||
bbshell.cleanup()
|
bbshell.cleanup()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print "SHELL: Sorry, this program should only be called by BitBake."
|
print("SHELL: Sorry, this program should only be called by BitBake.")
|
||||||
|
|||||||
260
bitbake/lib/bb/siggen.py
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
import hashlib
|
||||||
|
import re
|
||||||
|
|
||||||
|
try:
|
||||||
|
import cPickle as pickle
|
||||||
|
except ImportError:
|
||||||
|
import pickle
|
||||||
|
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
|
||||||
|
|
||||||
|
def init(d, dumpsigs):
|
||||||
|
siggens = [obj for obj in globals().itervalues()
|
||||||
|
if type(obj) is type and issubclass(obj, SignatureGenerator)]
|
||||||
|
|
||||||
|
desired = bb.data.getVar("BB_SIGNATURE_HANDLER", d, True) or "noop"
|
||||||
|
for sg in siggens:
|
||||||
|
if desired == sg.name:
|
||||||
|
return sg(d, dumpsigs)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
bb.error("Invalid signature generator '%s', using default 'noop' generator" % desired)
|
||||||
|
bb.error("Available generators: %s" % ", ".join(obj.name for obj in siggens))
|
||||||
|
return SignatureGenerator(d, dumpsigs)
|
||||||
|
|
||||||
|
class SignatureGenerator(object):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
name = "noop"
|
||||||
|
|
||||||
|
def __init__(self, data, dumpsigs):
|
||||||
|
return
|
||||||
|
|
||||||
|
def finalise(self, fn, d):
|
||||||
|
return
|
||||||
|
|
||||||
|
class SignatureGeneratorBasic(SignatureGenerator):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
name = "basic"
|
||||||
|
|
||||||
|
def __init__(self, data, dumpsigs):
|
||||||
|
self.basehash = {}
|
||||||
|
self.taskhash = {}
|
||||||
|
self.taskdeps = {}
|
||||||
|
self.runtaskdeps = {}
|
||||||
|
self.gendeps = {}
|
||||||
|
self.lookupcache = {}
|
||||||
|
self.basewhitelist = (data.getVar("BB_HASHBASE_WHITELIST", True) or "").split()
|
||||||
|
self.taskwhitelist = data.getVar("BB_HASHTASK_WHITELIST", True) or None
|
||||||
|
|
||||||
|
if self.taskwhitelist:
|
||||||
|
self.twl = re.compile(self.taskwhitelist)
|
||||||
|
else:
|
||||||
|
self.twl = None
|
||||||
|
|
||||||
|
self.dumpsigs = dumpsigs
|
||||||
|
|
||||||
|
def _build_data(self, fn, d):
|
||||||
|
|
||||||
|
taskdeps, gendeps = bb.data.generate_dependencies(d)
|
||||||
|
|
||||||
|
basehash = {}
|
||||||
|
lookupcache = {}
|
||||||
|
|
||||||
|
for task in taskdeps:
|
||||||
|
data = d.getVar(task, False)
|
||||||
|
lookupcache[task] = data
|
||||||
|
for dep in sorted(taskdeps[task]):
|
||||||
|
if dep in self.basewhitelist:
|
||||||
|
continue
|
||||||
|
if dep in lookupcache:
|
||||||
|
var = lookupcache[dep]
|
||||||
|
else:
|
||||||
|
var = d.getVar(dep, False)
|
||||||
|
lookupcache[dep] = var
|
||||||
|
if var:
|
||||||
|
data = data + var
|
||||||
|
self.basehash[fn + "." + task] = hashlib.md5(data).hexdigest()
|
||||||
|
#bb.note("Hash for %s is %s" % (task, tashhash[task]))
|
||||||
|
|
||||||
|
if self.dumpsigs:
|
||||||
|
self.taskdeps[fn] = taskdeps
|
||||||
|
self.gendeps[fn] = gendeps
|
||||||
|
self.lookupcache[fn] = lookupcache
|
||||||
|
|
||||||
|
return taskdeps
|
||||||
|
|
||||||
|
def finalise(self, fn, d, variant):
|
||||||
|
|
||||||
|
if variant:
|
||||||
|
fn = "virtual:" + variant + ":" + fn
|
||||||
|
|
||||||
|
taskdeps = self._build_data(fn, d)
|
||||||
|
|
||||||
|
#Slow but can be useful for debugging mismatched basehashes
|
||||||
|
#for task in self.taskdeps[fn]:
|
||||||
|
# self.dump_sigtask(fn, task, d.getVar("STAMP", True), False)
|
||||||
|
|
||||||
|
for task in taskdeps:
|
||||||
|
d.setVar("BB_BASEHASH_task-%s" % task, self.basehash[fn + "." + task])
|
||||||
|
|
||||||
|
def get_taskhash(self, fn, task, deps, dataCache):
|
||||||
|
k = fn + "." + task
|
||||||
|
data = dataCache.basetaskhash[k]
|
||||||
|
self.runtaskdeps[k] = deps
|
||||||
|
for dep in sorted(deps):
|
||||||
|
if self.twl and self.twl.search(dataCache.pkg_fn[fn]):
|
||||||
|
#bb.note("Skipping %s" % dep)
|
||||||
|
continue
|
||||||
|
if dep not in self.taskhash:
|
||||||
|
bb.fatal("%s is not in taskhash, caller isn't calling in dependency order?", dep)
|
||||||
|
data = data + self.taskhash[dep]
|
||||||
|
h = hashlib.md5(data).hexdigest()
|
||||||
|
self.taskhash[k] = h
|
||||||
|
#d.setVar("BB_TASKHASH_task-%s" % task, taskhash[task])
|
||||||
|
return h
|
||||||
|
|
||||||
|
def set_taskdata(self, hashes, deps):
|
||||||
|
self.runtaskdeps = deps
|
||||||
|
self.taskhash = hashes
|
||||||
|
|
||||||
|
def dump_sigtask(self, fn, task, stampbase, runtime):
|
||||||
|
k = fn + "." + task
|
||||||
|
if runtime == "customfile":
|
||||||
|
sigfile = stampbase
|
||||||
|
elif runtime:
|
||||||
|
sigfile = stampbase + "." + task + ".sigdata" + "." + self.taskhash[k]
|
||||||
|
else:
|
||||||
|
sigfile = stampbase + "." + task + ".sigbasedata" + "." + self.basehash[k]
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
data['basewhitelist'] = self.basewhitelist
|
||||||
|
data['taskwhitelist'] = self.taskwhitelist
|
||||||
|
data['taskdeps'] = self.taskdeps[fn][task]
|
||||||
|
data['basehash'] = self.basehash[k]
|
||||||
|
data['gendeps'] = {}
|
||||||
|
data['varvals'] = {}
|
||||||
|
data['varvals'][task] = self.lookupcache[fn][task]
|
||||||
|
for dep in self.taskdeps[fn][task]:
|
||||||
|
if dep in self.basewhitelist:
|
||||||
|
continue
|
||||||
|
data['gendeps'][dep] = self.gendeps[fn][dep]
|
||||||
|
data['varvals'][dep] = self.lookupcache[fn][dep]
|
||||||
|
|
||||||
|
if runtime:
|
||||||
|
data['runtaskdeps'] = self.runtaskdeps[k]
|
||||||
|
data['runtaskhashes'] = {}
|
||||||
|
for dep in data['runtaskdeps']:
|
||||||
|
data['runtaskhashes'][dep] = self.taskhash[dep]
|
||||||
|
|
||||||
|
p = pickle.Pickler(file(sigfile, "wb"), -1)
|
||||||
|
p.dump(data)
|
||||||
|
|
||||||
|
def dump_sigs(self, dataCache):
|
||||||
|
for fn in self.taskdeps:
|
||||||
|
for task in self.taskdeps[fn]:
|
||||||
|
k = fn + "." + task
|
||||||
|
if k not in self.taskhash:
|
||||||
|
continue
|
||||||
|
if dataCache.basetaskhash[k] != self.basehash[k]:
|
||||||
|
bb.error("Bitbake's cached basehash does not match the one we just generated!")
|
||||||
|
bb.error("The mismatched hashes were %s and %s" % (dataCache.basetaskhash[k], self.basehash[k]))
|
||||||
|
self.dump_sigtask(fn, task, dataCache.stamp[fn], True)
|
||||||
|
|
||||||
|
def dump_this_task(outfile, d):
|
||||||
|
fn = d.getVar("BB_FILENAME", True)
|
||||||
|
task = "do_" + d.getVar("BB_CURRENTTASK", True)
|
||||||
|
bb.parse.siggen.dump_sigtask(fn, task, outfile, "customfile")
|
||||||
|
|
||||||
|
def compare_sigfiles(a, b):
|
||||||
|
p1 = pickle.Unpickler(file(a, "rb"))
|
||||||
|
a_data = p1.load()
|
||||||
|
p2 = pickle.Unpickler(file(b, "rb"))
|
||||||
|
b_data = p2.load()
|
||||||
|
|
||||||
|
#print "Checking"
|
||||||
|
#print str(a_data)
|
||||||
|
#print str(b_data)
|
||||||
|
|
||||||
|
def dict_diff(a, b):
|
||||||
|
sa = set(a.keys())
|
||||||
|
sb = set(b.keys())
|
||||||
|
common = sa & sb
|
||||||
|
changed = set()
|
||||||
|
for i in common:
|
||||||
|
if a[i] != b[i]:
|
||||||
|
changed.add(i)
|
||||||
|
added = sa - sb
|
||||||
|
removed = sb - sa
|
||||||
|
return changed, added, removed
|
||||||
|
|
||||||
|
if 'basewhitelist' in a_data and a_data['basewhitelist'] != b_data['basewhitelist']:
|
||||||
|
print "basewhitelist changed from %s to %s" % (a_data['basewhitelist'], b_data['basewhitelist'])
|
||||||
|
|
||||||
|
if 'taskwhitelist' in a_data and a_data['taskwhitelist'] != b_data['taskwhitelist']:
|
||||||
|
print "taskwhitelist changed from %s to %s" % (a_data['taskwhitelist'], b_data['taskwhitelist'])
|
||||||
|
|
||||||
|
if a_data['taskdeps'] != b_data['taskdeps']:
|
||||||
|
print "Task dependencies changed from %s to %s" % (sorted(a_data['taskdeps']), sorted(b_data['taskdeps']))
|
||||||
|
|
||||||
|
if a_data['basehash'] != b_data['basehash']:
|
||||||
|
print "basehash changed from %s to %s" % (a_data['basehash'], b_data['basehash'])
|
||||||
|
|
||||||
|
changed, added, removed = dict_diff(a_data['gendeps'], b_data['gendeps'])
|
||||||
|
if changed:
|
||||||
|
for dep in changed:
|
||||||
|
print "List of dependencies for variable %s changed from %s to %s" % (dep, a_data['gendeps'][dep], b_data['gendeps'][dep])
|
||||||
|
if added:
|
||||||
|
for dep in added:
|
||||||
|
print "Dependency on variable %s was added" % (dep)
|
||||||
|
if removed:
|
||||||
|
for dep in removed:
|
||||||
|
print "Dependency on Variable %s was removed" % (dep)
|
||||||
|
|
||||||
|
|
||||||
|
changed, added, removed = dict_diff(a_data['varvals'], b_data['varvals'])
|
||||||
|
if changed:
|
||||||
|
for dep in changed:
|
||||||
|
print "Variable %s value changed from %s to %s" % (dep, a_data['varvals'][dep], b_data['varvals'][dep])
|
||||||
|
#if added:
|
||||||
|
# print "Dependency on variable %s was added (value %s)" % (dep, b_data['gendeps'][dep])
|
||||||
|
#if removed:
|
||||||
|
# print "Dependency on Variable %s was removed (value %s)" % (dep, a_data['gendeps'][dep])
|
||||||
|
|
||||||
|
if 'runtaskdeps' in a_data and 'runtaskdeps' in b_data and a_data['runtaskdeps'] != b_data['runtaskdeps']:
|
||||||
|
print "Tasks this task depends on changed from %s to %s" % (a_data['taskdeps'], b_data['taskdeps'])
|
||||||
|
|
||||||
|
if 'runtaskhashes' in a_data:
|
||||||
|
for dep in a_data['runtaskhashes']:
|
||||||
|
if a_data['runtaskhashes'][dep] != b_data['runtaskhashes'][dep]:
|
||||||
|
print "Hash for dependent task %s changed from %s to %s" % (dep, a_data['runtaskhashes'][dep], b_data['runtaskhashes'][dep])
|
||||||
|
|
||||||
|
def dump_sigfile(a):
|
||||||
|
p1 = pickle.Unpickler(file(a, "rb"))
|
||||||
|
a_data = p1.load()
|
||||||
|
|
||||||
|
print "basewhitelist: %s" % (a_data['basewhitelist'])
|
||||||
|
|
||||||
|
print "taskwhitelist: %s" % (a_data['taskwhitelist'])
|
||||||
|
|
||||||
|
print "Task dependencies: %s" % (sorted(a_data['taskdeps']))
|
||||||
|
|
||||||
|
print "basehash: %s" % (a_data['basehash'])
|
||||||
|
|
||||||
|
for dep in a_data['gendeps']:
|
||||||
|
print "List of dependencies for variable %s is %s" % (dep, a_data['gendeps'][dep])
|
||||||
|
|
||||||
|
for dep in a_data['varvals']:
|
||||||
|
print "Variable %s value is %s" % (dep, a_data['varvals'][dep])
|
||||||
|
|
||||||
|
if 'runtaskdeps' in a_data:
|
||||||
|
print "Tasks this task depends on: %s" % (a_data['runtaskdeps'])
|
||||||
|
|
||||||
|
if 'runtaskhashes' in a_data:
|
||||||
|
for dep in a_data['runtaskhashes']:
|
||||||
|
print "Hash for dependent task %s is %s" % (dep, a_data['runtaskhashes'][dep])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ def re_match_strings(target, strings):
|
|||||||
|
|
||||||
for name in strings:
|
for name in strings:
|
||||||
if (name==target or
|
if (name==target or
|
||||||
re.search(name,target)!=None):
|
re.search(name, target)!=None):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ class TaskData:
|
|||||||
|
|
||||||
def getrun_id(self, name):
|
def getrun_id(self, name):
|
||||||
"""
|
"""
|
||||||
Return an ID number for the run target name.
|
Return an ID number for the run target name.
|
||||||
If it doesn't exist, create one.
|
If it doesn't exist, create one.
|
||||||
"""
|
"""
|
||||||
if not name in self.run_names_index:
|
if not name in self.run_names_index:
|
||||||
@@ -95,7 +95,7 @@ class TaskData:
|
|||||||
|
|
||||||
def getfn_id(self, name):
|
def getfn_id(self, name):
|
||||||
"""
|
"""
|
||||||
Return an ID number for the filename.
|
Return an ID number for the filename.
|
||||||
If it doesn't exist, create one.
|
If it doesn't exist, create one.
|
||||||
"""
|
"""
|
||||||
if not name in self.fn_index:
|
if not name in self.fn_index:
|
||||||
@@ -271,7 +271,7 @@ class TaskData:
|
|||||||
|
|
||||||
def get_unresolved_build_targets(self, dataCache):
|
def get_unresolved_build_targets(self, dataCache):
|
||||||
"""
|
"""
|
||||||
Return a list of build targets who's providers
|
Return a list of build targets who's providers
|
||||||
are unknown.
|
are unknown.
|
||||||
"""
|
"""
|
||||||
unresolved = []
|
unresolved = []
|
||||||
@@ -286,7 +286,7 @@ class TaskData:
|
|||||||
|
|
||||||
def get_unresolved_run_targets(self, dataCache):
|
def get_unresolved_run_targets(self, dataCache):
|
||||||
"""
|
"""
|
||||||
Return a list of runtime targets who's providers
|
Return a list of runtime targets who's providers
|
||||||
are unknown.
|
are unknown.
|
||||||
"""
|
"""
|
||||||
unresolved = []
|
unresolved = []
|
||||||
@@ -304,7 +304,7 @@ class TaskData:
|
|||||||
Return a list of providers of item
|
Return a list of providers of item
|
||||||
"""
|
"""
|
||||||
targetid = self.getbuild_id(item)
|
targetid = self.getbuild_id(item)
|
||||||
|
|
||||||
return self.build_targets[targetid]
|
return self.build_targets[targetid]
|
||||||
|
|
||||||
def get_dependees(self, itemid):
|
def get_dependees(self, itemid):
|
||||||
@@ -354,20 +354,15 @@ class TaskData:
|
|||||||
self.add_provider_internal(cfgData, dataCache, item)
|
self.add_provider_internal(cfgData, dataCache, item)
|
||||||
except bb.providers.NoProvider:
|
except bb.providers.NoProvider:
|
||||||
if self.abort:
|
if self.abort:
|
||||||
if self.get_rdependees_str(item):
|
|
||||||
bb.msg.error(bb.msg.domain.Provider, "Nothing PROVIDES '%s' (but '%s' DEPENDS on or otherwise requires it)" % (item, self.get_dependees_str(item)))
|
|
||||||
else:
|
|
||||||
bb.msg.error(bb.msg.domain.Provider, "Nothing PROVIDES '%s'" % (item))
|
|
||||||
raise
|
raise
|
||||||
targetid = self.getbuild_id(item)
|
self.remove_buildtarget(self.getbuild_id(item))
|
||||||
self.remove_buildtarget(targetid)
|
|
||||||
|
|
||||||
self.mark_external_target(item)
|
self.mark_external_target(item)
|
||||||
|
|
||||||
def add_provider_internal(self, cfgData, dataCache, item):
|
def add_provider_internal(self, cfgData, dataCache, item):
|
||||||
"""
|
"""
|
||||||
Add the providers of item to the task data
|
Add the providers of item to the task data
|
||||||
Mark entries were specifically added externally as against dependencies
|
Mark entries were specifically added externally as against dependencies
|
||||||
added internally during dependency resolution
|
added internally during dependency resolution
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -375,11 +370,7 @@ class TaskData:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not item in dataCache.providers:
|
if not item in dataCache.providers:
|
||||||
if self.get_rdependees_str(item):
|
bb.event.fire(bb.event.NoProvider(item, dependees=self.get_rdependees_str(item)), cfgData)
|
||||||
bb.msg.note(2, bb.msg.domain.Provider, "Nothing PROVIDES '%s' (but '%s' DEPENDS on or otherwise requires it)" % (item, self.get_dependees_str(item)))
|
|
||||||
else:
|
|
||||||
bb.msg.note(2, bb.msg.domain.Provider, "Nothing PROVIDES '%s'" % (item))
|
|
||||||
bb.event.fire(bb.event.NoProvider(item), cfgData)
|
|
||||||
raise bb.providers.NoProvider(item)
|
raise bb.providers.NoProvider(item)
|
||||||
|
|
||||||
if self.have_build_target(item):
|
if self.have_build_target(item):
|
||||||
@@ -391,8 +382,7 @@ class TaskData:
|
|||||||
eligible = [p for p in eligible if not self.getfn_id(p) in self.failed_fnids]
|
eligible = [p for p in eligible if not self.getfn_id(p) in self.failed_fnids]
|
||||||
|
|
||||||
if not eligible:
|
if not eligible:
|
||||||
bb.msg.note(2, bb.msg.domain.Provider, "No buildable provider PROVIDES '%s' but '%s' DEPENDS on or otherwise requires it. Enable debugging and see earlier logs to find unbuildable providers." % (item, self.get_dependees_str(item)))
|
bb.event.fire(bb.event.NoProvider(item, dependees=self.get_dependees_str(item)), cfgData)
|
||||||
bb.event.fire(bb.event.NoProvider(item), cfgData)
|
|
||||||
raise bb.providers.NoProvider(item)
|
raise bb.providers.NoProvider(item)
|
||||||
|
|
||||||
if len(eligible) > 1 and foundUnique == False:
|
if len(eligible) > 1 and foundUnique == False:
|
||||||
@@ -400,8 +390,6 @@ class TaskData:
|
|||||||
providers_list = []
|
providers_list = []
|
||||||
for fn in eligible:
|
for fn in eligible:
|
||||||
providers_list.append(dataCache.pkg_fn[fn])
|
providers_list.append(dataCache.pkg_fn[fn])
|
||||||
bb.msg.note(1, bb.msg.domain.Provider, "multiple providers are available for %s (%s);" % (item, ", ".join(providers_list)))
|
|
||||||
bb.msg.note(1, bb.msg.domain.Provider, "consider defining PREFERRED_PROVIDER_%s" % item)
|
|
||||||
bb.event.fire(bb.event.MultipleProviders(item, providers_list), cfgData)
|
bb.event.fire(bb.event.MultipleProviders(item, providers_list), cfgData)
|
||||||
self.consider_msgs_cache.append(item)
|
self.consider_msgs_cache.append(item)
|
||||||
|
|
||||||
@@ -431,16 +419,14 @@ class TaskData:
|
|||||||
all_p = bb.providers.getRuntimeProviders(dataCache, item)
|
all_p = bb.providers.getRuntimeProviders(dataCache, item)
|
||||||
|
|
||||||
if not all_p:
|
if not all_p:
|
||||||
bb.msg.error(bb.msg.domain.Provider, "'%s' RDEPENDS/RRECOMMENDS or otherwise requires the runtime entity '%s' but it wasn't found in any PACKAGE or RPROVIDES variables" % (self.get_rdependees_str(item), item))
|
bb.event.fire(bb.event.NoProvider(item, runtime=True, dependees=self.get_rdependees_str(item)), cfgData)
|
||||||
bb.event.fire(bb.event.NoProvider(item, runtime=True), cfgData)
|
|
||||||
raise bb.providers.NoRProvider(item)
|
raise bb.providers.NoRProvider(item)
|
||||||
|
|
||||||
eligible, numberPreferred = bb.providers.filterProvidersRunTime(all_p, item, cfgData, dataCache)
|
eligible, numberPreferred = bb.providers.filterProvidersRunTime(all_p, item, cfgData, dataCache)
|
||||||
eligible = [p for p in eligible if not self.getfn_id(p) in self.failed_fnids]
|
eligible = [p for p in eligible if not self.getfn_id(p) in self.failed_fnids]
|
||||||
|
|
||||||
if not eligible:
|
if not eligible:
|
||||||
bb.msg.error(bb.msg.domain.Provider, "'%s' RDEPENDS/RRECOMMENDS or otherwise requires the runtime entity '%s' but it wasn't found in any PACKAGE or RPROVIDES variables of any buildable targets.\nEnable debugging and see earlier logs to find unbuildable targets." % (self.get_rdependees_str(item), item))
|
bb.event.fire(bb.event.NoProvider(item, runtime=True, dependees=self.get_rdependees_str(item)), cfgData)
|
||||||
bb.event.fire(bb.event.NoProvider(item, runtime=True), cfgData)
|
|
||||||
raise bb.providers.NoRProvider(item)
|
raise bb.providers.NoRProvider(item)
|
||||||
|
|
||||||
if len(eligible) > 1 and numberPreferred == 0:
|
if len(eligible) > 1 and numberPreferred == 0:
|
||||||
@@ -448,9 +434,7 @@ class TaskData:
|
|||||||
providers_list = []
|
providers_list = []
|
||||||
for fn in eligible:
|
for fn in eligible:
|
||||||
providers_list.append(dataCache.pkg_fn[fn])
|
providers_list.append(dataCache.pkg_fn[fn])
|
||||||
bb.msg.note(2, bb.msg.domain.Provider, "multiple providers are available for runtime %s (%s);" % (item, ", ".join(providers_list)))
|
bb.event.fire(bb.event.MultipleProviders(item, providers_list, runtime=True), cfgData)
|
||||||
bb.msg.note(2, bb.msg.domain.Provider, "consider defining a PREFERRED_PROVIDER entry to match runtime %s" % item)
|
|
||||||
bb.event.fire(bb.event.MultipleProviders(item,providers_list, runtime=True), cfgData)
|
|
||||||
self.consider_msgs_cache.append(item)
|
self.consider_msgs_cache.append(item)
|
||||||
|
|
||||||
if numberPreferred > 1:
|
if numberPreferred > 1:
|
||||||
@@ -458,9 +442,7 @@ class TaskData:
|
|||||||
providers_list = []
|
providers_list = []
|
||||||
for fn in eligible:
|
for fn in eligible:
|
||||||
providers_list.append(dataCache.pkg_fn[fn])
|
providers_list.append(dataCache.pkg_fn[fn])
|
||||||
bb.msg.note(2, bb.msg.domain.Provider, "multiple providers are available for runtime %s (top %s entries preferred) (%s);" % (item, numberPreferred, ", ".join(providers_list)))
|
bb.event.fire(bb.event.MultipleProviders(item, providers_list, runtime=True), cfgData)
|
||||||
bb.msg.note(2, bb.msg.domain.Provider, "consider defining only one PREFERRED_PROVIDER entry to match runtime %s" % item)
|
|
||||||
bb.event.fire(bb.event.MultipleProviders(item,providers_list, runtime=True), cfgData)
|
|
||||||
self.consider_msgs_cache.append(item)
|
self.consider_msgs_cache.append(item)
|
||||||
|
|
||||||
# run through the list until we find one that we can build
|
# run through the list until we find one that we can build
|
||||||
@@ -515,8 +497,9 @@ class TaskData:
|
|||||||
self.fail_fnid(self.tasks_fnid[taskid], missing_list)
|
self.fail_fnid(self.tasks_fnid[taskid], missing_list)
|
||||||
|
|
||||||
if self.abort and targetid in self.external_targets:
|
if self.abort and targetid in self.external_targets:
|
||||||
bb.msg.error(bb.msg.domain.Provider, "Required build target '%s' has no buildable providers.\nMissing or unbuildable dependency chain was: %s" % (self.build_names_index[targetid], missing_list))
|
target = self.build_names_index[targetid]
|
||||||
raise bb.providers.NoProvider
|
bb.msg.error(bb.msg.domain.Provider, "Required build target '%s' has no buildable providers.\nMissing or unbuildable dependency chain was: %s" % (target, missing_list))
|
||||||
|
raise bb.providers.NoProvider(target)
|
||||||
|
|
||||||
def remove_runtarget(self, targetid, missing_list = []):
|
def remove_runtarget(self, targetid, missing_list = []):
|
||||||
"""
|
"""
|
||||||
@@ -539,7 +522,7 @@ class TaskData:
|
|||||||
Resolve all unresolved build and runtime targets
|
Resolve all unresolved build and runtime targets
|
||||||
"""
|
"""
|
||||||
bb.msg.note(1, bb.msg.domain.TaskData, "Resolving any missing task queue dependencies")
|
bb.msg.note(1, bb.msg.domain.TaskData, "Resolving any missing task queue dependencies")
|
||||||
while 1:
|
while True:
|
||||||
added = 0
|
added = 0
|
||||||
for target in self.get_unresolved_build_targets(dataCache):
|
for target in self.get_unresolved_build_targets(dataCache):
|
||||||
try:
|
try:
|
||||||
@@ -548,10 +531,6 @@ class TaskData:
|
|||||||
except bb.providers.NoProvider:
|
except bb.providers.NoProvider:
|
||||||
targetid = self.getbuild_id(target)
|
targetid = self.getbuild_id(target)
|
||||||
if self.abort and targetid in self.external_targets:
|
if self.abort and targetid in self.external_targets:
|
||||||
if self.get_rdependees_str(target):
|
|
||||||
bb.msg.error(bb.msg.domain.Provider, "Nothing PROVIDES '%s' (but '%s' DEPENDS on or otherwise requires it)" % (target, self.get_dependees_str(target)))
|
|
||||||
else:
|
|
||||||
bb.msg.error(bb.msg.domain.Provider, "Nothing PROVIDES '%s'" % (target))
|
|
||||||
raise
|
raise
|
||||||
self.remove_buildtarget(targetid)
|
self.remove_buildtarget(targetid)
|
||||||
for target in self.get_unresolved_run_targets(dataCache):
|
for target in self.get_unresolved_run_targets(dataCache):
|
||||||
@@ -594,9 +573,9 @@ class TaskData:
|
|||||||
bb.msg.debug(3, bb.msg.domain.TaskData, "tasks:")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "tasks:")
|
||||||
for task in range(len(self.tasks_name)):
|
for task in range(len(self.tasks_name)):
|
||||||
bb.msg.debug(3, bb.msg.domain.TaskData, " (%s)%s - %s: %s" % (
|
bb.msg.debug(3, bb.msg.domain.TaskData, " (%s)%s - %s: %s" % (
|
||||||
task,
|
task,
|
||||||
self.fn_index[self.tasks_fnid[task]],
|
self.fn_index[self.tasks_fnid[task]],
|
||||||
self.tasks_name[task],
|
self.tasks_name[task],
|
||||||
self.tasks_tdepends[task]))
|
self.tasks_tdepends[task]))
|
||||||
|
|
||||||
bb.msg.debug(3, bb.msg.domain.TaskData, "dependency ids (per fn):")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "dependency ids (per fn):")
|
||||||
@@ -606,5 +585,3 @@ class TaskData:
|
|||||||
bb.msg.debug(3, bb.msg.domain.TaskData, "runtime dependency ids (per fn):")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "runtime dependency ids (per fn):")
|
||||||
for fnid in self.rdepids:
|
for fnid in self.rdepids:
|
||||||
bb.msg.debug(3, bb.msg.domain.TaskData, " %s %s: %s" % (fnid, self.fn_index[fnid], self.rdepids[fnid]))
|
bb.msg.debug(3, bb.msg.domain.TaskData, " %s %s: %s" % (fnid, self.fn_index[fnid], self.rdepids[fnid]))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,4 +15,3 @@
|
|||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
|||||||
@@ -15,4 +15,3 @@
|
|||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import time
|
|||||||
class BuildConfiguration:
|
class BuildConfiguration:
|
||||||
""" Represents a potential *or* historic *or* concrete build. It
|
""" Represents a potential *or* historic *or* concrete build. It
|
||||||
encompasses all the things that we need to tell bitbake to do to make it
|
encompasses all the things that we need to tell bitbake to do to make it
|
||||||
build what we want it to build.
|
build what we want it to build.
|
||||||
|
|
||||||
It also stored the metadata URL and the set of possible machines (and the
|
It also stored the metadata URL and the set of possible machines (and the
|
||||||
distros / images / uris for these. Apart from the metdata URL these are
|
distros / images / uris for these. Apart from the metdata URL these are
|
||||||
@@ -73,34 +73,33 @@ class BuildConfiguration:
|
|||||||
return self.urls
|
return self.urls
|
||||||
|
|
||||||
# It might be a lot lot better if we stored these in like, bitbake conf
|
# It might be a lot lot better if we stored these in like, bitbake conf
|
||||||
# file format.
|
# file format.
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_from_file (filename):
|
def load_from_file (filename):
|
||||||
f = open (filename, "r")
|
|
||||||
|
|
||||||
conf = BuildConfiguration()
|
conf = BuildConfiguration()
|
||||||
for line in f.readlines():
|
with open(filename, "r") as f:
|
||||||
data = line.split (";")[1]
|
for line in f:
|
||||||
if (line.startswith ("metadata-url;")):
|
data = line.split (";")[1]
|
||||||
conf.metadata_url = data.strip()
|
if (line.startswith ("metadata-url;")):
|
||||||
continue
|
conf.metadata_url = data.strip()
|
||||||
if (line.startswith ("url;")):
|
continue
|
||||||
conf.urls += [data.strip()]
|
if (line.startswith ("url;")):
|
||||||
continue
|
conf.urls += [data.strip()]
|
||||||
if (line.startswith ("extra-url;")):
|
continue
|
||||||
conf.extra_urls += [data.strip()]
|
if (line.startswith ("extra-url;")):
|
||||||
continue
|
conf.extra_urls += [data.strip()]
|
||||||
if (line.startswith ("machine;")):
|
continue
|
||||||
conf.machine = data.strip()
|
if (line.startswith ("machine;")):
|
||||||
continue
|
conf.machine = data.strip()
|
||||||
if (line.startswith ("distribution;")):
|
continue
|
||||||
conf.distro = data.strip()
|
if (line.startswith ("distribution;")):
|
||||||
continue
|
conf.distro = data.strip()
|
||||||
if (line.startswith ("image;")):
|
continue
|
||||||
conf.image = data.strip()
|
if (line.startswith ("image;")):
|
||||||
continue
|
conf.image = data.strip()
|
||||||
|
continue
|
||||||
|
|
||||||
f.close ()
|
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
# Serialise to a file. This is part of the build process and we use this
|
# Serialise to a file. This is part of the build process and we use this
|
||||||
@@ -140,13 +139,13 @@ class BuildResult(gobject.GObject):
|
|||||||
".conf" in the directory for the build.
|
".conf" in the directory for the build.
|
||||||
|
|
||||||
This is GObject so that it can be included in the TreeStore."""
|
This is GObject so that it can be included in the TreeStore."""
|
||||||
|
|
||||||
(STATE_COMPLETE, STATE_FAILED, STATE_ONGOING) = \
|
(STATE_COMPLETE, STATE_FAILED, STATE_ONGOING) = \
|
||||||
(0, 1, 2)
|
(0, 1, 2)
|
||||||
|
|
||||||
def __init__ (self, parent, identifier):
|
def __init__ (self, parent, identifier):
|
||||||
gobject.GObject.__init__ (self)
|
gobject.GObject.__init__ (self)
|
||||||
self.date = None
|
self.date = None
|
||||||
|
|
||||||
self.files = []
|
self.files = []
|
||||||
self.status = None
|
self.status = None
|
||||||
@@ -157,8 +156,8 @@ class BuildResult(gobject.GObject):
|
|||||||
# format build-<year><month><day>-<ordinal> we can easily
|
# format build-<year><month><day>-<ordinal> we can easily
|
||||||
# pull it out.
|
# pull it out.
|
||||||
# TODO: Better to stat a file?
|
# TODO: Better to stat a file?
|
||||||
(_ , date, revision) = identifier.split ("-")
|
(_, date, revision) = identifier.split ("-")
|
||||||
print date
|
print(date)
|
||||||
|
|
||||||
year = int (date[0:4])
|
year = int (date[0:4])
|
||||||
month = int (date[4:6])
|
month = int (date[4:6])
|
||||||
@@ -181,7 +180,7 @@ class BuildResult(gobject.GObject):
|
|||||||
self.add_file (file)
|
self.add_file (file)
|
||||||
|
|
||||||
def add_file (self, file):
|
def add_file (self, file):
|
||||||
# Just add the file for now. Don't care about the type.
|
# Just add the file for now. Don't care about the type.
|
||||||
self.files += [(file, None)]
|
self.files += [(file, None)]
|
||||||
|
|
||||||
class BuildManagerModel (gtk.TreeStore):
|
class BuildManagerModel (gtk.TreeStore):
|
||||||
@@ -194,7 +193,7 @@ class BuildManagerModel (gtk.TreeStore):
|
|||||||
|
|
||||||
def __init__ (self):
|
def __init__ (self):
|
||||||
gtk.TreeStore.__init__ (self,
|
gtk.TreeStore.__init__ (self,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
@@ -207,7 +206,7 @@ class BuildManager (gobject.GObject):
|
|||||||
"results" directory but is also used for starting a new build."""
|
"results" directory but is also used for starting a new build."""
|
||||||
|
|
||||||
__gsignals__ = {
|
__gsignals__ = {
|
||||||
'population-finished' : (gobject.SIGNAL_RUN_LAST,
|
'population-finished' : (gobject.SIGNAL_RUN_LAST,
|
||||||
gobject.TYPE_NONE,
|
gobject.TYPE_NONE,
|
||||||
()),
|
()),
|
||||||
'populate-error' : (gobject.SIGNAL_RUN_LAST,
|
'populate-error' : (gobject.SIGNAL_RUN_LAST,
|
||||||
@@ -220,13 +219,13 @@ class BuildManager (gobject.GObject):
|
|||||||
date = long (time.mktime (result.date.timetuple()))
|
date = long (time.mktime (result.date.timetuple()))
|
||||||
|
|
||||||
# Add a top level entry for the build
|
# Add a top level entry for the build
|
||||||
|
|
||||||
self.model.set (iter,
|
self.model.set (iter,
|
||||||
BuildManagerModel.COL_IDENT, result.identifier,
|
BuildManagerModel.COL_IDENT, result.identifier,
|
||||||
BuildManagerModel.COL_DESC, result.conf.image,
|
BuildManagerModel.COL_DESC, result.conf.image,
|
||||||
BuildManagerModel.COL_MACHINE, result.conf.machine,
|
BuildManagerModel.COL_MACHINE, result.conf.machine,
|
||||||
BuildManagerModel.COL_DISTRO, result.conf.distro,
|
BuildManagerModel.COL_DISTRO, result.conf.distro,
|
||||||
BuildManagerModel.COL_BUILD_RESULT, result,
|
BuildManagerModel.COL_BUILD_RESULT, result,
|
||||||
BuildManagerModel.COL_DATE, date,
|
BuildManagerModel.COL_DATE, date,
|
||||||
BuildManagerModel.COL_STATE, result.state)
|
BuildManagerModel.COL_STATE, result.state)
|
||||||
|
|
||||||
@@ -257,7 +256,7 @@ class BuildManager (gobject.GObject):
|
|||||||
|
|
||||||
while (iter):
|
while (iter):
|
||||||
(ident, state) = self.model.get(iter,
|
(ident, state) = self.model.get(iter,
|
||||||
BuildManagerModel.COL_IDENT,
|
BuildManagerModel.COL_IDENT,
|
||||||
BuildManagerModel.COL_STATE)
|
BuildManagerModel.COL_STATE)
|
||||||
|
|
||||||
if state == BuildResult.STATE_ONGOING:
|
if state == BuildResult.STATE_ONGOING:
|
||||||
@@ -385,8 +384,8 @@ class BuildManager (gobject.GObject):
|
|||||||
build_directory])
|
build_directory])
|
||||||
server.runCommand(["buildTargets", [conf.image], "rootfs"])
|
server.runCommand(["buildTargets", [conf.image], "rootfs"])
|
||||||
|
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print e
|
print(e)
|
||||||
|
|
||||||
class BuildManagerTreeView (gtk.TreeView):
|
class BuildManagerTreeView (gtk.TreeView):
|
||||||
""" The tree view for the build manager. This shows the historic builds
|
""" The tree view for the build manager. This shows the historic builds
|
||||||
@@ -422,29 +421,29 @@ class BuildManagerTreeView (gtk.TreeView):
|
|||||||
|
|
||||||
# Misc descriptiony thing
|
# Misc descriptiony thing
|
||||||
renderer = gtk.CellRendererText ()
|
renderer = gtk.CellRendererText ()
|
||||||
col = gtk.TreeViewColumn (None, renderer,
|
col = gtk.TreeViewColumn (None, renderer,
|
||||||
text=BuildManagerModel.COL_DESC)
|
text=BuildManagerModel.COL_DESC)
|
||||||
self.append_column (col)
|
self.append_column (col)
|
||||||
|
|
||||||
# Machine
|
# Machine
|
||||||
renderer = gtk.CellRendererText ()
|
renderer = gtk.CellRendererText ()
|
||||||
col = gtk.TreeViewColumn ("Machine", renderer,
|
col = gtk.TreeViewColumn ("Machine", renderer,
|
||||||
text=BuildManagerModel.COL_MACHINE)
|
text=BuildManagerModel.COL_MACHINE)
|
||||||
self.append_column (col)
|
self.append_column (col)
|
||||||
|
|
||||||
# distro
|
# distro
|
||||||
renderer = gtk.CellRendererText ()
|
renderer = gtk.CellRendererText ()
|
||||||
col = gtk.TreeViewColumn ("Distribution", renderer,
|
col = gtk.TreeViewColumn ("Distribution", renderer,
|
||||||
text=BuildManagerModel.COL_DISTRO)
|
text=BuildManagerModel.COL_DISTRO)
|
||||||
self.append_column (col)
|
self.append_column (col)
|
||||||
|
|
||||||
# date (using a custom function for formatting the cell contents it
|
# date (using a custom function for formatting the cell contents it
|
||||||
# takes epoch -> human readable string)
|
# takes epoch -> human readable string)
|
||||||
renderer = gtk.CellRendererText ()
|
renderer = gtk.CellRendererText ()
|
||||||
col = gtk.TreeViewColumn ("Date", renderer,
|
col = gtk.TreeViewColumn ("Date", renderer,
|
||||||
text=BuildManagerModel.COL_DATE)
|
text=BuildManagerModel.COL_DATE)
|
||||||
self.append_column (col)
|
self.append_column (col)
|
||||||
col.set_cell_data_func (renderer,
|
col.set_cell_data_func (renderer,
|
||||||
self.date_format_custom_cell_data_func)
|
self.date_format_custom_cell_data_func)
|
||||||
|
|
||||||
# For status.
|
# For status.
|
||||||
@@ -454,4 +453,3 @@ class BuildManagerTreeView (gtk.TreeView):
|
|||||||
self.append_column (col)
|
self.append_column (col)
|
||||||
col.set_cell_data_func (renderer,
|
col.set_cell_data_func (renderer,
|
||||||
self.state_format_custom_cell_data_fun)
|
self.state_format_custom_cell_data_fun)
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import gobject
|
|||||||
class RunningBuildModel (gtk.TreeStore):
|
class RunningBuildModel (gtk.TreeStore):
|
||||||
(COL_TYPE, COL_PACKAGE, COL_TASK, COL_MESSAGE, COL_ICON, COL_ACTIVE) = (0, 1, 2, 3, 4, 5)
|
(COL_TYPE, COL_PACKAGE, COL_TASK, COL_MESSAGE, COL_ICON, COL_ACTIVE) = (0, 1, 2, 3, 4, 5)
|
||||||
def __init__ (self):
|
def __init__ (self):
|
||||||
gtk.TreeStore.__init__ (self,
|
gtk.TreeStore.__init__ (self,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
@@ -34,7 +34,7 @@ class RunningBuildModel (gtk.TreeStore):
|
|||||||
|
|
||||||
class RunningBuild (gobject.GObject):
|
class RunningBuild (gobject.GObject):
|
||||||
__gsignals__ = {
|
__gsignals__ = {
|
||||||
'build-succeeded' : (gobject.SIGNAL_RUN_LAST,
|
'build-succeeded' : (gobject.SIGNAL_RUN_LAST,
|
||||||
gobject.TYPE_NONE,
|
gobject.TYPE_NONE,
|
||||||
()),
|
()),
|
||||||
'build-failed' : (gobject.SIGNAL_RUN_LAST,
|
'build-failed' : (gobject.SIGNAL_RUN_LAST,
|
||||||
@@ -63,7 +63,7 @@ class RunningBuild (gobject.GObject):
|
|||||||
# for the message.
|
# for the message.
|
||||||
if hasattr(event, 'pid'):
|
if hasattr(event, 'pid'):
|
||||||
pid = event.pid
|
pid = event.pid
|
||||||
if self.pids_to_task.has_key(pid):
|
if pid in self.pids_to_task:
|
||||||
(package, task) = self.pids_to_task[pid]
|
(package, task) = self.pids_to_task[pid]
|
||||||
parent = self.tasks_to_iter[(package, task)]
|
parent = self.tasks_to_iter[(package, task)]
|
||||||
|
|
||||||
@@ -82,29 +82,29 @@ class RunningBuild (gobject.GObject):
|
|||||||
|
|
||||||
# Add the message to the tree either at the top level if parent is
|
# Add the message to the tree either at the top level if parent is
|
||||||
# None otherwise as a descendent of a task.
|
# None otherwise as a descendent of a task.
|
||||||
self.model.append (parent,
|
self.model.append (parent,
|
||||||
(event.__name__.split()[-1], # e.g. MsgWarn, MsgError
|
(event.__name__.split()[-1], # e.g. MsgWarn, MsgError
|
||||||
package,
|
package,
|
||||||
task,
|
task,
|
||||||
event._message,
|
event._message,
|
||||||
icon,
|
icon,
|
||||||
False))
|
False))
|
||||||
elif isinstance(event, bb.build.TaskStarted):
|
elif isinstance(event, bb.build.TaskStarted):
|
||||||
(package, task) = (event._package, event._task)
|
(package, task) = (event._package, event._task)
|
||||||
|
|
||||||
# Save out this PID.
|
# Save out this PID.
|
||||||
self.pids_to_task[pid] = (package,task)
|
self.pids_to_task[pid] = (package, task)
|
||||||
|
|
||||||
# Check if we already have this package in our model. If so then
|
# Check if we already have this package in our model. If so then
|
||||||
# that can be the parent for the task. Otherwise we create a new
|
# that can be the parent for the task. Otherwise we create a new
|
||||||
# top level for the package.
|
# top level for the package.
|
||||||
if (self.tasks_to_iter.has_key ((package, None))):
|
if ((package, None) in self.tasks_to_iter):
|
||||||
parent = self.tasks_to_iter[(package, None)]
|
parent = self.tasks_to_iter[(package, None)]
|
||||||
else:
|
else:
|
||||||
parent = self.model.append (None, (None,
|
parent = self.model.append (None, (None,
|
||||||
package,
|
package,
|
||||||
None,
|
None,
|
||||||
"Package: %s" % (package),
|
"Package: %s" % (package),
|
||||||
None,
|
None,
|
||||||
False))
|
False))
|
||||||
self.tasks_to_iter[(package, None)] = parent
|
self.tasks_to_iter[(package, None)] = parent
|
||||||
@@ -114,10 +114,10 @@ class RunningBuild (gobject.GObject):
|
|||||||
self.model.set(parent, self.model.COL_ICON, "gtk-execute")
|
self.model.set(parent, self.model.COL_ICON, "gtk-execute")
|
||||||
|
|
||||||
# Add an entry in the model for this task
|
# Add an entry in the model for this task
|
||||||
i = self.model.append (parent, (None,
|
i = self.model.append (parent, (None,
|
||||||
package,
|
package,
|
||||||
task,
|
task,
|
||||||
"Task: %s" % (task),
|
"Task: %s" % (task),
|
||||||
None,
|
None,
|
||||||
False))
|
False))
|
||||||
|
|
||||||
@@ -176,5 +176,3 @@ class RunningBuildTreeView (gtk.TreeView):
|
|||||||
renderer = gtk.CellRendererText ()
|
renderer = gtk.CellRendererText ()
|
||||||
col = gtk.TreeViewColumn ("Message", renderer, text=3)
|
col = gtk.TreeViewColumn ("Message", renderer, text=3)
|
||||||
self.append_column (col)
|
self.append_column (col)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -201,14 +201,14 @@ def init(server, eventHandler):
|
|||||||
try:
|
try:
|
||||||
cmdline = server.runCommand(["getCmdLineAction"])
|
cmdline = server.runCommand(["getCmdLineAction"])
|
||||||
if not cmdline or cmdline[0] != "generateDotGraph":
|
if not cmdline or cmdline[0] != "generateDotGraph":
|
||||||
print "This UI is only compatible with the -g option"
|
print("This UI is only compatible with the -g option")
|
||||||
return
|
return
|
||||||
ret = server.runCommand(["generateDepTreeEvent", cmdline[1], cmdline[2]])
|
ret = server.runCommand(["generateDepTreeEvent", cmdline[1], cmdline[2]])
|
||||||
if ret != True:
|
if ret != True:
|
||||||
print "Couldn't run command! %s" % ret
|
print("Couldn't run command! %s" % ret)
|
||||||
return
|
return
|
||||||
except xmlrpclib.Fault, x:
|
except xmlrpclib.Fault as x:
|
||||||
print "XMLRPC Fault getting commandline:\n %s" % x
|
print("XMLRPC Fault getting commandline:\n %s" % x)
|
||||||
return
|
return
|
||||||
|
|
||||||
shutdown = 0
|
shutdown = 0
|
||||||
@@ -233,8 +233,8 @@ def init(server, eventHandler):
|
|||||||
x = event.sofar
|
x = event.sofar
|
||||||
y = event.total
|
y = event.total
|
||||||
if x == y:
|
if x == y:
|
||||||
print("\nParsing finished. %d cached, %d parsed, %d skipped, %d masked, %d errors."
|
print(("\nParsing finished. %d cached, %d parsed, %d skipped, %d masked, %d errors."
|
||||||
% ( event.cached, event.parsed, event.skipped, event.masked, event.errors))
|
% ( event.cached, event.parsed, event.skipped, event.masked, event.errors)))
|
||||||
pbar.hide()
|
pbar.hide()
|
||||||
gtk.gdk.threads_enter()
|
gtk.gdk.threads_enter()
|
||||||
pbar.progress.set_fraction(float(x)/float(y))
|
pbar.progress.set_fraction(float(x)/float(y))
|
||||||
@@ -250,7 +250,7 @@ def init(server, eventHandler):
|
|||||||
if isinstance(event, bb.command.CookerCommandCompleted):
|
if isinstance(event, bb.command.CookerCommandCompleted):
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.command.CookerCommandFailed):
|
if isinstance(event, bb.command.CookerCommandFailed):
|
||||||
print "Command execution failed: %s" % event.error
|
print("Command execution failed: %s" % event.error)
|
||||||
break
|
break
|
||||||
if isinstance(event, bb.cooker.CookerExit):
|
if isinstance(event, bb.cooker.CookerExit):
|
||||||
break
|
break
|
||||||
@@ -259,14 +259,13 @@ def init(server, eventHandler):
|
|||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
if shutdown == 2:
|
if shutdown == 2:
|
||||||
print "\nThird Keyboard Interrupt, exit.\n"
|
print("\nThird Keyboard Interrupt, exit.\n")
|
||||||
break
|
break
|
||||||
if shutdown == 1:
|
if shutdown == 1:
|
||||||
print "\nSecond Keyboard Interrupt, stopping...\n"
|
print("\nSecond Keyboard Interrupt, stopping...\n")
|
||||||
server.runCommand(["stateStop"])
|
server.runCommand(["stateStop"])
|
||||||
if shutdown == 0:
|
if shutdown == 0:
|
||||||
print "\nKeyboard Interrupt, closing down...\n"
|
print("\nKeyboard Interrupt, closing down...\n")
|
||||||
server.runCommand(["stateShutdown"])
|
server.runCommand(["stateShutdown"])
|
||||||
shutdown = shutdown + 1
|
shutdown = shutdown + 1
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ from bb.ui.crumbs.runningbuild import RunningBuildTreeView, RunningBuild
|
|||||||
|
|
||||||
def event_handle_idle_func (eventHandler, build):
|
def event_handle_idle_func (eventHandler, build):
|
||||||
|
|
||||||
# Consume as many messages as we can in the time available to us
|
# Consume as many messages as we can in the time available to us
|
||||||
event = eventHandler.getEvent()
|
event = eventHandler.getEvent()
|
||||||
while event:
|
while event:
|
||||||
build.handle_event (event)
|
build.handle_event (event)
|
||||||
event = eventHandler.getEvent()
|
event = eventHandler.getEvent()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
class MainWindow (gtk.Window):
|
class MainWindow (gtk.Window):
|
||||||
def __init__ (self):
|
def __init__ (self):
|
||||||
@@ -55,15 +55,15 @@ def init (server, eventHandler):
|
|||||||
window.cur_build_tv.set_model (running_build.model)
|
window.cur_build_tv.set_model (running_build.model)
|
||||||
try:
|
try:
|
||||||
cmdline = server.runCommand(["getCmdLineAction"])
|
cmdline = server.runCommand(["getCmdLineAction"])
|
||||||
print cmdline
|
print(cmdline)
|
||||||
if not cmdline:
|
if not cmdline:
|
||||||
return 1
|
return 1
|
||||||
ret = server.runCommand(cmdline)
|
ret = server.runCommand(cmdline)
|
||||||
if ret != True:
|
if ret != True:
|
||||||
print "Couldn't get default commandline! %s" % ret
|
print("Couldn't get default commandline! %s" % ret)
|
||||||
return 1
|
return 1
|
||||||
except xmlrpclib.Fault, x:
|
except xmlrpclib.Fault as x:
|
||||||
print "XMLRPC Fault getting commandline:\n %s" % x
|
print("XMLRPC Fault getting commandline:\n %s" % x)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Use a timeout function for probing the event queue to find out if we
|
# Use a timeout function for probing the event queue to find out if we
|
||||||
@@ -74,4 +74,3 @@ def init (server, eventHandler):
|
|||||||
running_build)
|
running_build)
|
||||||
|
|
||||||
gtk.main()
|
gtk.main()
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,9 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import os
|
from __future__ import division
|
||||||
|
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import itertools
|
import itertools
|
||||||
import xmlrpclib
|
import xmlrpclib
|
||||||
@@ -44,10 +45,10 @@ def init(server, eventHandler):
|
|||||||
return 1
|
return 1
|
||||||
ret = server.runCommand(cmdline)
|
ret = server.runCommand(cmdline)
|
||||||
if ret != True:
|
if ret != True:
|
||||||
print "Couldn't get default commandline! %s" % ret
|
print("Couldn't get default commandline! %s" % ret)
|
||||||
return 1
|
return 1
|
||||||
except xmlrpclib.Fault, x:
|
except xmlrpclib.Fault as x:
|
||||||
print "XMLRPC Fault getting commandline:\n %s" % x
|
print("XMLRPC Fault getting commandline:\n %s" % x)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
shutdown = 0
|
shutdown = 0
|
||||||
@@ -65,39 +66,39 @@ def init(server, eventHandler):
|
|||||||
if shutdown and helper.needUpdate:
|
if shutdown and helper.needUpdate:
|
||||||
activetasks, failedtasks = helper.getTasks()
|
activetasks, failedtasks = helper.getTasks()
|
||||||
if activetasks:
|
if activetasks:
|
||||||
print "Waiting for %s active tasks to finish:" % len(activetasks)
|
print("Waiting for %s active tasks to finish:" % len(activetasks))
|
||||||
tasknum = 1
|
tasknum = 1
|
||||||
for task in activetasks:
|
for task in activetasks:
|
||||||
print "%s: %s (pid %s)" % (tasknum, activetasks[task]["title"], task)
|
print("%s: %s (pid %s)" % (tasknum, activetasks[task]["title"], task))
|
||||||
tasknum = tasknum + 1
|
tasknum = tasknum + 1
|
||||||
|
|
||||||
if isinstance(event, bb.msg.MsgPlain):
|
if isinstance(event, bb.msg.MsgPlain):
|
||||||
print event._message
|
print(event._message)
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.msg.MsgDebug):
|
if isinstance(event, bb.msg.MsgDebug):
|
||||||
print 'DEBUG: ' + event._message
|
print('DEBUG: ' + event._message)
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.msg.MsgNote):
|
if isinstance(event, bb.msg.MsgNote):
|
||||||
print 'NOTE: ' + event._message
|
print('NOTE: ' + event._message)
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.msg.MsgWarn):
|
if isinstance(event, bb.msg.MsgWarn):
|
||||||
print 'WARNING: ' + event._message
|
print('WARNING: ' + event._message)
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.msg.MsgError):
|
if isinstance(event, bb.msg.MsgError):
|
||||||
return_value = 1
|
return_value = 1
|
||||||
print 'ERROR: ' + event._message
|
print('ERROR: ' + event._message)
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.msg.MsgFatal):
|
if isinstance(event, bb.msg.MsgFatal):
|
||||||
return_value = 1
|
return_value = 1
|
||||||
print 'FATAL: ' + event._message
|
print('FATAL: ' + event._message)
|
||||||
break
|
continue
|
||||||
if isinstance(event, bb.build.TaskFailed):
|
if isinstance(event, bb.build.TaskFailed):
|
||||||
return_value = 1
|
return_value = 1
|
||||||
logfile = event.logfile
|
logfile = event.logfile
|
||||||
if logfile:
|
if logfile and os.path.exists(logfile):
|
||||||
print "ERROR: Logfile of failure stored in: %s" % logfile
|
print("ERROR: Logfile of failure stored in: %s" % logfile)
|
||||||
if 1 or includelogs:
|
if 1 or includelogs:
|
||||||
print "Log data follows:"
|
print("Log data follows:")
|
||||||
f = open(logfile, "r")
|
f = open(logfile, "r")
|
||||||
lines = []
|
lines = []
|
||||||
while True:
|
while True:
|
||||||
@@ -110,19 +111,19 @@ def init(server, eventHandler):
|
|||||||
if len(lines) > int(loglines):
|
if len(lines) > int(loglines):
|
||||||
lines.pop(0)
|
lines.pop(0)
|
||||||
else:
|
else:
|
||||||
print '| %s' % l
|
print('| %s' % l)
|
||||||
f.close()
|
f.close()
|
||||||
if lines:
|
if lines:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
print line
|
print(line)
|
||||||
if isinstance(event, bb.build.TaskBase):
|
if isinstance(event, bb.build.TaskBase):
|
||||||
print "NOTE: %s" % event._message
|
print("NOTE: %s" % event._message)
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.event.ParseProgress):
|
if isinstance(event, bb.event.ParseProgress):
|
||||||
x = event.sofar
|
x = event.sofar
|
||||||
y = event.total
|
y = event.total
|
||||||
if os.isatty(sys.stdout.fileno()):
|
if os.isatty(sys.stdout.fileno()):
|
||||||
sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
|
sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( next(parsespin), x, y, x*100//y ) )
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
else:
|
else:
|
||||||
if x == 1:
|
if x == 1:
|
||||||
@@ -132,8 +133,8 @@ def init(server, eventHandler):
|
|||||||
sys.stdout.write("done.")
|
sys.stdout.write("done.")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
if x == y:
|
if x == y:
|
||||||
print("\nParsing of %d .bb files complete (%d cached, %d parsed). %d targets, %d skipped, %d masked, %d errors."
|
print(("\nParsing of %d .bb files complete (%d cached, %d parsed). %d targets, %d skipped, %d masked, %d errors."
|
||||||
% ( event.total, event.cached, event.parsed, event.virtuals, event.skipped, event.masked, event.errors))
|
% ( event.total, event.cached, event.parsed, event.virtuals, event.skipped, event.masked, event.errors)))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(event, bb.command.CookerCommandCompleted):
|
if isinstance(event, bb.command.CookerCommandCompleted):
|
||||||
@@ -143,39 +144,48 @@ def init(server, eventHandler):
|
|||||||
continue
|
continue
|
||||||
if isinstance(event, bb.command.CookerCommandFailed):
|
if isinstance(event, bb.command.CookerCommandFailed):
|
||||||
return_value = 1
|
return_value = 1
|
||||||
print "Command execution failed: %s" % event.error
|
print("Command execution failed: %s" % event.error)
|
||||||
break
|
break
|
||||||
if isinstance(event, bb.cooker.CookerExit):
|
if isinstance(event, bb.cooker.CookerExit):
|
||||||
break
|
break
|
||||||
|
if isinstance(event, bb.event.MultipleProviders):
|
||||||
|
print("NOTE: multiple providers are available for %s%s (%s)" % (event._is_runtime and "runtime " or "",
|
||||||
|
event._item,
|
||||||
|
", ".join(event._candidates)))
|
||||||
|
print("NOTE: consider defining a PREFERRED_PROVIDER entry to match %s" % event._item)
|
||||||
|
continue
|
||||||
|
if isinstance(event, bb.event.NoProvider):
|
||||||
|
if event._runtime:
|
||||||
|
r = "R"
|
||||||
|
else:
|
||||||
|
r = ""
|
||||||
|
|
||||||
|
if event._dependees:
|
||||||
|
print("ERROR: Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % (r, event._item, ", ".join(event._dependees), r))
|
||||||
|
else:
|
||||||
|
print("ERROR: Nothing %sPROVIDES '%s'" % (r, event._item))
|
||||||
|
continue
|
||||||
|
|
||||||
# ignore
|
# ignore
|
||||||
if isinstance(event, bb.event.BuildStarted):
|
if isinstance(event, (bb.event.BuildBase,
|
||||||
|
bb.event.StampUpdate,
|
||||||
|
bb.event.ConfigParsed,
|
||||||
|
bb.event.RecipeParsed,
|
||||||
|
bb.runqueue.runQueueEvent,
|
||||||
|
bb.runqueue.runQueueExitWait)):
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.event.BuildCompleted):
|
|
||||||
continue
|
print("Unknown Event: %s" % event)
|
||||||
if isinstance(event, bb.event.MultipleProviders):
|
|
||||||
continue
|
|
||||||
if isinstance(event, bb.runqueue.runQueueEvent):
|
|
||||||
continue
|
|
||||||
if isinstance(event, bb.runqueue.runQueueExitWait):
|
|
||||||
continue
|
|
||||||
if isinstance(event, bb.event.StampUpdate):
|
|
||||||
continue
|
|
||||||
if isinstance(event, bb.event.ConfigParsed):
|
|
||||||
continue
|
|
||||||
if isinstance(event, bb.event.RecipeParsed):
|
|
||||||
continue
|
|
||||||
print "Unknown Event: %s" % event
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
if shutdown == 2:
|
if shutdown == 2:
|
||||||
print "\nThird Keyboard Interrupt, exit.\n"
|
print("\nThird Keyboard Interrupt, exit.\n")
|
||||||
break
|
break
|
||||||
if shutdown == 1:
|
if shutdown == 1:
|
||||||
print "\nSecond Keyboard Interrupt, stopping...\n"
|
print("\nSecond Keyboard Interrupt, stopping...\n")
|
||||||
server.runCommand(["stateStop"])
|
server.runCommand(["stateStop"])
|
||||||
if shutdown == 0:
|
if shutdown == 0:
|
||||||
print "\nKeyboard Interrupt, closing down...\n"
|
print("\nKeyboard Interrupt, closing down...\n")
|
||||||
server.runCommand(["stateShutdown"])
|
server.runCommand(["stateShutdown"])
|
||||||
shutdown = shutdown + 1
|
shutdown = shutdown + 1
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
import os, sys, curses, itertools, time
|
import os, sys, curses, itertools, time
|
||||||
import bb
|
import bb
|
||||||
import xmlrpclib
|
import xmlrpclib
|
||||||
@@ -136,7 +138,7 @@ class NCursesUI:
|
|||||||
"""Thread Activity Window"""
|
"""Thread Activity Window"""
|
||||||
def __init__( self, x, y, width, height ):
|
def __init__( self, x, y, width, height ):
|
||||||
NCursesUI.DecoratedWindow.__init__( self, "Thread Activity", x, y, width, height )
|
NCursesUI.DecoratedWindow.__init__( self, "Thread Activity", x, y, width, height )
|
||||||
|
|
||||||
def setStatus( self, thread, text ):
|
def setStatus( self, thread, text ):
|
||||||
line = "%02d: %s" % ( thread, text )
|
line = "%02d: %s" % ( thread, text )
|
||||||
width = self.dimensions[WIDTH]
|
width = self.dimensions[WIDTH]
|
||||||
@@ -199,8 +201,8 @@ class NCursesUI:
|
|||||||
|
|
||||||
main_left = 0
|
main_left = 0
|
||||||
main_top = 0
|
main_top = 0
|
||||||
main_height = ( height / 3 * 2 )
|
main_height = ( height // 3 * 2 )
|
||||||
main_width = ( width / 3 ) * 2
|
main_width = ( width // 3 ) * 2
|
||||||
clo_left = main_left
|
clo_left = main_left
|
||||||
clo_top = main_top + main_height
|
clo_top = main_top + main_height
|
||||||
clo_height = height - main_height - main_top - 1
|
clo_height = height - main_height - main_top - 1
|
||||||
@@ -225,17 +227,17 @@ class NCursesUI:
|
|||||||
|
|
||||||
helper = uihelper.BBUIHelper()
|
helper = uihelper.BBUIHelper()
|
||||||
shutdown = 0
|
shutdown = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmdline = server.runCommand(["getCmdLineAction"])
|
cmdline = server.runCommand(["getCmdLineAction"])
|
||||||
if not cmdline:
|
if not cmdline:
|
||||||
return
|
return
|
||||||
ret = server.runCommand(cmdline)
|
ret = server.runCommand(cmdline)
|
||||||
if ret != True:
|
if ret != True:
|
||||||
print "Couldn't get default commandlind! %s" % ret
|
print("Couldn't get default commandlind! %s" % ret)
|
||||||
return
|
return
|
||||||
except xmlrpclib.Fault, x:
|
except xmlrpclib.Fault as x:
|
||||||
print "XMLRPC Fault getting commandline:\n %s" % x
|
print("XMLRPC Fault getting commandline:\n %s" % x)
|
||||||
return
|
return
|
||||||
|
|
||||||
exitflag = False
|
exitflag = False
|
||||||
@@ -246,7 +248,7 @@ class NCursesUI:
|
|||||||
continue
|
continue
|
||||||
helper.eventHandler(event)
|
helper.eventHandler(event)
|
||||||
#mw.appendText("%s\n" % event[0])
|
#mw.appendText("%s\n" % event[0])
|
||||||
if isinstance(event, bb.build.Task):
|
if isinstance(event, bb.build.TaskBase):
|
||||||
mw.appendText("NOTE: %s\n" % event._message)
|
mw.appendText("NOTE: %s\n" % event._message)
|
||||||
if isinstance(event, bb.msg.MsgDebug):
|
if isinstance(event, bb.msg.MsgDebug):
|
||||||
mw.appendText('DEBUG: ' + event._message + '\n')
|
mw.appendText('DEBUG: ' + event._message + '\n')
|
||||||
@@ -263,10 +265,10 @@ class NCursesUI:
|
|||||||
y = event.total
|
y = event.total
|
||||||
if x == y:
|
if x == y:
|
||||||
mw.setStatus("Idle")
|
mw.setStatus("Idle")
|
||||||
mw.appendText("Parsing finished. %d cached, %d parsed, %d skipped, %d masked."
|
mw.appendText("Parsing finished. %d cached, %d parsed, %d skipped, %d masked."
|
||||||
% ( event.cached, event.parsed, event.skipped, event.masked ))
|
% ( event.cached, event.parsed, event.skipped, event.masked ))
|
||||||
else:
|
else:
|
||||||
mw.setStatus("Parsing: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
|
mw.setStatus("Parsing: %s (%04d/%04d) [%2d %%]" % ( next(parsespin), x, y, x*100//y ) )
|
||||||
# if isinstance(event, bb.build.TaskFailed):
|
# if isinstance(event, bb.build.TaskFailed):
|
||||||
# if event.logfile:
|
# if event.logfile:
|
||||||
# if data.getVar("BBINCLUDELOGS", d):
|
# if data.getVar("BBINCLUDELOGS", d):
|
||||||
@@ -301,12 +303,12 @@ class NCursesUI:
|
|||||||
taw.setText(0, 0, "")
|
taw.setText(0, 0, "")
|
||||||
if activetasks:
|
if activetasks:
|
||||||
taw.appendText("Active Tasks:\n")
|
taw.appendText("Active Tasks:\n")
|
||||||
for task in activetasks:
|
for task in activetasks.itervalues():
|
||||||
taw.appendText(task)
|
taw.appendText(task["title"])
|
||||||
if failedtasks:
|
if failedtasks:
|
||||||
taw.appendText("Failed Tasks:\n")
|
taw.appendText("Failed Tasks:\n")
|
||||||
for task in failedtasks:
|
for task in failedtasks:
|
||||||
taw.appendText(task)
|
taw.appendText(task["title"])
|
||||||
|
|
||||||
curses.doupdate()
|
curses.doupdate()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
@@ -324,7 +326,7 @@ class NCursesUI:
|
|||||||
|
|
||||||
def init(server, eventHandler):
|
def init(server, eventHandler):
|
||||||
if not os.isatty(sys.stdout.fileno()):
|
if not os.isatty(sys.stdout.fileno()):
|
||||||
print "FATAL: Unable to run 'ncurses' UI without a TTY."
|
print("FATAL: Unable to run 'ncurses' UI without a TTY.")
|
||||||
return
|
return
|
||||||
ui = NCursesUI()
|
ui = NCursesUI()
|
||||||
try:
|
try:
|
||||||
@@ -332,4 +334,3 @@ def init(server, eventHandler):
|
|||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import gtk.glade
|
|||||||
import threading
|
import threading
|
||||||
import urllib2
|
import urllib2
|
||||||
import os
|
import os
|
||||||
|
import contextlib
|
||||||
|
|
||||||
from bb.ui.crumbs.buildmanager import BuildManager, BuildConfiguration
|
from bb.ui.crumbs.buildmanager import BuildManager, BuildConfiguration
|
||||||
from bb.ui.crumbs.buildmanager import BuildManagerTreeView
|
from bb.ui.crumbs.buildmanager import BuildManagerTreeView
|
||||||
@@ -38,7 +39,7 @@ class MetaDataLoader(gobject.GObject):
|
|||||||
on what machines are available. The distribution and images available for
|
on what machines are available. The distribution and images available for
|
||||||
the machine and the the uris to use for building the given machine."""
|
the machine and the the uris to use for building the given machine."""
|
||||||
__gsignals__ = {
|
__gsignals__ = {
|
||||||
'success' : (gobject.SIGNAL_RUN_LAST,
|
'success' : (gobject.SIGNAL_RUN_LAST,
|
||||||
gobject.TYPE_NONE,
|
gobject.TYPE_NONE,
|
||||||
()),
|
()),
|
||||||
'error' : (gobject.SIGNAL_RUN_LAST,
|
'error' : (gobject.SIGNAL_RUN_LAST,
|
||||||
@@ -77,20 +78,19 @@ class MetaDataLoader(gobject.GObject):
|
|||||||
def run (self):
|
def run (self):
|
||||||
result = {}
|
result = {}
|
||||||
try:
|
try:
|
||||||
f = urllib2.urlopen (self.url)
|
with contextlib.closing (urllib2.urlopen (self.url)) as f:
|
||||||
|
# Parse the metadata format. The format is....
|
||||||
|
# <machine>;<default distro>|<distro>...;<default image>|<image>...;<type##url>|...
|
||||||
|
for line in f:
|
||||||
|
components = line.split(";")
|
||||||
|
if (len (components) < 4):
|
||||||
|
raise MetaDataLoader.LoaderThread.LoaderImportException
|
||||||
|
machine = components[0]
|
||||||
|
distros = components[1].split("|")
|
||||||
|
images = components[2].split("|")
|
||||||
|
urls = components[3].split("|")
|
||||||
|
|
||||||
# Parse the metadata format. The format is....
|
result[machine] = (distros, images, urls)
|
||||||
# <machine>;<default distro>|<distro>...;<default image>|<image>...;<type##url>|...
|
|
||||||
for line in f.readlines():
|
|
||||||
components = line.split(";")
|
|
||||||
if (len (components) < 4):
|
|
||||||
raise MetaDataLoader.LoaderThread.LoaderImportException
|
|
||||||
machine = components[0]
|
|
||||||
distros = components[1].split("|")
|
|
||||||
images = components[2].split("|")
|
|
||||||
urls = components[3].split("|")
|
|
||||||
|
|
||||||
result[machine] = (distros, images, urls)
|
|
||||||
|
|
||||||
# Create an object representing this *potential*
|
# Create an object representing this *potential*
|
||||||
# configuration. It can become concrete if the machine, distro
|
# configuration. It can become concrete if the machine, distro
|
||||||
@@ -104,13 +104,13 @@ class MetaDataLoader(gobject.GObject):
|
|||||||
gobject.idle_add (MetaDataLoader.emit_success_signal,
|
gobject.idle_add (MetaDataLoader.emit_success_signal,
|
||||||
self.loader)
|
self.loader)
|
||||||
|
|
||||||
except MetaDataLoader.LoaderThread.LoaderImportException, e:
|
except MetaDataLoader.LoaderThread.LoaderImportException as e:
|
||||||
gobject.idle_add (MetaDataLoader.emit_error_signal, self.loader,
|
gobject.idle_add (MetaDataLoader.emit_error_signal, self.loader,
|
||||||
"Repository metadata corrupt")
|
"Repository metadata corrupt")
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
gobject.idle_add (MetaDataLoader.emit_error_signal, self.loader,
|
gobject.idle_add (MetaDataLoader.emit_error_signal, self.loader,
|
||||||
"Unable to download repository metadata")
|
"Unable to download repository metadata")
|
||||||
print e
|
print(e)
|
||||||
|
|
||||||
def try_fetch_from_url (self, url):
|
def try_fetch_from_url (self, url):
|
||||||
# Try and download the metadata. Firing a signal if successful
|
# Try and download the metadata. Firing a signal if successful
|
||||||
@@ -211,7 +211,7 @@ class BuildSetupDialog (gtk.Dialog):
|
|||||||
# Build
|
# Build
|
||||||
button = gtk.Button ("_Build", None, True)
|
button = gtk.Button ("_Build", None, True)
|
||||||
image = gtk.Image ()
|
image = gtk.Image ()
|
||||||
image.set_from_stock (gtk.STOCK_EXECUTE,gtk.ICON_SIZE_BUTTON)
|
image.set_from_stock (gtk.STOCK_EXECUTE, gtk.ICON_SIZE_BUTTON)
|
||||||
button.set_image (image)
|
button.set_image (image)
|
||||||
self.add_action_widget (button, BuildSetupDialog.RESPONSE_BUILD)
|
self.add_action_widget (button, BuildSetupDialog.RESPONSE_BUILD)
|
||||||
button.show_all ()
|
button.show_all ()
|
||||||
@@ -293,7 +293,7 @@ class BuildSetupDialog (gtk.Dialog):
|
|||||||
if (active_iter):
|
if (active_iter):
|
||||||
self.configuration.machine = model.get(active_iter, 0)[0]
|
self.configuration.machine = model.get(active_iter, 0)[0]
|
||||||
|
|
||||||
# Extract the chosen distro from the combo
|
# Extract the chosen distro from the combo
|
||||||
model = self.distribution_combo.get_model()
|
model = self.distribution_combo.get_model()
|
||||||
active_iter = self.distribution_combo.get_active_iter()
|
active_iter = self.distribution_combo.get_active_iter()
|
||||||
if (active_iter):
|
if (active_iter):
|
||||||
@@ -311,62 +311,62 @@ class BuildSetupDialog (gtk.Dialog):
|
|||||||
#
|
#
|
||||||
# TODO: Should be a method on the RunningBuild class
|
# TODO: Should be a method on the RunningBuild class
|
||||||
def event_handle_timeout (eventHandler, build):
|
def event_handle_timeout (eventHandler, build):
|
||||||
# Consume as many messages as we can ...
|
# Consume as many messages as we can ...
|
||||||
event = eventHandler.getEvent()
|
event = eventHandler.getEvent()
|
||||||
while event:
|
while event:
|
||||||
build.handle_event (event)
|
build.handle_event (event)
|
||||||
event = eventHandler.getEvent()
|
event = eventHandler.getEvent()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
class MainWindow (gtk.Window):
|
class MainWindow (gtk.Window):
|
||||||
|
|
||||||
# Callback that gets fired when the user hits a button in the
|
# Callback that gets fired when the user hits a button in the
|
||||||
# BuildSetupDialog.
|
# BuildSetupDialog.
|
||||||
def build_dialog_box_response_cb (self, dialog, response_id):
|
def build_dialog_box_response_cb (self, dialog, response_id):
|
||||||
conf = None
|
conf = None
|
||||||
if (response_id == BuildSetupDialog.RESPONSE_BUILD):
|
if (response_id == BuildSetupDialog.RESPONSE_BUILD):
|
||||||
dialog.update_configuration()
|
dialog.update_configuration()
|
||||||
print dialog.configuration.machine, dialog.configuration.distro, \
|
print(dialog.configuration.machine, dialog.configuration.distro, \
|
||||||
dialog.configuration.image
|
dialog.configuration.image)
|
||||||
conf = dialog.configuration
|
conf = dialog.configuration
|
||||||
|
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
|
|
||||||
if conf:
|
if conf:
|
||||||
self.manager.do_build (conf)
|
self.manager.do_build (conf)
|
||||||
|
|
||||||
def build_button_clicked_cb (self, button):
|
def build_button_clicked_cb (self, button):
|
||||||
dialog = BuildSetupDialog ()
|
dialog = BuildSetupDialog ()
|
||||||
|
|
||||||
# For some unknown reason Dialog.run causes nice little deadlocks ... :-(
|
# For some unknown reason Dialog.run causes nice little deadlocks ... :-(
|
||||||
dialog.connect ("response", self.build_dialog_box_response_cb)
|
dialog.connect ("response", self.build_dialog_box_response_cb)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
def __init__ (self):
|
def __init__ (self):
|
||||||
gtk.Window.__init__ (self)
|
gtk.Window.__init__ (self)
|
||||||
|
|
||||||
# Pull in *just* the main vbox from the Glade XML data and then pack
|
# Pull in *just* the main vbox from the Glade XML data and then pack
|
||||||
# that inside the window
|
# that inside the window
|
||||||
gxml = gtk.glade.XML (os.path.dirname(__file__) + "/crumbs/puccho.glade",
|
gxml = gtk.glade.XML (os.path.dirname(__file__) + "/crumbs/puccho.glade",
|
||||||
root = "main_window_vbox")
|
root = "main_window_vbox")
|
||||||
vbox = gxml.get_widget ("main_window_vbox")
|
vbox = gxml.get_widget ("main_window_vbox")
|
||||||
self.add (vbox)
|
self.add (vbox)
|
||||||
|
|
||||||
# Create the tree views for the build manager view and the progress view
|
# Create the tree views for the build manager view and the progress view
|
||||||
self.build_manager_view = BuildManagerTreeView()
|
self.build_manager_view = BuildManagerTreeView()
|
||||||
self.running_build_view = RunningBuildTreeView()
|
self.running_build_view = RunningBuildTreeView()
|
||||||
|
|
||||||
# Grab the scrolled windows that we put the tree views into
|
# Grab the scrolled windows that we put the tree views into
|
||||||
self.results_scrolledwindow = gxml.get_widget ("results_scrolledwindow")
|
self.results_scrolledwindow = gxml.get_widget ("results_scrolledwindow")
|
||||||
self.progress_scrolledwindow = gxml.get_widget ("progress_scrolledwindow")
|
self.progress_scrolledwindow = gxml.get_widget ("progress_scrolledwindow")
|
||||||
|
|
||||||
# Put the tree views inside ...
|
# Put the tree views inside ...
|
||||||
self.results_scrolledwindow.add (self.build_manager_view)
|
self.results_scrolledwindow.add (self.build_manager_view)
|
||||||
self.progress_scrolledwindow.add (self.running_build_view)
|
self.progress_scrolledwindow.add (self.running_build_view)
|
||||||
|
|
||||||
# Hook up the build button...
|
# Hook up the build button...
|
||||||
self.build_button = gxml.get_widget ("main_toolbutton_build")
|
self.build_button = gxml.get_widget ("main_toolbutton_build")
|
||||||
self.build_button.connect ("clicked", self.build_button_clicked_cb)
|
self.build_button.connect ("clicked", self.build_button_clicked_cb)
|
||||||
|
|
||||||
# I'm not very happy about the current ownership of the RunningBuild. I have
|
# I'm not very happy about the current ownership of the RunningBuild. I have
|
||||||
# my suspicions that this object should be held by the BuildManager since we
|
# my suspicions that this object should be held by the BuildManager since we
|
||||||
@@ -383,11 +383,11 @@ def running_build_succeeded_cb (running_build, manager):
|
|||||||
# BuildManager. It can then hook onto the signals directly and drive
|
# BuildManager. It can then hook onto the signals directly and drive
|
||||||
# interesting things it cares about.
|
# interesting things it cares about.
|
||||||
manager.notify_build_succeeded ()
|
manager.notify_build_succeeded ()
|
||||||
print "build succeeded"
|
print("build succeeded")
|
||||||
|
|
||||||
def running_build_failed_cb (running_build, manager):
|
def running_build_failed_cb (running_build, manager):
|
||||||
# As above
|
# As above
|
||||||
print "build failed"
|
print("build failed")
|
||||||
manager.notify_build_failed ()
|
manager.notify_build_failed ()
|
||||||
|
|
||||||
def init (server, eventHandler):
|
def init (server, eventHandler):
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Use this class to fork off a thread to recieve event callbacks from the bitbake
|
Use this class to fork off a thread to recieve event callbacks from the bitbake
|
||||||
server and queue them for the UI to process. This process must be used to avoid
|
server and queue them for the UI to process. This process must be used to avoid
|
||||||
client/server deadlocks.
|
client/server deadlocks.
|
||||||
"""
|
"""
|
||||||
@@ -110,16 +110,15 @@ class UIXMLRPCServer (SimpleXMLRPCServer):
|
|||||||
return (sock, addr)
|
return (sock, addr)
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
pass
|
pass
|
||||||
return (None,None)
|
return (None, None)
|
||||||
|
|
||||||
def close_request(self, request):
|
def close_request(self, request):
|
||||||
if request is None:
|
if request is None:
|
||||||
return
|
return
|
||||||
SimpleXMLRPCServer.close_request(self, request)
|
SimpleXMLRPCServer.close_request(self, request)
|
||||||
|
|
||||||
def process_request(self, request, client_address):
|
def process_request(self, request, client_address):
|
||||||
if request is None:
|
if request is None:
|
||||||
return
|
return
|
||||||
SimpleXMLRPCServer.process_request(self, request, client_address)
|
SimpleXMLRPCServer.process_request(self, request, client_address)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,22 @@ BitBake Utility Functions
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
import re, fcntl, os, string, stat, shutil, time
|
||||||
|
import sys
|
||||||
|
import bb
|
||||||
|
import errno
|
||||||
|
import bb.msg
|
||||||
|
from commands import getstatusoutput
|
||||||
|
|
||||||
|
# Version comparison
|
||||||
separators = ".-"
|
separators = ".-"
|
||||||
|
|
||||||
import re, fcntl, os, types, bb, string, stat, shutil
|
# Context used in better_exec, eval
|
||||||
from commands import getstatusoutput
|
_context = {
|
||||||
|
"os": os,
|
||||||
|
"bb": bb,
|
||||||
|
"time": time,
|
||||||
|
}
|
||||||
|
|
||||||
def explode_version(s):
|
def explode_version(s):
|
||||||
r = []
|
r = []
|
||||||
@@ -60,9 +72,9 @@ def vercmp_part(a, b):
|
|||||||
if ca == None and cb == None:
|
if ca == None and cb == None:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if type(ca) is types.StringType:
|
if isinstance(ca, basestring):
|
||||||
sa = ca in separators
|
sa = ca in separators
|
||||||
if type(cb) is types.StringType:
|
if isinstance(cb, basestring):
|
||||||
sb = cb in separators
|
sb = cb in separators
|
||||||
if sa and not sb:
|
if sa and not sb:
|
||||||
return -1
|
return -1
|
||||||
@@ -85,6 +97,131 @@ def vercmp(ta, tb):
|
|||||||
r = vercmp_part(ra, rb)
|
r = vercmp_part(ra, rb)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
_package_weights_ = {"pre":-2, "p":0, "alpha":-4, "beta":-3, "rc":-1} # dicts are unordered
|
||||||
|
_package_ends_ = ["pre", "p", "alpha", "beta", "rc", "cvs", "bk", "HEAD" ] # so we need ordered list
|
||||||
|
|
||||||
|
def relparse(myver):
|
||||||
|
"""Parses the last elements of a version number into a triplet, that can
|
||||||
|
later be compared.
|
||||||
|
"""
|
||||||
|
|
||||||
|
number = 0
|
||||||
|
p1 = 0
|
||||||
|
p2 = 0
|
||||||
|
mynewver = myver.split('_')
|
||||||
|
if len(mynewver) == 2:
|
||||||
|
# an _package_weights_
|
||||||
|
number = float(mynewver[0])
|
||||||
|
match = 0
|
||||||
|
for x in _package_ends_:
|
||||||
|
elen = len(x)
|
||||||
|
if mynewver[1][:elen] == x:
|
||||||
|
match = 1
|
||||||
|
p1 = _package_weights_[x]
|
||||||
|
try:
|
||||||
|
p2 = float(mynewver[1][elen:])
|
||||||
|
except:
|
||||||
|
p2 = 0
|
||||||
|
break
|
||||||
|
if not match:
|
||||||
|
# normal number or number with letter at end
|
||||||
|
divider = len(myver)-1
|
||||||
|
if myver[divider:] not in "1234567890":
|
||||||
|
# letter at end
|
||||||
|
p1 = ord(myver[divider:])
|
||||||
|
number = float(myver[0:divider])
|
||||||
|
else:
|
||||||
|
number = float(myver)
|
||||||
|
else:
|
||||||
|
# normal number or number with letter at end
|
||||||
|
divider = len(myver)-1
|
||||||
|
if myver[divider:] not in "1234567890":
|
||||||
|
#letter at end
|
||||||
|
p1 = ord(myver[divider:])
|
||||||
|
number = float(myver[0:divider])
|
||||||
|
else:
|
||||||
|
number = float(myver)
|
||||||
|
return [number, p1, p2]
|
||||||
|
|
||||||
|
__vercmp_cache__ = {}
|
||||||
|
|
||||||
|
def vercmp_string(val1, val2):
|
||||||
|
"""This takes two version strings and returns an integer to tell you whether
|
||||||
|
the versions are the same, val1>val2 or val2>val1.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# quick short-circuit
|
||||||
|
if val1 == val2:
|
||||||
|
return 0
|
||||||
|
valkey = val1 + " " + val2
|
||||||
|
|
||||||
|
# cache lookup
|
||||||
|
try:
|
||||||
|
return __vercmp_cache__[valkey]
|
||||||
|
try:
|
||||||
|
return - __vercmp_cache__[val2 + " " + val1]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# consider 1_p2 vc 1.1
|
||||||
|
# after expansion will become (1_p2,0) vc (1,1)
|
||||||
|
# then 1_p2 is compared with 1 before 0 is compared with 1
|
||||||
|
# to solve the bug we need to convert it to (1,0_p2)
|
||||||
|
# by splitting _prepart part and adding it back _after_expansion
|
||||||
|
|
||||||
|
val1_prepart = val2_prepart = ''
|
||||||
|
if val1.count('_'):
|
||||||
|
val1, val1_prepart = val1.split('_', 1)
|
||||||
|
if val2.count('_'):
|
||||||
|
val2, val2_prepart = val2.split('_', 1)
|
||||||
|
|
||||||
|
# replace '-' by '.'
|
||||||
|
# FIXME: Is it needed? can val1/2 contain '-'?
|
||||||
|
|
||||||
|
val1 = val1.split("-")
|
||||||
|
if len(val1) == 2:
|
||||||
|
val1[0] = val1[0] + "." + val1[1]
|
||||||
|
val2 = val2.split("-")
|
||||||
|
if len(val2) == 2:
|
||||||
|
val2[0] = val2[0] + "." + val2[1]
|
||||||
|
|
||||||
|
val1 = val1[0].split('.')
|
||||||
|
val2 = val2[0].split('.')
|
||||||
|
|
||||||
|
# add back decimal point so that .03 does not become "3" !
|
||||||
|
for x in range(1, len(val1)):
|
||||||
|
if val1[x][0] == '0' :
|
||||||
|
val1[x] = '.' + val1[x]
|
||||||
|
for x in range(1, len(val2)):
|
||||||
|
if val2[x][0] == '0' :
|
||||||
|
val2[x] = '.' + val2[x]
|
||||||
|
|
||||||
|
# extend varion numbers
|
||||||
|
if len(val2) < len(val1):
|
||||||
|
val2.extend(["0"]*(len(val1)-len(val2)))
|
||||||
|
elif len(val1) < len(val2):
|
||||||
|
val1.extend(["0"]*(len(val2)-len(val1)))
|
||||||
|
|
||||||
|
# add back _prepart tails
|
||||||
|
if val1_prepart:
|
||||||
|
val1[-1] += '_' + val1_prepart
|
||||||
|
if val2_prepart:
|
||||||
|
val2[-1] += '_' + val2_prepart
|
||||||
|
# The above code will extend version numbers out so they
|
||||||
|
# have the same number of digits.
|
||||||
|
for x in range(0, len(val1)):
|
||||||
|
cmp1 = relparse(val1[x])
|
||||||
|
cmp2 = relparse(val2[x])
|
||||||
|
for y in range(0, 3):
|
||||||
|
myret = cmp1[y] - cmp2[y]
|
||||||
|
if myret != 0:
|
||||||
|
__vercmp_cache__[valkey] = myret
|
||||||
|
return myret
|
||||||
|
__vercmp_cache__[valkey] = 0
|
||||||
|
return 0
|
||||||
|
|
||||||
def explode_deps(s):
|
def explode_deps(s):
|
||||||
"""
|
"""
|
||||||
Take an RDEPENDS style string of format:
|
Take an RDEPENDS style string of format:
|
||||||
@@ -113,10 +250,10 @@ def explode_dep_versions(s):
|
|||||||
"""
|
"""
|
||||||
Take an RDEPENDS style string of format:
|
Take an RDEPENDS style string of format:
|
||||||
"DEPEND1 (optional version) DEPEND2 (optional version) ..."
|
"DEPEND1 (optional version) DEPEND2 (optional version) ..."
|
||||||
and return a dictonary of dependencies and versions.
|
and return a dictionary of dependencies and versions.
|
||||||
"""
|
"""
|
||||||
r = {}
|
r = {}
|
||||||
l = s.split()
|
l = s.replace(",", "").split()
|
||||||
lastdep = None
|
lastdep = None
|
||||||
lastver = ""
|
lastver = ""
|
||||||
inversion = False
|
inversion = False
|
||||||
@@ -138,40 +275,61 @@ def explode_dep_versions(s):
|
|||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
def join_deps(deps):
|
||||||
|
"""
|
||||||
|
Take the result from explode_dep_versions and generate a dependency string
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
for dep in deps:
|
||||||
|
if deps[dep]:
|
||||||
|
result.append(dep + " (" + deps[dep] + ")")
|
||||||
|
else:
|
||||||
|
result.append(dep)
|
||||||
|
return ", ".join(result)
|
||||||
|
|
||||||
|
def extend_deps(dest, src):
|
||||||
|
"""
|
||||||
|
Extend the results from explode_dep_versions by appending all of the items
|
||||||
|
in the second list, avoiding duplicates.
|
||||||
|
"""
|
||||||
|
for dep in src:
|
||||||
|
if dep not in dest:
|
||||||
|
dest[dep] = src[dep]
|
||||||
|
elif dest[dep] != src[dep]:
|
||||||
|
dest[dep] = src[dep]
|
||||||
|
|
||||||
def _print_trace(body, line):
|
def _print_trace(body, line):
|
||||||
"""
|
"""
|
||||||
Print the Environment of a Text Body
|
Print the Environment of a Text Body
|
||||||
"""
|
"""
|
||||||
import bb
|
|
||||||
|
|
||||||
# print the environment of the method
|
# print the environment of the method
|
||||||
bb.msg.error(bb.msg.domain.Util, "Printing the environment of the function")
|
min_line = max(1, line-4)
|
||||||
min_line = max(1,line-4)
|
max_line = min(line + 4, len(body)-1)
|
||||||
max_line = min(line+4,len(body)-1)
|
for i in range(min_line, max_line + 1):
|
||||||
for i in range(min_line,max_line+1):
|
|
||||||
bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) )
|
bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) )
|
||||||
|
|
||||||
|
|
||||||
def better_compile(text, file, realfile):
|
def better_compile(text, file, realfile, mode = "exec"):
|
||||||
"""
|
"""
|
||||||
A better compile method. This method
|
A better compile method. This method
|
||||||
will print the offending lines.
|
will print the offending lines.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return compile(text, file, "exec")
|
return compile(text, file, mode)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
import bb,sys
|
|
||||||
|
|
||||||
# split the text into lines again
|
# split the text into lines again
|
||||||
body = text.split('\n')
|
body = text.split('\n')
|
||||||
bb.msg.error(bb.msg.domain.Util, "Error in compiling python function in: ", realfile)
|
bb.msg.error(bb.msg.domain.Util, "Error in compiling python function in: %s" % (realfile))
|
||||||
bb.msg.error(bb.msg.domain.Util, "The lines leading to this error were:")
|
bb.msg.error(bb.msg.domain.Util, str(e))
|
||||||
bb.msg.error(bb.msg.domain.Util, "\t%d:%s:'%s'" % (e.lineno, e.__class__.__name__, body[e.lineno-1]))
|
if e.lineno:
|
||||||
|
bb.msg.error(bb.msg.domain.Util, "The lines leading to this error were:")
|
||||||
_print_trace(body, e.lineno)
|
bb.msg.error(bb.msg.domain.Util, "\t%d:%s:'%s'" % (e.lineno, e.__class__.__name__, body[e.lineno-1]))
|
||||||
|
_print_trace(body, e.lineno)
|
||||||
# exit now
|
else:
|
||||||
sys.exit(1)
|
bb.msg.error(bb.msg.domain.Util, "The function causing this error was:")
|
||||||
|
for line in body:
|
||||||
|
bb.msg.error(bb.msg.domain.Util, line)
|
||||||
|
raise
|
||||||
|
|
||||||
def better_exec(code, context, text, realfile):
|
def better_exec(code, context, text, realfile):
|
||||||
"""
|
"""
|
||||||
@@ -179,69 +337,40 @@ def better_exec(code, context, text, realfile):
|
|||||||
print the lines that are responsible for the
|
print the lines that are responsible for the
|
||||||
error.
|
error.
|
||||||
"""
|
"""
|
||||||
import bb,sys
|
import bb.parse
|
||||||
try:
|
try:
|
||||||
exec code in context
|
exec(code, _context, context)
|
||||||
except:
|
except:
|
||||||
(t,value,tb) = sys.exc_info()
|
(t, value, tb) = sys.exc_info()
|
||||||
|
|
||||||
if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
|
if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# print the Header of the Error Message
|
# print the Header of the Error Message
|
||||||
bb.msg.error(bb.msg.domain.Util, "Error in executing python function in: %s" % realfile)
|
bb.msg.error(bb.msg.domain.Util, "Error in executing python function in: %s" % realfile)
|
||||||
bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t,value) )
|
bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t, value))
|
||||||
|
|
||||||
# let us find the line number now
|
# Strip 'us' from the stack (better_exec call)
|
||||||
while tb.tb_next:
|
tb = tb.tb_next
|
||||||
tb = tb.tb_next
|
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
line = traceback.tb_lineno(tb)
|
tbextract = traceback.extract_tb(tb)
|
||||||
|
tbextract = "\n".join(traceback.format_list(tbextract))
|
||||||
|
bb.msg.error(bb.msg.domain.Util, "Traceback:")
|
||||||
|
for line in tbextract.split('\n'):
|
||||||
|
bb.msg.error(bb.msg.domain.Util, line)
|
||||||
|
|
||||||
|
line = traceback.tb_lineno(tb)
|
||||||
|
bb.msg.error(bb.msg.domain.Util, "The lines leading to this error were:")
|
||||||
_print_trace( text.split('\n'), line )
|
_print_trace( text.split('\n'), line )
|
||||||
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def Enum(*names):
|
def simple_exec(code, context):
|
||||||
"""
|
exec(code, _context, context)
|
||||||
A simple class to give Enum support
|
|
||||||
"""
|
|
||||||
|
|
||||||
assert names, "Empty enums are not supported"
|
def better_eval(source, locals):
|
||||||
|
return eval(source, _context, locals)
|
||||||
class EnumClass(object):
|
|
||||||
__slots__ = names
|
|
||||||
def __iter__(self): return iter(constants)
|
|
||||||
def __len__(self): return len(constants)
|
|
||||||
def __getitem__(self, i): return constants[i]
|
|
||||||
def __repr__(self): return 'Enum' + str(names)
|
|
||||||
def __str__(self): return 'enum ' + str(constants)
|
|
||||||
|
|
||||||
class EnumValue(object):
|
|
||||||
__slots__ = ('__value')
|
|
||||||
def __init__(self, value): self.__value = value
|
|
||||||
Value = property(lambda self: self.__value)
|
|
||||||
EnumType = property(lambda self: EnumType)
|
|
||||||
def __hash__(self): return hash(self.__value)
|
|
||||||
def __cmp__(self, other):
|
|
||||||
# C fans might want to remove the following assertion
|
|
||||||
# to make all enums comparable by ordinal value {;))
|
|
||||||
assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
|
|
||||||
return cmp(self.__value, other.__value)
|
|
||||||
def __invert__(self): return constants[maximum - self.__value]
|
|
||||||
def __nonzero__(self): return bool(self.__value)
|
|
||||||
def __repr__(self): return str(names[self.__value])
|
|
||||||
|
|
||||||
maximum = len(names) - 1
|
|
||||||
constants = [None] * len(names)
|
|
||||||
for i, each in enumerate(names):
|
|
||||||
val = EnumValue(i)
|
|
||||||
setattr(EnumClass, each, val)
|
|
||||||
constants[i] = val
|
|
||||||
constants = tuple(constants)
|
|
||||||
EnumType = EnumClass()
|
|
||||||
return EnumType
|
|
||||||
|
|
||||||
def lockfile(name):
|
def lockfile(name):
|
||||||
"""
|
"""
|
||||||
@@ -250,37 +379,36 @@ def lockfile(name):
|
|||||||
"""
|
"""
|
||||||
path = os.path.dirname(name)
|
path = os.path.dirname(name)
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
import bb, sys
|
|
||||||
bb.msg.error(bb.msg.domain.Util, "Error, lockfile path does not exist!: %s" % path)
|
bb.msg.error(bb.msg.domain.Util, "Error, lockfile path does not exist!: %s" % path)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# If we leave the lockfiles lying around there is no problem
|
# If we leave the lockfiles lying around there is no problem
|
||||||
# but we should clean up after ourselves. This gives potential
|
# but we should clean up after ourselves. This gives potential
|
||||||
# for races though. To work around this, when we acquire the lock
|
# for races though. To work around this, when we acquire the lock
|
||||||
# we check the file we locked was still the lock file on disk.
|
# we check the file we locked was still the lock file on disk.
|
||||||
# by comparing inode numbers. If they don't match or the lockfile
|
# by comparing inode numbers. If they don't match or the lockfile
|
||||||
# no longer exists, we start again.
|
# no longer exists, we start again.
|
||||||
|
|
||||||
# This implementation is unfair since the last person to request the
|
# This implementation is unfair since the last person to request the
|
||||||
# lock is the most likely to win it.
|
# lock is the most likely to win it.
|
||||||
|
|
||||||
try:
|
try:
|
||||||
lf = open(name, "a+")
|
lf = open(name, "a + ")
|
||||||
fcntl.flock(lf.fileno(), fcntl.LOCK_EX)
|
fcntl.flock(lf.fileno(), fcntl.LOCK_EX)
|
||||||
statinfo = os.fstat(lf.fileno())
|
statinfo = os.fstat(lf.fileno())
|
||||||
if os.path.exists(lf.name):
|
if os.path.exists(lf.name):
|
||||||
statinfo2 = os.stat(lf.name)
|
statinfo2 = os.stat(lf.name)
|
||||||
if statinfo.st_ino == statinfo2.st_ino:
|
if statinfo.st_ino == statinfo2.st_ino:
|
||||||
return lf
|
return lf
|
||||||
# File no longer exists or changed, retry
|
# File no longer exists or changed, retry
|
||||||
lf.close
|
lf.close
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def unlockfile(lf):
|
def unlockfile(lf):
|
||||||
"""
|
"""
|
||||||
Unlock a file locked using lockfile()
|
Unlock a file locked using lockfile()
|
||||||
"""
|
"""
|
||||||
os.unlink(lf.name)
|
os.unlink(lf.name)
|
||||||
fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
|
fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
|
||||||
@@ -296,7 +424,7 @@ def md5_file(filename):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
import md5
|
import md5
|
||||||
m = md5.new()
|
m = md5.new()
|
||||||
|
|
||||||
for line in open(filename):
|
for line in open(filename):
|
||||||
m.update(line)
|
m.update(line)
|
||||||
return m.hexdigest()
|
return m.hexdigest()
|
||||||
@@ -324,6 +452,7 @@ def preserved_envvars_list():
|
|||||||
'BB_PRESERVE_ENV',
|
'BB_PRESERVE_ENV',
|
||||||
'BB_ENV_WHITELIST',
|
'BB_ENV_WHITELIST',
|
||||||
'BB_ENV_EXTRAWHITE',
|
'BB_ENV_EXTRAWHITE',
|
||||||
|
'BB_TASKHASH',
|
||||||
'COLORTERM',
|
'COLORTERM',
|
||||||
'DBUS_SESSION_BUS_ADDRESS',
|
'DBUS_SESSION_BUS_ADDRESS',
|
||||||
'DESKTOP_SESSION',
|
'DESKTOP_SESSION',
|
||||||
@@ -356,19 +485,17 @@ def filter_environment(good_vars):
|
|||||||
are not known and may influence the build in a negative way.
|
are not known and may influence the build in a negative way.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import bb
|
|
||||||
|
|
||||||
removed_vars = []
|
removed_vars = []
|
||||||
for key in os.environ.keys():
|
for key in os.environ.keys():
|
||||||
if key in good_vars:
|
if key in good_vars:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
removed_vars.append(key)
|
removed_vars.append(key)
|
||||||
os.unsetenv(key)
|
os.unsetenv(key)
|
||||||
del os.environ[key]
|
del os.environ[key]
|
||||||
|
|
||||||
if len(removed_vars):
|
if len(removed_vars):
|
||||||
bb.debug(1, "Removed the following variables from the environment:", ",".join(removed_vars))
|
bb.msg.debug(1, bb.msg.domain.Util, "Removed the following variables from the environment: %s" % (", ".join(removed_vars)))
|
||||||
|
|
||||||
return removed_vars
|
return removed_vars
|
||||||
|
|
||||||
@@ -398,7 +525,7 @@ def build_environment(d):
|
|||||||
"""
|
"""
|
||||||
Build an environment from all exported variables.
|
Build an environment from all exported variables.
|
||||||
"""
|
"""
|
||||||
import bb
|
import bb.data
|
||||||
for var in bb.data.keys(d):
|
for var in bb.data.keys(d):
|
||||||
export = bb.data.getVarFlag(var, "export", d)
|
export = bb.data.getVarFlag(var, "export", d)
|
||||||
if export:
|
if export:
|
||||||
@@ -407,7 +534,7 @@ def build_environment(d):
|
|||||||
def prunedir(topdir):
|
def prunedir(topdir):
|
||||||
# Delete everything reachable from the directory named in 'topdir'.
|
# Delete everything reachable from the directory named in 'topdir'.
|
||||||
# CAUTION: This is dangerous!
|
# CAUTION: This is dangerous!
|
||||||
for root, dirs, files in os.walk(topdir, topdown=False):
|
for root, dirs, files in os.walk(topdir, topdown = False):
|
||||||
for name in files:
|
for name in files:
|
||||||
os.remove(os.path.join(root, name))
|
os.remove(os.path.join(root, name))
|
||||||
for name in dirs:
|
for name in dirs:
|
||||||
@@ -422,7 +549,7 @@ def prunedir(topdir):
|
|||||||
# but thats possibly insane and suffixes is probably going to be small
|
# but thats possibly insane and suffixes is probably going to be small
|
||||||
#
|
#
|
||||||
def prune_suffix(var, suffixes, d):
|
def prune_suffix(var, suffixes, d):
|
||||||
# See if var ends with any of the suffixes listed and
|
# See if var ends with any of the suffixes listed and
|
||||||
# remove it if found
|
# remove it if found
|
||||||
for suffix in suffixes:
|
for suffix in suffixes:
|
||||||
if var.endswith(suffix):
|
if var.endswith(suffix):
|
||||||
@@ -434,169 +561,172 @@ def mkdirhier(dir):
|
|||||||
directory already exists like os.makedirs
|
directory already exists like os.makedirs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
bb.debug(3, "mkdirhier(%s)" % dir)
|
bb.msg.debug(3, bb.msg.domain.Util, "mkdirhier(%s)" % dir)
|
||||||
try:
|
try:
|
||||||
os.makedirs(dir)
|
os.makedirs(dir)
|
||||||
bb.debug(2, "created " + dir)
|
bb.msg.debug(2, bb.msg.domain.Util, "created " + dir)
|
||||||
except OSError, e:
|
except OSError as e:
|
||||||
if e.errno != 17: raise e
|
if e.errno != errno.EEXIST:
|
||||||
|
raise e
|
||||||
|
|
||||||
import stat
|
def movefile(src, dest, newmtime = None, sstat = None):
|
||||||
|
|
||||||
def movefile(src,dest,newmtime=None,sstat=None):
|
|
||||||
"""Moves a file from src to dest, preserving all permissions and
|
"""Moves a file from src to dest, preserving all permissions and
|
||||||
attributes; mtime will be preserved even when moving across
|
attributes; mtime will be preserved even when moving across
|
||||||
filesystems. Returns true on success and false on failure. Move is
|
filesystems. Returns true on success and false on failure. Move is
|
||||||
atomic.
|
atomic.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#print "movefile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")"
|
#print "movefile(" + src + "," + dest + "," + str(newmtime) + "," + str(sstat) + ")"
|
||||||
try:
|
try:
|
||||||
if not sstat:
|
if not sstat:
|
||||||
sstat=os.lstat(src)
|
sstat = os.lstat(src)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print "movefile: Stating source file failed...", e
|
print("movefile: Stating source file failed...", e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
destexists=1
|
destexists = 1
|
||||||
try:
|
try:
|
||||||
dstat=os.lstat(dest)
|
dstat = os.lstat(dest)
|
||||||
except:
|
except:
|
||||||
dstat=os.lstat(os.path.dirname(dest))
|
dstat = os.lstat(os.path.dirname(dest))
|
||||||
destexists=0
|
destexists = 0
|
||||||
|
|
||||||
if destexists:
|
if destexists:
|
||||||
if stat.S_ISLNK(dstat[stat.ST_MODE]):
|
if stat.S_ISLNK(dstat[stat.ST_MODE]):
|
||||||
try:
|
try:
|
||||||
os.unlink(dest)
|
os.unlink(dest)
|
||||||
destexists=0
|
destexists = 0
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if stat.S_ISLNK(sstat[stat.ST_MODE]):
|
if stat.S_ISLNK(sstat[stat.ST_MODE]):
|
||||||
try:
|
try:
|
||||||
target=os.readlink(src)
|
target = os.readlink(src)
|
||||||
if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
|
if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
|
||||||
os.unlink(dest)
|
os.unlink(dest)
|
||||||
os.symlink(target,dest)
|
os.symlink(target, dest)
|
||||||
#os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
|
#os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
|
||||||
os.unlink(src)
|
os.unlink(src)
|
||||||
return os.lstat(dest)
|
return os.lstat(dest)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print "movefile: failed to properly create symlink:", dest, "->", target, e
|
print("movefile: failed to properly create symlink:", dest, "->", target, e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
renamefailed=1
|
renamefailed = 1
|
||||||
if sstat[stat.ST_DEV]==dstat[stat.ST_DEV]:
|
if sstat[stat.ST_DEV] == dstat[stat.ST_DEV]:
|
||||||
try:
|
try:
|
||||||
ret=os.rename(src,dest)
|
os.rename(src, dest)
|
||||||
renamefailed=0
|
renamefailed = 0
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
import errno
|
if e[0] != errno.EXDEV:
|
||||||
if e[0]!=errno.EXDEV:
|
|
||||||
# Some random error.
|
# Some random error.
|
||||||
print "movefile: Failed to move", src, "to", dest, e
|
print("movefile: Failed to move", src, "to", dest, e)
|
||||||
return None
|
return None
|
||||||
# Invalid cross-device-link 'bind' mounted or actually Cross-Device
|
# Invalid cross-device-link 'bind' mounted or actually Cross-Device
|
||||||
|
|
||||||
if renamefailed:
|
if renamefailed:
|
||||||
didcopy=0
|
didcopy = 0
|
||||||
if stat.S_ISREG(sstat[stat.ST_MODE]):
|
if stat.S_ISREG(sstat[stat.ST_MODE]):
|
||||||
try: # For safety copy then move it over.
|
try: # For safety copy then move it over.
|
||||||
shutil.copyfile(src,dest+"#new")
|
shutil.copyfile(src, dest + "#new")
|
||||||
os.rename(dest+"#new",dest)
|
os.rename(dest + "#new", dest)
|
||||||
didcopy=1
|
didcopy = 1
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print 'movefile: copy', src, '->', dest, 'failed.', e
|
print('movefile: copy', src, '->', dest, 'failed.', e)
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
#we don't yet handle special, so we need to fall back to /bin/mv
|
#we don't yet handle special, so we need to fall back to /bin/mv
|
||||||
a=getstatusoutput("/bin/mv -f "+"'"+src+"' '"+dest+"'")
|
a = getstatusoutput("/bin/mv -f " + "'" + src + "' '" + dest + "'")
|
||||||
if a[0]!=0:
|
if a[0] != 0:
|
||||||
print "movefile: Failed to move special file:" + src + "' to '" + dest + "'", a
|
print("movefile: Failed to move special file:" + src + "' to '" + dest + "'", a)
|
||||||
return None # failure
|
return None # failure
|
||||||
try:
|
try:
|
||||||
if didcopy:
|
if didcopy:
|
||||||
os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
|
os.lchown(dest, sstat[stat.ST_UID], sstat[stat.ST_GID])
|
||||||
os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
|
os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
|
||||||
os.unlink(src)
|
os.unlink(src)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print "movefile: Failed to chown/chmod/unlink", dest, e
|
print("movefile: Failed to chown/chmod/unlink", dest, e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if newmtime:
|
if newmtime:
|
||||||
os.utime(dest,(newmtime,newmtime))
|
os.utime(dest, (newmtime, newmtime))
|
||||||
else:
|
else:
|
||||||
os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
|
os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
|
||||||
newmtime=sstat[stat.ST_MTIME]
|
newmtime = sstat[stat.ST_MTIME]
|
||||||
return newmtime
|
return newmtime
|
||||||
|
|
||||||
def copyfile(src,dest,newmtime=None,sstat=None):
|
def copyfile(src, dest, newmtime = None, sstat = None):
|
||||||
"""
|
"""
|
||||||
Copies a file from src to dest, preserving all permissions and
|
Copies a file from src to dest, preserving all permissions and
|
||||||
attributes; mtime will be preserved even when moving across
|
attributes; mtime will be preserved even when moving across
|
||||||
filesystems. Returns true on success and false on failure.
|
filesystems. Returns true on success and false on failure.
|
||||||
"""
|
"""
|
||||||
#print "copyfile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")"
|
#print "copyfile(" + src + "," + dest + "," + str(newmtime) + "," + str(sstat) + ")"
|
||||||
try:
|
try:
|
||||||
if not sstat:
|
if not sstat:
|
||||||
sstat=os.lstat(src)
|
sstat = os.lstat(src)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print "copyfile: Stating source file failed...", e
|
print("copyfile: Stating source file failed...", e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
destexists=1
|
destexists = 1
|
||||||
try:
|
try:
|
||||||
dstat=os.lstat(dest)
|
dstat = os.lstat(dest)
|
||||||
except:
|
except:
|
||||||
dstat=os.lstat(os.path.dirname(dest))
|
dstat = os.lstat(os.path.dirname(dest))
|
||||||
destexists=0
|
destexists = 0
|
||||||
|
|
||||||
if destexists:
|
if destexists:
|
||||||
if stat.S_ISLNK(dstat[stat.ST_MODE]):
|
if stat.S_ISLNK(dstat[stat.ST_MODE]):
|
||||||
try:
|
try:
|
||||||
os.unlink(dest)
|
os.unlink(dest)
|
||||||
destexists=0
|
destexists = 0
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if stat.S_ISLNK(sstat[stat.ST_MODE]):
|
if stat.S_ISLNK(sstat[stat.ST_MODE]):
|
||||||
try:
|
try:
|
||||||
target=os.readlink(src)
|
target = os.readlink(src)
|
||||||
if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
|
if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
|
||||||
os.unlink(dest)
|
os.unlink(dest)
|
||||||
os.symlink(target,dest)
|
os.symlink(target, dest)
|
||||||
#os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
|
#os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
|
||||||
return os.lstat(dest)
|
return os.lstat(dest)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print "copyfile: failed to properly create symlink:", dest, "->", target, e
|
print("copyfile: failed to properly create symlink:", dest, "->", target, e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if stat.S_ISREG(sstat[stat.ST_MODE]):
|
if stat.S_ISREG(sstat[stat.ST_MODE]):
|
||||||
try: # For safety copy then move it over.
|
os.chmod(src, stat.S_IRUSR) # Make sure we can read it
|
||||||
shutil.copyfile(src,dest+"#new")
|
try: # For safety copy then move it over.
|
||||||
os.rename(dest+"#new",dest)
|
shutil.copyfile(src, dest + "#new")
|
||||||
except Exception, e:
|
os.rename(dest + "#new", dest)
|
||||||
print 'copyfile: copy', src, '->', dest, 'failed.', e
|
except Exception as e:
|
||||||
return False
|
print('copyfile: copy', src, '->', dest, 'failed.', e)
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
os.chmod(src, sstat[stat.ST_MODE])
|
||||||
|
os.utime(src, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
#we don't yet handle special, so we need to fall back to /bin/mv
|
#we don't yet handle special, so we need to fall back to /bin/mv
|
||||||
a=getstatusoutput("/bin/cp -f "+"'"+src+"' '"+dest+"'")
|
a = getstatusoutput("/bin/cp -f " + "'" + src + "' '" + dest + "'")
|
||||||
if a[0]!=0:
|
if a[0] != 0:
|
||||||
print "copyfile: Failed to copy special file:" + src + "' to '" + dest + "'", a
|
print("copyfile: Failed to copy special file:" + src + "' to '" + dest + "'", a)
|
||||||
return False # failure
|
return False # failure
|
||||||
try:
|
try:
|
||||||
os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
|
os.lchown(dest, sstat[stat.ST_UID], sstat[stat.ST_GID])
|
||||||
os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
|
os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print "copyfile: Failed to chown/chmod/unlink", dest, e
|
print("copyfile: Failed to chown/chmod/unlink", dest, e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if newmtime:
|
if newmtime:
|
||||||
os.utime(dest,(newmtime,newmtime))
|
os.utime(dest, (newmtime, newmtime))
|
||||||
else:
|
else:
|
||||||
os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
|
os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
|
||||||
newmtime=sstat[stat.ST_MTIME]
|
newmtime = sstat[stat.ST_MTIME]
|
||||||
return newmtime
|
return newmtime
|
||||||
|
|
||||||
def which(path, item, direction = 0):
|
def which(path, item, direction = 0):
|
||||||
@@ -614,3 +744,19 @@ def which(path, item, direction = 0):
|
|||||||
return next
|
return next
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def init_logger(logger, verbose, debug, debug_domains):
|
||||||
|
"""
|
||||||
|
Set verbosity and debug levels in the logger
|
||||||
|
"""
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
logger.set_verbose(True)
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
logger.set_debug_level(debug)
|
||||||
|
else:
|
||||||
|
logger.set_debug_level(0)
|
||||||
|
|
||||||
|
if debug_domains:
|
||||||
|
logger.set_debug_domains(debug_domains)
|
||||||
|
|||||||
570
bitbake/lib/codegen.py
Normal file
@@ -0,0 +1,570 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
codegen
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
Extension to ast that allow ast -> python code generation.
|
||||||
|
|
||||||
|
:copyright: Copyright 2008 by Armin Ronacher.
|
||||||
|
:license: BSD.
|
||||||
|
"""
|
||||||
|
from ast import *
|
||||||
|
|
||||||
|
BOOLOP_SYMBOLS = {
|
||||||
|
And: 'and',
|
||||||
|
Or: 'or'
|
||||||
|
}
|
||||||
|
|
||||||
|
BINOP_SYMBOLS = {
|
||||||
|
Add: '+',
|
||||||
|
Sub: '-',
|
||||||
|
Mult: '*',
|
||||||
|
Div: '/',
|
||||||
|
FloorDiv: '//',
|
||||||
|
Mod: '%',
|
||||||
|
LShift: '<<',
|
||||||
|
RShift: '>>',
|
||||||
|
BitOr: '|',
|
||||||
|
BitAnd: '&',
|
||||||
|
BitXor: '^'
|
||||||
|
}
|
||||||
|
|
||||||
|
CMPOP_SYMBOLS = {
|
||||||
|
Eq: '==',
|
||||||
|
Gt: '>',
|
||||||
|
GtE: '>=',
|
||||||
|
In: 'in',
|
||||||
|
Is: 'is',
|
||||||
|
IsNot: 'is not',
|
||||||
|
Lt: '<',
|
||||||
|
LtE: '<=',
|
||||||
|
NotEq: '!=',
|
||||||
|
NotIn: 'not in'
|
||||||
|
}
|
||||||
|
|
||||||
|
UNARYOP_SYMBOLS = {
|
||||||
|
Invert: '~',
|
||||||
|
Not: 'not',
|
||||||
|
UAdd: '+',
|
||||||
|
USub: '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
ALL_SYMBOLS = {}
|
||||||
|
ALL_SYMBOLS.update(BOOLOP_SYMBOLS)
|
||||||
|
ALL_SYMBOLS.update(BINOP_SYMBOLS)
|
||||||
|
ALL_SYMBOLS.update(CMPOP_SYMBOLS)
|
||||||
|
ALL_SYMBOLS.update(UNARYOP_SYMBOLS)
|
||||||
|
|
||||||
|
def to_source(node, indent_with=' ' * 4, add_line_information=False):
|
||||||
|
"""This function can convert a node tree back into python sourcecode.
|
||||||
|
This is useful for debugging purposes, especially if you're dealing with
|
||||||
|
custom asts not generated by python itself.
|
||||||
|
|
||||||
|
It could be that the sourcecode is evaluable when the AST itself is not
|
||||||
|
compilable / evaluable. The reason for this is that the AST contains some
|
||||||
|
more data than regular sourcecode does, which is dropped during
|
||||||
|
conversion.
|
||||||
|
|
||||||
|
Each level of indentation is replaced with `indent_with`. Per default this
|
||||||
|
parameter is equal to four spaces as suggested by PEP 8, but it might be
|
||||||
|
adjusted to match the application's styleguide.
|
||||||
|
|
||||||
|
If `add_line_information` is set to `True` comments for the line numbers
|
||||||
|
of the nodes are added to the output. This can be used to spot wrong line
|
||||||
|
number information of statement nodes.
|
||||||
|
"""
|
||||||
|
generator = SourceGenerator(indent_with, add_line_information)
|
||||||
|
generator.visit(node)
|
||||||
|
return ''.join(generator.result)
|
||||||
|
|
||||||
|
|
||||||
|
class SourceGenerator(NodeVisitor):
|
||||||
|
"""This visitor is able to transform a well formed syntax tree into python
|
||||||
|
sourcecode. For more details have a look at the docstring of the
|
||||||
|
`node_to_source` function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, indent_with, add_line_information=False):
|
||||||
|
self.result = []
|
||||||
|
self.indent_with = indent_with
|
||||||
|
self.add_line_information = add_line_information
|
||||||
|
self.indentation = 0
|
||||||
|
self.new_lines = 0
|
||||||
|
|
||||||
|
def write(self, x):
|
||||||
|
if self.new_lines:
|
||||||
|
if self.result:
|
||||||
|
self.result.append('\n' * self.new_lines)
|
||||||
|
self.result.append(self.indent_with * self.indentation)
|
||||||
|
self.new_lines = 0
|
||||||
|
self.result.append(x)
|
||||||
|
|
||||||
|
def newline(self, node=None, extra=0):
|
||||||
|
self.new_lines = max(self.new_lines, 1 + extra)
|
||||||
|
if node is not None and self.add_line_information:
|
||||||
|
self.write('# line: %s' % node.lineno)
|
||||||
|
self.new_lines = 1
|
||||||
|
|
||||||
|
def body(self, statements):
|
||||||
|
self.new_line = True
|
||||||
|
self.indentation += 1
|
||||||
|
for stmt in statements:
|
||||||
|
self.visit(stmt)
|
||||||
|
self.indentation -= 1
|
||||||
|
|
||||||
|
def body_or_else(self, node):
|
||||||
|
self.body(node.body)
|
||||||
|
if node.orelse:
|
||||||
|
self.newline()
|
||||||
|
self.write('else:')
|
||||||
|
self.body(node.orelse)
|
||||||
|
|
||||||
|
def signature(self, node):
|
||||||
|
want_comma = []
|
||||||
|
def write_comma():
|
||||||
|
if want_comma:
|
||||||
|
self.write(', ')
|
||||||
|
else:
|
||||||
|
want_comma.append(True)
|
||||||
|
|
||||||
|
padding = [None] * (len(node.args) - len(node.defaults))
|
||||||
|
for arg, default in zip(node.args, padding + node.defaults):
|
||||||
|
write_comma()
|
||||||
|
self.visit(arg)
|
||||||
|
if default is not None:
|
||||||
|
self.write('=')
|
||||||
|
self.visit(default)
|
||||||
|
if node.vararg is not None:
|
||||||
|
write_comma()
|
||||||
|
self.write('*' + node.vararg)
|
||||||
|
if node.kwarg is not None:
|
||||||
|
write_comma()
|
||||||
|
self.write('**' + node.kwarg)
|
||||||
|
|
||||||
|
def decorators(self, node):
|
||||||
|
for decorator in node.decorator_list:
|
||||||
|
self.newline(decorator)
|
||||||
|
self.write('@')
|
||||||
|
self.visit(decorator)
|
||||||
|
|
||||||
|
# Statements
|
||||||
|
|
||||||
|
def visit_Assign(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
for idx, target in enumerate(node.targets):
|
||||||
|
if idx:
|
||||||
|
self.write(', ')
|
||||||
|
self.visit(target)
|
||||||
|
self.write(' = ')
|
||||||
|
self.visit(node.value)
|
||||||
|
|
||||||
|
def visit_AugAssign(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.visit(node.target)
|
||||||
|
self.write(BINOP_SYMBOLS[type(node.op)] + '=')
|
||||||
|
self.visit(node.value)
|
||||||
|
|
||||||
|
def visit_ImportFrom(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('from %s%s import ' % ('.' * node.level, node.module))
|
||||||
|
for idx, item in enumerate(node.names):
|
||||||
|
if idx:
|
||||||
|
self.write(', ')
|
||||||
|
self.write(item)
|
||||||
|
|
||||||
|
def visit_Import(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
for item in node.names:
|
||||||
|
self.write('import ')
|
||||||
|
self.visit(item)
|
||||||
|
|
||||||
|
def visit_Expr(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.generic_visit(node)
|
||||||
|
|
||||||
|
def visit_FunctionDef(self, node):
|
||||||
|
self.newline(extra=1)
|
||||||
|
self.decorators(node)
|
||||||
|
self.newline(node)
|
||||||
|
self.write('def %s(' % node.name)
|
||||||
|
self.signature(node.args)
|
||||||
|
self.write('):')
|
||||||
|
self.body(node.body)
|
||||||
|
|
||||||
|
def visit_ClassDef(self, node):
|
||||||
|
have_args = []
|
||||||
|
def paren_or_comma():
|
||||||
|
if have_args:
|
||||||
|
self.write(', ')
|
||||||
|
else:
|
||||||
|
have_args.append(True)
|
||||||
|
self.write('(')
|
||||||
|
|
||||||
|
self.newline(extra=2)
|
||||||
|
self.decorators(node)
|
||||||
|
self.newline(node)
|
||||||
|
self.write('class %s' % node.name)
|
||||||
|
for base in node.bases:
|
||||||
|
paren_or_comma()
|
||||||
|
self.visit(base)
|
||||||
|
# XXX: the if here is used to keep this module compatible
|
||||||
|
# with python 2.6.
|
||||||
|
if hasattr(node, 'keywords'):
|
||||||
|
for keyword in node.keywords:
|
||||||
|
paren_or_comma()
|
||||||
|
self.write(keyword.arg + '=')
|
||||||
|
self.visit(keyword.value)
|
||||||
|
if node.starargs is not None:
|
||||||
|
paren_or_comma()
|
||||||
|
self.write('*')
|
||||||
|
self.visit(node.starargs)
|
||||||
|
if node.kwargs is not None:
|
||||||
|
paren_or_comma()
|
||||||
|
self.write('**')
|
||||||
|
self.visit(node.kwargs)
|
||||||
|
self.write(have_args and '):' or ':')
|
||||||
|
self.body(node.body)
|
||||||
|
|
||||||
|
def visit_If(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('if ')
|
||||||
|
self.visit(node.test)
|
||||||
|
self.write(':')
|
||||||
|
self.body(node.body)
|
||||||
|
while True:
|
||||||
|
else_ = node.orelse
|
||||||
|
if len(else_) == 1 and isinstance(else_[0], If):
|
||||||
|
node = else_[0]
|
||||||
|
self.newline()
|
||||||
|
self.write('elif ')
|
||||||
|
self.visit(node.test)
|
||||||
|
self.write(':')
|
||||||
|
self.body(node.body)
|
||||||
|
else:
|
||||||
|
self.newline()
|
||||||
|
self.write('else:')
|
||||||
|
self.body(else_)
|
||||||
|
break
|
||||||
|
|
||||||
|
def visit_For(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('for ')
|
||||||
|
self.visit(node.target)
|
||||||
|
self.write(' in ')
|
||||||
|
self.visit(node.iter)
|
||||||
|
self.write(':')
|
||||||
|
self.body_or_else(node)
|
||||||
|
|
||||||
|
def visit_While(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('while ')
|
||||||
|
self.visit(node.test)
|
||||||
|
self.write(':')
|
||||||
|
self.body_or_else(node)
|
||||||
|
|
||||||
|
def visit_With(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('with ')
|
||||||
|
self.visit(node.context_expr)
|
||||||
|
if node.optional_vars is not None:
|
||||||
|
self.write(' as ')
|
||||||
|
self.visit(node.optional_vars)
|
||||||
|
self.write(':')
|
||||||
|
self.body(node.body)
|
||||||
|
|
||||||
|
def visit_Pass(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('pass')
|
||||||
|
|
||||||
|
def visit_Print(self, node):
|
||||||
|
# XXX: python 2.6 only
|
||||||
|
self.newline(node)
|
||||||
|
self.write('print ')
|
||||||
|
want_comma = False
|
||||||
|
if node.dest is not None:
|
||||||
|
self.write(' >> ')
|
||||||
|
self.visit(node.dest)
|
||||||
|
want_comma = True
|
||||||
|
for value in node.values:
|
||||||
|
if want_comma:
|
||||||
|
self.write(', ')
|
||||||
|
self.visit(value)
|
||||||
|
want_comma = True
|
||||||
|
if not node.nl:
|
||||||
|
self.write(',')
|
||||||
|
|
||||||
|
def visit_Delete(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('del ')
|
||||||
|
for idx, target in enumerate(node):
|
||||||
|
if idx:
|
||||||
|
self.write(', ')
|
||||||
|
self.visit(target)
|
||||||
|
|
||||||
|
def visit_TryExcept(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('try:')
|
||||||
|
self.body(node.body)
|
||||||
|
for handler in node.handlers:
|
||||||
|
self.visit(handler)
|
||||||
|
|
||||||
|
def visit_TryFinally(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('try:')
|
||||||
|
self.body(node.body)
|
||||||
|
self.newline(node)
|
||||||
|
self.write('finally:')
|
||||||
|
self.body(node.finalbody)
|
||||||
|
|
||||||
|
def visit_Global(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('global ' + ', '.join(node.names))
|
||||||
|
|
||||||
|
def visit_Nonlocal(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('nonlocal ' + ', '.join(node.names))
|
||||||
|
|
||||||
|
def visit_Return(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('return ')
|
||||||
|
self.visit(node.value)
|
||||||
|
|
||||||
|
def visit_Break(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('break')
|
||||||
|
|
||||||
|
def visit_Continue(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('continue')
|
||||||
|
|
||||||
|
def visit_Raise(self, node):
|
||||||
|
# XXX: Python 2.6 / 3.0 compatibility
|
||||||
|
self.newline(node)
|
||||||
|
self.write('raise')
|
||||||
|
if hasattr(node, 'exc') and node.exc is not None:
|
||||||
|
self.write(' ')
|
||||||
|
self.visit(node.exc)
|
||||||
|
if node.cause is not None:
|
||||||
|
self.write(' from ')
|
||||||
|
self.visit(node.cause)
|
||||||
|
elif hasattr(node, 'type') and node.type is not None:
|
||||||
|
self.visit(node.type)
|
||||||
|
if node.inst is not None:
|
||||||
|
self.write(', ')
|
||||||
|
self.visit(node.inst)
|
||||||
|
if node.tback is not None:
|
||||||
|
self.write(', ')
|
||||||
|
self.visit(node.tback)
|
||||||
|
|
||||||
|
# Expressions
|
||||||
|
|
||||||
|
def visit_Attribute(self, node):
|
||||||
|
self.visit(node.value)
|
||||||
|
self.write('.' + node.attr)
|
||||||
|
|
||||||
|
def visit_Call(self, node):
|
||||||
|
want_comma = []
|
||||||
|
def write_comma():
|
||||||
|
if want_comma:
|
||||||
|
self.write(', ')
|
||||||
|
else:
|
||||||
|
want_comma.append(True)
|
||||||
|
|
||||||
|
self.visit(node.func)
|
||||||
|
self.write('(')
|
||||||
|
for arg in node.args:
|
||||||
|
write_comma()
|
||||||
|
self.visit(arg)
|
||||||
|
for keyword in node.keywords:
|
||||||
|
write_comma()
|
||||||
|
self.write(keyword.arg + '=')
|
||||||
|
self.visit(keyword.value)
|
||||||
|
if node.starargs is not None:
|
||||||
|
write_comma()
|
||||||
|
self.write('*')
|
||||||
|
self.visit(node.starargs)
|
||||||
|
if node.kwargs is not None:
|
||||||
|
write_comma()
|
||||||
|
self.write('**')
|
||||||
|
self.visit(node.kwargs)
|
||||||
|
self.write(')')
|
||||||
|
|
||||||
|
def visit_Name(self, node):
|
||||||
|
self.write(node.id)
|
||||||
|
|
||||||
|
def visit_Str(self, node):
|
||||||
|
self.write(repr(node.s))
|
||||||
|
|
||||||
|
def visit_Bytes(self, node):
|
||||||
|
self.write(repr(node.s))
|
||||||
|
|
||||||
|
def visit_Num(self, node):
|
||||||
|
self.write(repr(node.n))
|
||||||
|
|
||||||
|
def visit_Tuple(self, node):
|
||||||
|
self.write('(')
|
||||||
|
idx = -1
|
||||||
|
for idx, item in enumerate(node.elts):
|
||||||
|
if idx:
|
||||||
|
self.write(', ')
|
||||||
|
self.visit(item)
|
||||||
|
self.write(idx and ')' or ',)')
|
||||||
|
|
||||||
|
def sequence_visit(left, right):
|
||||||
|
def visit(self, node):
|
||||||
|
self.write(left)
|
||||||
|
for idx, item in enumerate(node.elts):
|
||||||
|
if idx:
|
||||||
|
self.write(', ')
|
||||||
|
self.visit(item)
|
||||||
|
self.write(right)
|
||||||
|
return visit
|
||||||
|
|
||||||
|
visit_List = sequence_visit('[', ']')
|
||||||
|
visit_Set = sequence_visit('{', '}')
|
||||||
|
del sequence_visit
|
||||||
|
|
||||||
|
def visit_Dict(self, node):
|
||||||
|
self.write('{')
|
||||||
|
for idx, (key, value) in enumerate(zip(node.keys, node.values)):
|
||||||
|
if idx:
|
||||||
|
self.write(', ')
|
||||||
|
self.visit(key)
|
||||||
|
self.write(': ')
|
||||||
|
self.visit(value)
|
||||||
|
self.write('}')
|
||||||
|
|
||||||
|
def visit_BinOp(self, node):
|
||||||
|
self.visit(node.left)
|
||||||
|
self.write(' %s ' % BINOP_SYMBOLS[type(node.op)])
|
||||||
|
self.visit(node.right)
|
||||||
|
|
||||||
|
def visit_BoolOp(self, node):
|
||||||
|
self.write('(')
|
||||||
|
for idx, value in enumerate(node.values):
|
||||||
|
if idx:
|
||||||
|
self.write(' %s ' % BOOLOP_SYMBOLS[type(node.op)])
|
||||||
|
self.visit(value)
|
||||||
|
self.write(')')
|
||||||
|
|
||||||
|
def visit_Compare(self, node):
|
||||||
|
self.write('(')
|
||||||
|
self.write(node.left)
|
||||||
|
for op, right in zip(node.ops, node.comparators):
|
||||||
|
self.write(' %s %%' % CMPOP_SYMBOLS[type(op)])
|
||||||
|
self.visit(right)
|
||||||
|
self.write(')')
|
||||||
|
|
||||||
|
def visit_UnaryOp(self, node):
|
||||||
|
self.write('(')
|
||||||
|
op = UNARYOP_SYMBOLS[type(node.op)]
|
||||||
|
self.write(op)
|
||||||
|
if op == 'not':
|
||||||
|
self.write(' ')
|
||||||
|
self.visit(node.operand)
|
||||||
|
self.write(')')
|
||||||
|
|
||||||
|
def visit_Subscript(self, node):
|
||||||
|
self.visit(node.value)
|
||||||
|
self.write('[')
|
||||||
|
self.visit(node.slice)
|
||||||
|
self.write(']')
|
||||||
|
|
||||||
|
def visit_Slice(self, node):
|
||||||
|
if node.lower is not None:
|
||||||
|
self.visit(node.lower)
|
||||||
|
self.write(':')
|
||||||
|
if node.upper is not None:
|
||||||
|
self.visit(node.upper)
|
||||||
|
if node.step is not None:
|
||||||
|
self.write(':')
|
||||||
|
if not (isinstance(node.step, Name) and node.step.id == 'None'):
|
||||||
|
self.visit(node.step)
|
||||||
|
|
||||||
|
def visit_ExtSlice(self, node):
|
||||||
|
for idx, item in node.dims:
|
||||||
|
if idx:
|
||||||
|
self.write(', ')
|
||||||
|
self.visit(item)
|
||||||
|
|
||||||
|
def visit_Yield(self, node):
|
||||||
|
self.write('yield ')
|
||||||
|
self.visit(node.value)
|
||||||
|
|
||||||
|
def visit_Lambda(self, node):
|
||||||
|
self.write('lambda ')
|
||||||
|
self.signature(node.args)
|
||||||
|
self.write(': ')
|
||||||
|
self.visit(node.body)
|
||||||
|
|
||||||
|
def visit_Ellipsis(self, node):
|
||||||
|
self.write('Ellipsis')
|
||||||
|
|
||||||
|
def generator_visit(left, right):
|
||||||
|
def visit(self, node):
|
||||||
|
self.write(left)
|
||||||
|
self.visit(node.elt)
|
||||||
|
for comprehension in node.generators:
|
||||||
|
self.visit(comprehension)
|
||||||
|
self.write(right)
|
||||||
|
return visit
|
||||||
|
|
||||||
|
visit_ListComp = generator_visit('[', ']')
|
||||||
|
visit_GeneratorExp = generator_visit('(', ')')
|
||||||
|
visit_SetComp = generator_visit('{', '}')
|
||||||
|
del generator_visit
|
||||||
|
|
||||||
|
def visit_DictComp(self, node):
|
||||||
|
self.write('{')
|
||||||
|
self.visit(node.key)
|
||||||
|
self.write(': ')
|
||||||
|
self.visit(node.value)
|
||||||
|
for comprehension in node.generators:
|
||||||
|
self.visit(comprehension)
|
||||||
|
self.write('}')
|
||||||
|
|
||||||
|
def visit_IfExp(self, node):
|
||||||
|
self.visit(node.body)
|
||||||
|
self.write(' if ')
|
||||||
|
self.visit(node.test)
|
||||||
|
self.write(' else ')
|
||||||
|
self.visit(node.orelse)
|
||||||
|
|
||||||
|
def visit_Starred(self, node):
|
||||||
|
self.write('*')
|
||||||
|
self.visit(node.value)
|
||||||
|
|
||||||
|
def visit_Repr(self, node):
|
||||||
|
# XXX: python 2.6 only
|
||||||
|
self.write('`')
|
||||||
|
self.visit(node.value)
|
||||||
|
self.write('`')
|
||||||
|
|
||||||
|
# Helper Nodes
|
||||||
|
|
||||||
|
def visit_alias(self, node):
|
||||||
|
self.write(node.name)
|
||||||
|
if node.asname is not None:
|
||||||
|
self.write(' as ' + node.asname)
|
||||||
|
|
||||||
|
def visit_comprehension(self, node):
|
||||||
|
self.write(' for ')
|
||||||
|
self.visit(node.target)
|
||||||
|
self.write(' in ')
|
||||||
|
self.visit(node.iter)
|
||||||
|
if node.ifs:
|
||||||
|
for if_ in node.ifs:
|
||||||
|
self.write(' if ')
|
||||||
|
self.visit(if_)
|
||||||
|
|
||||||
|
def visit_excepthandler(self, node):
|
||||||
|
self.newline(node)
|
||||||
|
self.write('except')
|
||||||
|
if node.type is not None:
|
||||||
|
self.write(' ')
|
||||||
|
self.visit(node.type)
|
||||||
|
if node.name is not None:
|
||||||
|
self.write(' as ')
|
||||||
|
self.visit(node.name)
|
||||||
|
self.write(':')
|
||||||
|
self.body(node.body)
|
||||||
4
bitbake/lib/ply/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# PLY package
|
||||||
|
# Author: David Beazley (dave@dabeaz.com)
|
||||||
|
|
||||||
|
__all__ = ['lex','yacc']
|
||||||
1058
bitbake/lib/ply/lex.py
Normal file
3276
bitbake/lib/ply/yacc.py
Normal file
710
bitbake/lib/pysh/builtin.py
Normal file
@@ -0,0 +1,710 @@
|
|||||||
|
# builtin.py - builtins and utilities definitions for pysh.
|
||||||
|
#
|
||||||
|
# Copyright 2007 Patrick Mezard
|
||||||
|
#
|
||||||
|
# This software may be used and distributed according to the terms
|
||||||
|
# of the GNU General Public License, incorporated herein by reference.
|
||||||
|
|
||||||
|
"""Builtin and internal utilities implementations.
|
||||||
|
|
||||||
|
- Beware not to use python interpreter environment as if it were the shell
|
||||||
|
environment. For instance, commands working directory must be explicitely handled
|
||||||
|
through env['PWD'] instead of relying on python working directory.
|
||||||
|
"""
|
||||||
|
import errno
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
def has_subprocess_bug():
|
||||||
|
return getattr(subprocess, 'list2cmdline') and \
|
||||||
|
( subprocess.list2cmdline(['']) == '' or \
|
||||||
|
subprocess.list2cmdline(['foo|bar']) == 'foo|bar')
|
||||||
|
|
||||||
|
# Detect python bug 1634343: "subprocess swallows empty arguments under win32"
|
||||||
|
# <http://sourceforge.net/tracker/index.php?func=detail&aid=1634343&group_id=5470&atid=105470>
|
||||||
|
# Also detect: "[ 1710802 ] subprocess must escape redirection characters under win32"
|
||||||
|
# <http://sourceforge.net/tracker/index.php?func=detail&aid=1710802&group_id=5470&atid=105470>
|
||||||
|
if has_subprocess_bug():
|
||||||
|
import subprocess_fix
|
||||||
|
subprocess.list2cmdline = subprocess_fix.list2cmdline
|
||||||
|
|
||||||
|
from sherrors import *
|
||||||
|
|
||||||
|
class NonExitingParser(optparse.OptionParser):
|
||||||
|
"""OptionParser default behaviour upon error is to print the error message and
|
||||||
|
exit. Raise a utility error instead.
|
||||||
|
"""
|
||||||
|
def error(self, msg):
|
||||||
|
raise UtilityError(msg)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# set special builtin
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
OPT_SET = NonExitingParser(usage="set - set or unset options and positional parameters")
|
||||||
|
OPT_SET.add_option( '-f', action='store_true', dest='has_f', default=False,
|
||||||
|
help='The shell shall disable pathname expansion.')
|
||||||
|
OPT_SET.add_option('-e', action='store_true', dest='has_e', default=False,
|
||||||
|
help="""When this option is on, if a simple command fails for any of the \
|
||||||
|
reasons listed in Consequences of Shell Errors or returns an exit status \
|
||||||
|
value >0, and is not part of the compound list following a while, until, \
|
||||||
|
or if keyword, and is not a part of an AND or OR list, and is not a \
|
||||||
|
pipeline preceded by the ! reserved word, then the shell shall immediately \
|
||||||
|
exit.""")
|
||||||
|
OPT_SET.add_option('-x', action='store_true', dest='has_x', default=False,
|
||||||
|
help="""The shell shall write to standard error a trace for each command \
|
||||||
|
after it expands the command and before it executes it. It is unspecified \
|
||||||
|
whether the command that turns tracing off is traced.""")
|
||||||
|
|
||||||
|
def builtin_set(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
option, args = OPT_SET.parse_args(args)
|
||||||
|
env = interp.get_env()
|
||||||
|
|
||||||
|
if option.has_f:
|
||||||
|
env.set_opt('-f')
|
||||||
|
if option.has_e:
|
||||||
|
env.set_opt('-e')
|
||||||
|
if option.has_x:
|
||||||
|
env.set_opt('-x')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# shift special builtin
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def builtin_shift(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
params = interp.get_env().get_positional_args()
|
||||||
|
if args:
|
||||||
|
try:
|
||||||
|
n = int(args[0])
|
||||||
|
if n > len(params):
|
||||||
|
raise ValueError()
|
||||||
|
except ValueError:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
n = 1
|
||||||
|
|
||||||
|
params[:n] = []
|
||||||
|
interp.get_env().set_positional_args(params)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# export special builtin
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
OPT_EXPORT = NonExitingParser(usage="set - set or unset options and positional parameters")
|
||||||
|
OPT_EXPORT.add_option('-p', action='store_true', dest='has_p', default=False)
|
||||||
|
|
||||||
|
def builtin_export(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
option, args = OPT_EXPORT.parse_args(args)
|
||||||
|
if option.has_p:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
for arg in args:
|
||||||
|
try:
|
||||||
|
name, value = arg.split('=', 1)
|
||||||
|
except ValueError:
|
||||||
|
name, value = arg, None
|
||||||
|
env = interp.get_env().export(name, value)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# return special builtin
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def builtin_return(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
res = 0
|
||||||
|
if args:
|
||||||
|
try:
|
||||||
|
res = int(args[0])
|
||||||
|
except ValueError:
|
||||||
|
res = 0
|
||||||
|
if not 0<=res<=255:
|
||||||
|
res = 0
|
||||||
|
|
||||||
|
# BUG: should be last executed command exit code
|
||||||
|
raise ReturnSignal(res)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# trap special builtin
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def builtin_trap(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
if len(args) < 2:
|
||||||
|
stderr.write('trap: usage: trap [[arg] signal_spec ...]\n')
|
||||||
|
return 2
|
||||||
|
|
||||||
|
action = args[0]
|
||||||
|
for sig in args[1:]:
|
||||||
|
try:
|
||||||
|
env.traps[sig] = action
|
||||||
|
except Exception, e:
|
||||||
|
stderr.write('trap: %s\n' % str(e))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# unset special builtin
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
OPT_UNSET = NonExitingParser("unset - unset values and attributes of variables and functions")
|
||||||
|
OPT_UNSET.add_option( '-f', action='store_true', dest='has_f', default=False)
|
||||||
|
OPT_UNSET.add_option( '-v', action='store_true', dest='has_v', default=False)
|
||||||
|
|
||||||
|
def builtin_unset(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
option, args = OPT_UNSET.parse_args(args)
|
||||||
|
|
||||||
|
status = 0
|
||||||
|
env = interp.get_env()
|
||||||
|
for arg in args:
|
||||||
|
try:
|
||||||
|
if option.has_f:
|
||||||
|
env.remove_function(arg)
|
||||||
|
else:
|
||||||
|
del env[arg]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
except VarAssignmentError:
|
||||||
|
status = 1
|
||||||
|
|
||||||
|
return status
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# wait special builtin
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def builtin_wait(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
return interp.wait([int(arg) for arg in args])
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# cat utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def utility_cat(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
if not args:
|
||||||
|
args = ['-']
|
||||||
|
|
||||||
|
status = 0
|
||||||
|
for arg in args:
|
||||||
|
if arg == '-':
|
||||||
|
data = stdin.read()
|
||||||
|
else:
|
||||||
|
path = os.path.join(env['PWD'], arg)
|
||||||
|
try:
|
||||||
|
f = file(path, 'rb')
|
||||||
|
try:
|
||||||
|
data = f.read()
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
except IOError, e:
|
||||||
|
if e.errno != errno.ENOENT:
|
||||||
|
raise
|
||||||
|
status = 1
|
||||||
|
continue
|
||||||
|
stdout.write(data)
|
||||||
|
stdout.flush()
|
||||||
|
return status
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# cd utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
OPT_CD = NonExitingParser("cd - change the working directory")
|
||||||
|
|
||||||
|
def utility_cd(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
option, args = OPT_CD.parse_args(args)
|
||||||
|
env = interp.get_env()
|
||||||
|
|
||||||
|
directory = None
|
||||||
|
printdir = False
|
||||||
|
if not args:
|
||||||
|
home = env.get('HOME')
|
||||||
|
if home:
|
||||||
|
# Unspecified, do nothing
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
directory = home
|
||||||
|
elif len(args)==1:
|
||||||
|
directory = args[0]
|
||||||
|
if directory=='-':
|
||||||
|
if 'OLDPWD' not in env:
|
||||||
|
raise UtilityError("OLDPWD not set")
|
||||||
|
printdir = True
|
||||||
|
directory = env['OLDPWD']
|
||||||
|
else:
|
||||||
|
raise UtilityError("too many arguments")
|
||||||
|
|
||||||
|
curpath = None
|
||||||
|
# Absolute directories will be handled correctly by the os.path.join call.
|
||||||
|
if not directory.startswith('.') and not directory.startswith('..'):
|
||||||
|
cdpaths = env.get('CDPATH', '.').split(';')
|
||||||
|
for cdpath in cdpaths:
|
||||||
|
p = os.path.join(cdpath, directory)
|
||||||
|
if os.path.isdir(p):
|
||||||
|
curpath = p
|
||||||
|
break
|
||||||
|
|
||||||
|
if curpath is None:
|
||||||
|
curpath = directory
|
||||||
|
curpath = os.path.join(env['PWD'], directory)
|
||||||
|
|
||||||
|
env['OLDPWD'] = env['PWD']
|
||||||
|
env['PWD'] = curpath
|
||||||
|
if printdir:
|
||||||
|
stdout.write('%s\n' % curpath)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# colon utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def utility_colon(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# echo utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def utility_echo(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
# Echo only takes arguments, no options. Use printf if you need fancy stuff.
|
||||||
|
output = ' '.join(args) + '\n'
|
||||||
|
stdout.write(output)
|
||||||
|
stdout.flush()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# egrep utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# egrep is usually a shell script.
|
||||||
|
# Unfortunately, pysh does not support shell scripts *with arguments* right now,
|
||||||
|
# so the redirection is implemented here, assuming grep is available.
|
||||||
|
def utility_egrep(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
return run_command('grep', ['-E'] + args, interp, env, stdin, stdout,
|
||||||
|
stderr, debugflags)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# env utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def utility_env(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
if args and args[0]=='-i':
|
||||||
|
raise NotImplementedError('env: -i option is not implemented')
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
for arg in args:
|
||||||
|
if '=' not in arg:
|
||||||
|
break
|
||||||
|
# Update the current environment
|
||||||
|
name, value = arg.split('=', 1)
|
||||||
|
env[name] = value
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if args[i:]:
|
||||||
|
# Find then execute the specified interpreter
|
||||||
|
utility = env.find_in_path(args[i])
|
||||||
|
if not utility:
|
||||||
|
return 127
|
||||||
|
args[i:i+1] = utility
|
||||||
|
name = args[i]
|
||||||
|
args = args[i+1:]
|
||||||
|
try:
|
||||||
|
return run_command(name, args, interp, env, stdin, stdout, stderr,
|
||||||
|
debugflags)
|
||||||
|
except UtilityError:
|
||||||
|
stderr.write('env: failed to execute %s' % ' '.join([name]+args))
|
||||||
|
return 126
|
||||||
|
else:
|
||||||
|
for pair in env.get_variables().iteritems():
|
||||||
|
stdout.write('%s=%s\n' % pair)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# exit utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def utility_exit(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
res = None
|
||||||
|
if args:
|
||||||
|
try:
|
||||||
|
res = int(args[0])
|
||||||
|
except ValueError:
|
||||||
|
res = None
|
||||||
|
if not 0<=res<=255:
|
||||||
|
res = None
|
||||||
|
|
||||||
|
if res is None:
|
||||||
|
# BUG: should be last executed command exit code
|
||||||
|
res = 0
|
||||||
|
|
||||||
|
raise ExitSignal(res)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# fgrep utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# see egrep
|
||||||
|
def utility_fgrep(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
return run_command('grep', ['-F'] + args, interp, env, stdin, stdout,
|
||||||
|
stderr, debugflags)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# gunzip utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# see egrep
|
||||||
|
def utility_gunzip(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
return run_command('gzip', ['-d'] + args, interp, env, stdin, stdout,
|
||||||
|
stderr, debugflags)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# kill utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def utility_kill(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
for arg in args:
|
||||||
|
pid = int(arg)
|
||||||
|
status = subprocess.call(['pskill', '/T', str(pid)],
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
# pskill is asynchronous, hence the stupid polling loop
|
||||||
|
while 1:
|
||||||
|
p = subprocess.Popen(['pslist', str(pid)],
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
output = p.communicate()[0]
|
||||||
|
if ('process %d was not' % pid) in output:
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
return status
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# mkdir utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
OPT_MKDIR = NonExitingParser("mkdir - make directories.")
|
||||||
|
OPT_MKDIR.add_option('-p', action='store_true', dest='has_p', default=False)
|
||||||
|
|
||||||
|
def utility_mkdir(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
# TODO: implement umask
|
||||||
|
# TODO: implement proper utility error report
|
||||||
|
option, args = OPT_MKDIR.parse_args(args)
|
||||||
|
for arg in args:
|
||||||
|
path = os.path.join(env['PWD'], arg)
|
||||||
|
if option.has_p:
|
||||||
|
try:
|
||||||
|
os.makedirs(path)
|
||||||
|
except IOError, e:
|
||||||
|
if e.errno != errno.EEXIST:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
os.mkdir(path)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# netstat utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def utility_netstat(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
# Do you really expect me to implement netstat ?
|
||||||
|
# This empty form is enough for Mercurial tests since it's
|
||||||
|
# supposed to generate nothing upon success. Faking this test
|
||||||
|
# is not a big deal either.
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# pwd utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
OPT_PWD = NonExitingParser("pwd - return working directory name")
|
||||||
|
OPT_PWD.add_option('-L', action='store_true', dest='has_L', default=True,
|
||||||
|
help="""If the PWD environment variable contains an absolute pathname of \
|
||||||
|
the current directory that does not contain the filenames dot or dot-dot, \
|
||||||
|
pwd shall write this pathname to standard output. Otherwise, the -L option \
|
||||||
|
shall behave as the -P option.""")
|
||||||
|
OPT_PWD.add_option('-P', action='store_true', dest='has_L', default=False,
|
||||||
|
help="""The absolute pathname written shall not contain filenames that, in \
|
||||||
|
the context of the pathname, refer to files of type symbolic link.""")
|
||||||
|
|
||||||
|
def utility_pwd(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
option, args = OPT_PWD.parse_args(args)
|
||||||
|
stdout.write('%s\n' % env['PWD'])
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# printf utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
RE_UNESCAPE = re.compile(r'(\\x[a-zA-Z0-9]{2}|\\[0-7]{1,3}|\\.)')
|
||||||
|
|
||||||
|
def utility_printf(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
def replace(m):
|
||||||
|
assert m.group()
|
||||||
|
g = m.group()[1:]
|
||||||
|
if g.startswith('x'):
|
||||||
|
return chr(int(g[1:], 16))
|
||||||
|
if len(g) <= 3 and len([c for c in g if c in '01234567']) == len(g):
|
||||||
|
# Yay, an octal number
|
||||||
|
return chr(int(g, 8))
|
||||||
|
return {
|
||||||
|
'a': '\a',
|
||||||
|
'b': '\b',
|
||||||
|
'f': '\f',
|
||||||
|
'n': '\n',
|
||||||
|
'r': '\r',
|
||||||
|
't': '\t',
|
||||||
|
'v': '\v',
|
||||||
|
'\\': '\\',
|
||||||
|
}.get(g)
|
||||||
|
|
||||||
|
# Convert escape sequences
|
||||||
|
format = re.sub(RE_UNESCAPE, replace, args[0])
|
||||||
|
stdout.write(format % tuple(args[1:]))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# true utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def utility_true(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# sed utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
RE_SED = re.compile(r'^s(.).*\1[a-zA-Z]*$')
|
||||||
|
|
||||||
|
# cygwin sed fails with some expressions when they do not end with a single space.
|
||||||
|
# see unit tests for details. Interestingly, the same expressions works perfectly
|
||||||
|
# in cygwin shell.
|
||||||
|
def utility_sed(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
# Scan pattern arguments and append a space if necessary
|
||||||
|
for i in xrange(len(args)):
|
||||||
|
if not RE_SED.search(args[i]):
|
||||||
|
continue
|
||||||
|
args[i] = args[i] + ' '
|
||||||
|
|
||||||
|
return run_command(name, args, interp, env, stdin, stdout,
|
||||||
|
stderr, debugflags)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# sleep utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
def utility_sleep(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
time.sleep(int(args[0]))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# sort utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
OPT_SORT = NonExitingParser("sort - sort, merge, or sequence check text files")
|
||||||
|
|
||||||
|
def utility_sort(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||||
|
|
||||||
|
def sort(path):
|
||||||
|
if path == '-':
|
||||||
|
lines = stdin.readlines()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
f = file(path)
|
||||||
|
try:
|
||||||
|
lines = f.readlines()
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
except IOError, e:
|
||||||
|
stderr.write(str(e) + '\n')
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if lines and lines[-1][-1]!='\n':
|
||||||
|
lines[-1] = lines[-1] + '\n'
|
||||||
|
return lines
|
||||||
|
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
option, args = OPT_SORT.parse_args(args)
|
||||||
|
alllines = []
|
||||||
|
|
||||||
|
if len(args)<=0:
|
||||||
|
args += ['-']
|
||||||
|
|
||||||
|
# Load all files lines
|
||||||
|
curdir = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir(env['PWD'])
|
||||||
|
for path in args:
|
||||||
|
alllines += sort(path)
|
||||||
|
finally:
|
||||||
|
os.chdir(curdir)
|
||||||
|
|
||||||
|
alllines.sort()
|
||||||
|
for line in alllines:
|
||||||
|
stdout.write(line)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# hg utility
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
hgcommands = [
|
||||||
|
'add',
|
||||||
|
'addremove',
|
||||||
|
'commit', 'ci',
|
||||||
|
'debugrename',
|
||||||
|
'debugwalk',
|
||||||
|
'falabala', # Dummy command used in a mercurial test
|
||||||
|
'incoming',
|
||||||
|
'locate',
|
||||||
|
'pull',
|
||||||
|
'push',
|
||||||
|
'qinit',
|
||||||
|
'remove', 'rm',
|
||||||
|
'rename', 'mv',
|
||||||
|
'revert',
|
||||||
|
'showconfig',
|
||||||
|
'status', 'st',
|
||||||
|
'strip',
|
||||||
|
]
|
||||||
|
|
||||||
|
def rewriteslashes(name, args):
|
||||||
|
# Several hg commands output file paths, rewrite the separators
|
||||||
|
if len(args) > 1 and name.lower().endswith('python') \
|
||||||
|
and args[0].endswith('hg'):
|
||||||
|
for cmd in hgcommands:
|
||||||
|
if cmd in args[1:]:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# svn output contains many paths with OS specific separators.
|
||||||
|
# Normalize these to unix paths.
|
||||||
|
base = os.path.basename(name)
|
||||||
|
if base.startswith('svn'):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def rewritehg(output):
|
||||||
|
if not output:
|
||||||
|
return output
|
||||||
|
# Rewrite os specific messages
|
||||||
|
output = output.replace(': The system cannot find the file specified',
|
||||||
|
': No such file or directory')
|
||||||
|
output = re.sub(': Access is denied.*$', ': Permission denied', output)
|
||||||
|
output = output.replace(': No connection could be made because the target machine actively refused it',
|
||||||
|
': Connection refused')
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(name, args, interp, env, stdin, stdout,
|
||||||
|
stderr, debugflags):
|
||||||
|
# Execute the command
|
||||||
|
if 'debug-utility' in debugflags:
|
||||||
|
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||||
|
|
||||||
|
hgbin = interp.options().hgbinary
|
||||||
|
ishg = hgbin and ('hg' in name or args and 'hg' in args[0])
|
||||||
|
unixoutput = 'cygwin' in name or ishg
|
||||||
|
|
||||||
|
exec_env = env.get_variables()
|
||||||
|
try:
|
||||||
|
# BUG: comparing file descriptor is clearly not a reliable way to tell
|
||||||
|
# whether they point on the same underlying object. But in pysh limited
|
||||||
|
# scope this is usually right, we do not expect complicated redirections
|
||||||
|
# besides usual 2>&1.
|
||||||
|
# Still there is one case we have but cannot deal with is when stdout
|
||||||
|
# and stderr are redirected *by pysh caller*. This the reason for the
|
||||||
|
# --redirect pysh() option.
|
||||||
|
# Now, we want to know they are the same because we sometimes need to
|
||||||
|
# transform the command output, mostly remove CR-LF to ensure that
|
||||||
|
# command output is unix-like. Cygwin utilies are a special case because
|
||||||
|
# they explicitely set their output streams to binary mode, so we have
|
||||||
|
# nothing to do. For all others commands, we have to guess whether they
|
||||||
|
# are sending text data, in which case the transformation must be done.
|
||||||
|
# Again, the NUL character test is unreliable but should be enough for
|
||||||
|
# hg tests.
|
||||||
|
redirected = stdout.fileno()==stderr.fileno()
|
||||||
|
if not redirected:
|
||||||
|
p = subprocess.Popen([name] + args, cwd=env['PWD'], env=exec_env,
|
||||||
|
stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
else:
|
||||||
|
p = subprocess.Popen([name] + args, cwd=env['PWD'], env=exec_env,
|
||||||
|
stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
out, err = p.communicate()
|
||||||
|
except WindowsError, e:
|
||||||
|
raise UtilityError(str(e))
|
||||||
|
|
||||||
|
if not unixoutput:
|
||||||
|
def encode(s):
|
||||||
|
if '\0' in s:
|
||||||
|
return s
|
||||||
|
return s.replace('\r\n', '\n')
|
||||||
|
else:
|
||||||
|
encode = lambda s: s
|
||||||
|
|
||||||
|
if rewriteslashes(name, args):
|
||||||
|
encode1_ = encode
|
||||||
|
def encode(s):
|
||||||
|
s = encode1_(s)
|
||||||
|
s = s.replace('\\\\', '\\')
|
||||||
|
s = s.replace('\\', '/')
|
||||||
|
return s
|
||||||
|
|
||||||
|
if ishg:
|
||||||
|
encode2_ = encode
|
||||||
|
def encode(s):
|
||||||
|
return rewritehg(encode2_(s))
|
||||||
|
|
||||||
|
stdout.write(encode(out))
|
||||||
|
if not redirected:
|
||||||
|
stderr.write(encode(err))
|
||||||
|
return p.returncode
|
||||||
|
|
||||||
1367
bitbake/lib/pysh/interp.py
Normal file
116
bitbake/lib/pysh/lsprof.py
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from _lsprof import Profiler, profiler_entry
|
||||||
|
|
||||||
|
__all__ = ['profile', 'Stats']
|
||||||
|
|
||||||
|
def profile(f, *args, **kwds):
|
||||||
|
"""XXX docstring"""
|
||||||
|
p = Profiler()
|
||||||
|
p.enable(subcalls=True, builtins=True)
|
||||||
|
try:
|
||||||
|
f(*args, **kwds)
|
||||||
|
finally:
|
||||||
|
p.disable()
|
||||||
|
return Stats(p.getstats())
|
||||||
|
|
||||||
|
|
||||||
|
class Stats(object):
|
||||||
|
"""XXX docstring"""
|
||||||
|
|
||||||
|
def __init__(self, data):
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
def sort(self, crit="inlinetime"):
|
||||||
|
"""XXX docstring"""
|
||||||
|
if crit not in profiler_entry.__dict__:
|
||||||
|
raise ValueError("Can't sort by %s" % crit)
|
||||||
|
self.data.sort(lambda b, a: cmp(getattr(a, crit),
|
||||||
|
getattr(b, crit)))
|
||||||
|
for e in self.data:
|
||||||
|
if e.calls:
|
||||||
|
e.calls.sort(lambda b, a: cmp(getattr(a, crit),
|
||||||
|
getattr(b, crit)))
|
||||||
|
|
||||||
|
def pprint(self, top=None, file=None, limit=None, climit=None):
|
||||||
|
"""XXX docstring"""
|
||||||
|
if file is None:
|
||||||
|
file = sys.stdout
|
||||||
|
d = self.data
|
||||||
|
if top is not None:
|
||||||
|
d = d[:top]
|
||||||
|
cols = "% 12s %12s %11.4f %11.4f %s\n"
|
||||||
|
hcols = "% 12s %12s %12s %12s %s\n"
|
||||||
|
cols2 = "+%12s %12s %11.4f %11.4f + %s\n"
|
||||||
|
file.write(hcols % ("CallCount", "Recursive", "Total(ms)",
|
||||||
|
"Inline(ms)", "module:lineno(function)"))
|
||||||
|
count = 0
|
||||||
|
for e in d:
|
||||||
|
file.write(cols % (e.callcount, e.reccallcount, e.totaltime,
|
||||||
|
e.inlinetime, label(e.code)))
|
||||||
|
count += 1
|
||||||
|
if limit is not None and count == limit:
|
||||||
|
return
|
||||||
|
ccount = 0
|
||||||
|
if e.calls:
|
||||||
|
for se in e.calls:
|
||||||
|
file.write(cols % ("+%s" % se.callcount, se.reccallcount,
|
||||||
|
se.totaltime, se.inlinetime,
|
||||||
|
"+%s" % label(se.code)))
|
||||||
|
count += 1
|
||||||
|
ccount += 1
|
||||||
|
if limit is not None and count == limit:
|
||||||
|
return
|
||||||
|
if climit is not None and ccount == climit:
|
||||||
|
break
|
||||||
|
|
||||||
|
def freeze(self):
|
||||||
|
"""Replace all references to code objects with string
|
||||||
|
descriptions; this makes it possible to pickle the instance."""
|
||||||
|
|
||||||
|
# this code is probably rather ickier than it needs to be!
|
||||||
|
for i in range(len(self.data)):
|
||||||
|
e = self.data[i]
|
||||||
|
if not isinstance(e.code, str):
|
||||||
|
self.data[i] = type(e)((label(e.code),) + e[1:])
|
||||||
|
if e.calls:
|
||||||
|
for j in range(len(e.calls)):
|
||||||
|
se = e.calls[j]
|
||||||
|
if not isinstance(se.code, str):
|
||||||
|
e.calls[j] = type(se)((label(se.code),) + se[1:])
|
||||||
|
|
||||||
|
_fn2mod = {}
|
||||||
|
|
||||||
|
def label(code):
|
||||||
|
if isinstance(code, str):
|
||||||
|
return code
|
||||||
|
try:
|
||||||
|
mname = _fn2mod[code.co_filename]
|
||||||
|
except KeyError:
|
||||||
|
for k, v in sys.modules.items():
|
||||||
|
if v is None:
|
||||||
|
continue
|
||||||
|
if not hasattr(v, '__file__'):
|
||||||
|
continue
|
||||||
|
if not isinstance(v.__file__, str):
|
||||||
|
continue
|
||||||
|
if v.__file__.startswith(code.co_filename):
|
||||||
|
mname = _fn2mod[code.co_filename] = k
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
mname = _fn2mod[code.co_filename] = '<%s>'%code.co_filename
|
||||||
|
|
||||||
|
return '%s:%d(%s)' % (mname, code.co_firstlineno, code.co_name)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import os
|
||||||
|
sys.argv = sys.argv[1:]
|
||||||
|
if not sys.argv:
|
||||||
|
print >> sys.stderr, "usage: lsprof.py <script> <arguments...>"
|
||||||
|
sys.exit(2)
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])))
|
||||||
|
stats = profile(execfile, sys.argv[0], globals(), locals())
|
||||||
|
stats.sort()
|
||||||
|
stats.pprint()
|
||||||
167
bitbake/lib/pysh/pysh.py
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# pysh.py - command processing for pysh.
|
||||||
|
#
|
||||||
|
# Copyright 2007 Patrick Mezard
|
||||||
|
#
|
||||||
|
# This software may be used and distributed according to the terms
|
||||||
|
# of the GNU General Public License, incorporated herein by reference.
|
||||||
|
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import interp
|
||||||
|
|
||||||
|
SH_OPT = optparse.OptionParser(prog='pysh', usage="%prog [OPTIONS]", version='0.1')
|
||||||
|
SH_OPT.add_option('-c', action='store_true', dest='command_string', default=None,
|
||||||
|
help='A string that shall be interpreted by the shell as one or more commands')
|
||||||
|
SH_OPT.add_option('--redirect-to', dest='redirect_to', default=None,
|
||||||
|
help='Redirect script commands stdout and stderr to the specified file')
|
||||||
|
# See utility_command in builtin.py about the reason for this flag.
|
||||||
|
SH_OPT.add_option('--redirected', dest='redirected', action='store_true', default=False,
|
||||||
|
help='Tell the interpreter that stdout and stderr are actually the same objects, which is really stdout')
|
||||||
|
SH_OPT.add_option('--debug-parsing', action='store_true', dest='debug_parsing', default=False,
|
||||||
|
help='Trace PLY execution')
|
||||||
|
SH_OPT.add_option('--debug-tree', action='store_true', dest='debug_tree', default=False,
|
||||||
|
help='Display the generated syntax tree.')
|
||||||
|
SH_OPT.add_option('--debug-cmd', action='store_true', dest='debug_cmd', default=False,
|
||||||
|
help='Trace command execution before parameters expansion and exit status.')
|
||||||
|
SH_OPT.add_option('--debug-utility', action='store_true', dest='debug_utility', default=False,
|
||||||
|
help='Trace utility calls, after parameters expansions')
|
||||||
|
SH_OPT.add_option('--ast', action='store_true', dest='ast', default=False,
|
||||||
|
help='Encoded commands to execute in a subprocess')
|
||||||
|
SH_OPT.add_option('--profile', action='store_true', default=False,
|
||||||
|
help='Profile pysh run')
|
||||||
|
|
||||||
|
|
||||||
|
def split_args(args):
|
||||||
|
# Separate shell arguments from command ones
|
||||||
|
# Just stop at the first argument not starting with a dash. I know, this is completely broken,
|
||||||
|
# it ignores files starting with a dash or may take option values for command file. This is not
|
||||||
|
# supposed to happen for now
|
||||||
|
command_index = len(args)
|
||||||
|
for i,arg in enumerate(args):
|
||||||
|
if not arg.startswith('-'):
|
||||||
|
command_index = i
|
||||||
|
break
|
||||||
|
|
||||||
|
return args[:command_index], args[command_index:]
|
||||||
|
|
||||||
|
|
||||||
|
def fixenv(env):
|
||||||
|
path = env.get('PATH')
|
||||||
|
if path is not None:
|
||||||
|
parts = path.split(os.pathsep)
|
||||||
|
# Remove Windows utilities from PATH, they are useless at best and
|
||||||
|
# some of them (find) may be confused with other utilities.
|
||||||
|
parts = [p for p in parts if 'system32' not in p.lower()]
|
||||||
|
env['PATH'] = os.pathsep.join(parts)
|
||||||
|
if env.get('HOME') is None:
|
||||||
|
# Several utilities, including cvsps, cannot work without
|
||||||
|
# a defined HOME directory.
|
||||||
|
env['HOME'] = os.path.expanduser('~')
|
||||||
|
return env
|
||||||
|
|
||||||
|
def _sh(cwd, shargs, cmdargs, options, debugflags=None, env=None):
|
||||||
|
if os.environ.get('PYSH_TEXT') != '1':
|
||||||
|
import msvcrt
|
||||||
|
for fp in (sys.stdin, sys.stdout, sys.stderr):
|
||||||
|
msvcrt.setmode(fp.fileno(), os.O_BINARY)
|
||||||
|
|
||||||
|
hgbin = os.environ.get('PYSH_HGTEXT') != '1'
|
||||||
|
|
||||||
|
if debugflags is None:
|
||||||
|
debugflags = []
|
||||||
|
if options.debug_parsing: debugflags.append('debug-parsing')
|
||||||
|
if options.debug_utility: debugflags.append('debug-utility')
|
||||||
|
if options.debug_cmd: debugflags.append('debug-cmd')
|
||||||
|
if options.debug_tree: debugflags.append('debug-tree')
|
||||||
|
|
||||||
|
if env is None:
|
||||||
|
env = fixenv(dict(os.environ))
|
||||||
|
if cwd is None:
|
||||||
|
cwd = os.getcwd()
|
||||||
|
|
||||||
|
if not cmdargs:
|
||||||
|
# Nothing to do
|
||||||
|
return 0
|
||||||
|
|
||||||
|
ast = None
|
||||||
|
command_file = None
|
||||||
|
if options.command_string:
|
||||||
|
input = cmdargs[0]
|
||||||
|
if not options.ast:
|
||||||
|
input += '\n'
|
||||||
|
else:
|
||||||
|
args, input = interp.decodeargs(input), None
|
||||||
|
env, ast = args
|
||||||
|
cwd = env.get('PWD', cwd)
|
||||||
|
else:
|
||||||
|
command_file = cmdargs[0]
|
||||||
|
arguments = cmdargs[1:]
|
||||||
|
|
||||||
|
prefix = interp.resolve_shebang(command_file, ignoreshell=True)
|
||||||
|
if prefix:
|
||||||
|
input = ' '.join(prefix + [command_file] + arguments)
|
||||||
|
else:
|
||||||
|
# Read commands from file
|
||||||
|
f = file(command_file)
|
||||||
|
try:
|
||||||
|
# Trailing newline to help the parser
|
||||||
|
input = f.read() + '\n'
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
redirect = None
|
||||||
|
try:
|
||||||
|
if options.redirected:
|
||||||
|
stdout = sys.stdout
|
||||||
|
stderr = stdout
|
||||||
|
elif options.redirect_to:
|
||||||
|
redirect = open(options.redirect_to, 'wb')
|
||||||
|
stdout = redirect
|
||||||
|
stderr = redirect
|
||||||
|
else:
|
||||||
|
stdout = sys.stdout
|
||||||
|
stderr = sys.stderr
|
||||||
|
|
||||||
|
# TODO: set arguments to environment variables
|
||||||
|
opts = interp.Options()
|
||||||
|
opts.hgbinary = hgbin
|
||||||
|
ip = interp.Interpreter(cwd, debugflags, stdout=stdout, stderr=stderr,
|
||||||
|
opts=opts)
|
||||||
|
try:
|
||||||
|
# Export given environment in shell object
|
||||||
|
for k,v in env.iteritems():
|
||||||
|
ip.get_env().export(k,v)
|
||||||
|
return ip.execute_script(input, ast, scriptpath=command_file)
|
||||||
|
finally:
|
||||||
|
ip.close()
|
||||||
|
finally:
|
||||||
|
if redirect is not None:
|
||||||
|
redirect.close()
|
||||||
|
|
||||||
|
def sh(cwd=None, args=None, debugflags=None, env=None):
|
||||||
|
if args is None:
|
||||||
|
args = sys.argv[1:]
|
||||||
|
shargs, cmdargs = split_args(args)
|
||||||
|
options, shargs = SH_OPT.parse_args(shargs)
|
||||||
|
|
||||||
|
if options.profile:
|
||||||
|
import lsprof
|
||||||
|
p = lsprof.Profiler()
|
||||||
|
p.enable(subcalls=True)
|
||||||
|
try:
|
||||||
|
return _sh(cwd, shargs, cmdargs, options, debugflags, env)
|
||||||
|
finally:
|
||||||
|
p.disable()
|
||||||
|
stats = lsprof.Stats(p.getstats())
|
||||||
|
stats.sort()
|
||||||
|
stats.pprint(top=10, file=sys.stderr, climit=5)
|
||||||
|
else:
|
||||||
|
return _sh(cwd, shargs, cmdargs, options, debugflags, env)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
sys.exit(sh())
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
main()
|
||||||
888
bitbake/lib/pysh/pyshlex.py
Normal file
@@ -0,0 +1,888 @@
|
|||||||
|
# pyshlex.py - PLY compatible lexer for pysh.
|
||||||
|
#
|
||||||
|
# Copyright 2007 Patrick Mezard
|
||||||
|
#
|
||||||
|
# This software may be used and distributed according to the terms
|
||||||
|
# of the GNU General Public License, incorporated herein by reference.
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# - review all "char in 'abc'" snippets: the empty string can be matched
|
||||||
|
# - test line continuations within quoted/expansion strings
|
||||||
|
# - eof is buggy wrt sublexers
|
||||||
|
# - the lexer cannot really work in pull mode as it would be required to run
|
||||||
|
# PLY in pull mode. It was designed to work incrementally and it would not be
|
||||||
|
# that hard to enable pull mode.
|
||||||
|
import re
|
||||||
|
try:
|
||||||
|
s = set()
|
||||||
|
del s
|
||||||
|
except NameError:
|
||||||
|
from Set import Set as set
|
||||||
|
|
||||||
|
from ply import lex
|
||||||
|
from sherrors import *
|
||||||
|
|
||||||
|
class NeedMore(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def is_blank(c):
|
||||||
|
return c in (' ', '\t')
|
||||||
|
|
||||||
|
_RE_DIGITS = re.compile(r'^\d+$')
|
||||||
|
|
||||||
|
def are_digits(s):
|
||||||
|
return _RE_DIGITS.search(s) is not None
|
||||||
|
|
||||||
|
_OPERATORS = dict([
|
||||||
|
('&&', 'AND_IF'),
|
||||||
|
('||', 'OR_IF'),
|
||||||
|
(';;', 'DSEMI'),
|
||||||
|
('<<', 'DLESS'),
|
||||||
|
('>>', 'DGREAT'),
|
||||||
|
('<&', 'LESSAND'),
|
||||||
|
('>&', 'GREATAND'),
|
||||||
|
('<>', 'LESSGREAT'),
|
||||||
|
('<<-', 'DLESSDASH'),
|
||||||
|
('>|', 'CLOBBER'),
|
||||||
|
('&', 'AMP'),
|
||||||
|
(';', 'COMMA'),
|
||||||
|
('<', 'LESS'),
|
||||||
|
('>', 'GREATER'),
|
||||||
|
('(', 'LPARENS'),
|
||||||
|
(')', 'RPARENS'),
|
||||||
|
])
|
||||||
|
|
||||||
|
#Make a function to silence pychecker "Local variable shadows global"
|
||||||
|
def make_partial_ops():
|
||||||
|
partials = {}
|
||||||
|
for k in _OPERATORS:
|
||||||
|
for i in range(1, len(k)+1):
|
||||||
|
partials[k[:i]] = None
|
||||||
|
return partials
|
||||||
|
|
||||||
|
_PARTIAL_OPERATORS = make_partial_ops()
|
||||||
|
|
||||||
|
def is_partial_op(s):
|
||||||
|
"""Return True if s matches a non-empty subpart of an operator starting
|
||||||
|
at its first character.
|
||||||
|
"""
|
||||||
|
return s in _PARTIAL_OPERATORS
|
||||||
|
|
||||||
|
def is_op(s):
|
||||||
|
"""If s matches an operator, returns the operator identifier. Return None
|
||||||
|
otherwise.
|
||||||
|
"""
|
||||||
|
return _OPERATORS.get(s)
|
||||||
|
|
||||||
|
_RESERVEDS = dict([
|
||||||
|
('if', 'If'),
|
||||||
|
('then', 'Then'),
|
||||||
|
('else', 'Else'),
|
||||||
|
('elif', 'Elif'),
|
||||||
|
('fi', 'Fi'),
|
||||||
|
('do', 'Do'),
|
||||||
|
('done', 'Done'),
|
||||||
|
('case', 'Case'),
|
||||||
|
('esac', 'Esac'),
|
||||||
|
('while', 'While'),
|
||||||
|
('until', 'Until'),
|
||||||
|
('for', 'For'),
|
||||||
|
('{', 'Lbrace'),
|
||||||
|
('}', 'Rbrace'),
|
||||||
|
('!', 'Bang'),
|
||||||
|
('in', 'In'),
|
||||||
|
('|', 'PIPE'),
|
||||||
|
])
|
||||||
|
|
||||||
|
def get_reserved(s):
|
||||||
|
return _RESERVEDS.get(s)
|
||||||
|
|
||||||
|
_RE_NAME = re.compile(r'^[0-9a-zA-Z_]+$')
|
||||||
|
|
||||||
|
def is_name(s):
|
||||||
|
return _RE_NAME.search(s) is not None
|
||||||
|
|
||||||
|
def find_chars(seq, chars):
|
||||||
|
for i,v in enumerate(seq):
|
||||||
|
if v in chars:
|
||||||
|
return i,v
|
||||||
|
return -1, None
|
||||||
|
|
||||||
|
class WordLexer:
|
||||||
|
"""WordLexer parse quoted or expansion expressions and return an expression
|
||||||
|
tree. The input string can be any well formed sequence beginning with quoting
|
||||||
|
or expansion character. Embedded expressions are handled recursively. The
|
||||||
|
resulting tree is made of lists and strings. Lists represent quoted or
|
||||||
|
expansion expressions. Each list first element is the opening separator,
|
||||||
|
the last one the closing separator. In-between can be any number of strings
|
||||||
|
or lists for sub-expressions. Non quoted/expansion expression can written as
|
||||||
|
strings or as lists with empty strings as starting and ending delimiters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
NAME_CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
|
||||||
|
NAME_CHARSET = dict(zip(NAME_CHARSET, NAME_CHARSET))
|
||||||
|
|
||||||
|
SPECIAL_CHARSET = '@*#?-$!0'
|
||||||
|
|
||||||
|
#Characters which can be escaped depends on the current delimiters
|
||||||
|
ESCAPABLE = {
|
||||||
|
'`': set(['$', '\\', '`']),
|
||||||
|
'"': set(['$', '\\', '`', '"']),
|
||||||
|
"'": set(),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, heredoc = False):
|
||||||
|
# _buffer is the unprocessed input characters buffer
|
||||||
|
self._buffer = []
|
||||||
|
# _stack is empty or contains a quoted list being processed
|
||||||
|
# (this is the DFS path to the quoted expression being evaluated).
|
||||||
|
self._stack = []
|
||||||
|
self._escapable = None
|
||||||
|
# True when parsing unquoted here documents
|
||||||
|
self._heredoc = heredoc
|
||||||
|
|
||||||
|
def add(self, data, eof=False):
|
||||||
|
"""Feed the lexer with more data. If the quoted expression can be
|
||||||
|
delimited, return a tuple (expr, remaining) containing the expression
|
||||||
|
tree and the unconsumed data.
|
||||||
|
Otherwise, raise NeedMore.
|
||||||
|
"""
|
||||||
|
self._buffer += list(data)
|
||||||
|
self._parse(eof)
|
||||||
|
|
||||||
|
result = self._stack[0]
|
||||||
|
remaining = ''.join(self._buffer)
|
||||||
|
self._stack = []
|
||||||
|
self._buffer = []
|
||||||
|
return result, remaining
|
||||||
|
|
||||||
|
def _is_escapable(self, c, delim=None):
|
||||||
|
if delim is None:
|
||||||
|
if self._heredoc:
|
||||||
|
# Backslashes works as if they were double quoted in unquoted
|
||||||
|
# here-documents
|
||||||
|
delim = '"'
|
||||||
|
else:
|
||||||
|
if len(self._stack)<=1:
|
||||||
|
return True
|
||||||
|
delim = self._stack[-2][0]
|
||||||
|
|
||||||
|
escapables = self.ESCAPABLE.get(delim, None)
|
||||||
|
return escapables is None or c in escapables
|
||||||
|
|
||||||
|
def _parse_squote(self, buf, result, eof):
|
||||||
|
if not buf:
|
||||||
|
raise NeedMore()
|
||||||
|
try:
|
||||||
|
pos = buf.index("'")
|
||||||
|
except ValueError:
|
||||||
|
raise NeedMore()
|
||||||
|
result[-1] += ''.join(buf[:pos])
|
||||||
|
result += ["'"]
|
||||||
|
return pos+1, True
|
||||||
|
|
||||||
|
def _parse_bquote(self, buf, result, eof):
|
||||||
|
if not buf:
|
||||||
|
raise NeedMore()
|
||||||
|
|
||||||
|
if buf[0]=='\n':
|
||||||
|
#Remove line continuations
|
||||||
|
result[:] = ['', '', '']
|
||||||
|
elif self._is_escapable(buf[0]):
|
||||||
|
result[-1] += buf[0]
|
||||||
|
result += ['']
|
||||||
|
else:
|
||||||
|
#Keep as such
|
||||||
|
result[:] = ['', '\\'+buf[0], '']
|
||||||
|
|
||||||
|
return 1, True
|
||||||
|
|
||||||
|
def _parse_dquote(self, buf, result, eof):
|
||||||
|
if not buf:
|
||||||
|
raise NeedMore()
|
||||||
|
pos, sep = find_chars(buf, '$\\`"')
|
||||||
|
if pos==-1:
|
||||||
|
raise NeedMore()
|
||||||
|
|
||||||
|
result[-1] += ''.join(buf[:pos])
|
||||||
|
if sep=='"':
|
||||||
|
result += ['"']
|
||||||
|
return pos+1, True
|
||||||
|
else:
|
||||||
|
#Keep everything until the separator and defer processing
|
||||||
|
return pos, False
|
||||||
|
|
||||||
|
def _parse_command(self, buf, result, eof):
|
||||||
|
if not buf:
|
||||||
|
raise NeedMore()
|
||||||
|
|
||||||
|
chars = '$\\`"\''
|
||||||
|
if result[0] == '$(':
|
||||||
|
chars += ')'
|
||||||
|
pos, sep = find_chars(buf, chars)
|
||||||
|
if pos == -1:
|
||||||
|
raise NeedMore()
|
||||||
|
|
||||||
|
result[-1] += ''.join(buf[:pos])
|
||||||
|
if (result[0]=='$(' and sep==')') or (result[0]=='`' and sep=='`'):
|
||||||
|
result += [sep]
|
||||||
|
return pos+1, True
|
||||||
|
else:
|
||||||
|
return pos, False
|
||||||
|
|
||||||
|
def _parse_parameter(self, buf, result, eof):
|
||||||
|
if not buf:
|
||||||
|
raise NeedMore()
|
||||||
|
|
||||||
|
pos, sep = find_chars(buf, '$\\`"\'}')
|
||||||
|
if pos==-1:
|
||||||
|
raise NeedMore()
|
||||||
|
|
||||||
|
result[-1] += ''.join(buf[:pos])
|
||||||
|
if sep=='}':
|
||||||
|
result += [sep]
|
||||||
|
return pos+1, True
|
||||||
|
else:
|
||||||
|
return pos, False
|
||||||
|
|
||||||
|
def _parse_dollar(self, buf, result, eof):
|
||||||
|
sep = result[0]
|
||||||
|
if sep=='$':
|
||||||
|
if not buf:
|
||||||
|
#TODO: handle empty $
|
||||||
|
raise NeedMore()
|
||||||
|
if buf[0]=='(':
|
||||||
|
if len(buf)==1:
|
||||||
|
raise NeedMore()
|
||||||
|
|
||||||
|
if buf[1]=='(':
|
||||||
|
result[0] = '$(('
|
||||||
|
buf[:2] = []
|
||||||
|
else:
|
||||||
|
result[0] = '$('
|
||||||
|
buf[:1] = []
|
||||||
|
|
||||||
|
elif buf[0]=='{':
|
||||||
|
result[0] = '${'
|
||||||
|
buf[:1] = []
|
||||||
|
else:
|
||||||
|
if buf[0] in self.SPECIAL_CHARSET:
|
||||||
|
result[-1] = buf[0]
|
||||||
|
read = 1
|
||||||
|
else:
|
||||||
|
for read,c in enumerate(buf):
|
||||||
|
if c not in self.NAME_CHARSET:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if not eof:
|
||||||
|
raise NeedMore()
|
||||||
|
read += 1
|
||||||
|
|
||||||
|
result[-1] += ''.join(buf[0:read])
|
||||||
|
|
||||||
|
if not result[-1]:
|
||||||
|
result[:] = ['', result[0], '']
|
||||||
|
else:
|
||||||
|
result += ['']
|
||||||
|
return read,True
|
||||||
|
|
||||||
|
sep = result[0]
|
||||||
|
if sep=='$(':
|
||||||
|
parsefunc = self._parse_command
|
||||||
|
elif sep=='${':
|
||||||
|
parsefunc = self._parse_parameter
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
pos, closed = parsefunc(buf, result, eof)
|
||||||
|
return pos, closed
|
||||||
|
|
||||||
|
def _parse(self, eof):
|
||||||
|
buf = self._buffer
|
||||||
|
stack = self._stack
|
||||||
|
recurse = False
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
if not stack or recurse:
|
||||||
|
if not buf:
|
||||||
|
raise NeedMore()
|
||||||
|
if buf[0] not in ('"\\`$\''):
|
||||||
|
raise ShellSyntaxError('Invalid quoted string sequence')
|
||||||
|
stack.append([buf[0], ''])
|
||||||
|
buf[:1] = []
|
||||||
|
recurse = False
|
||||||
|
|
||||||
|
result = stack[-1]
|
||||||
|
if result[0]=="'":
|
||||||
|
parsefunc = self._parse_squote
|
||||||
|
elif result[0]=='\\':
|
||||||
|
parsefunc = self._parse_bquote
|
||||||
|
elif result[0]=='"':
|
||||||
|
parsefunc = self._parse_dquote
|
||||||
|
elif result[0]=='`':
|
||||||
|
parsefunc = self._parse_command
|
||||||
|
elif result[0][0]=='$':
|
||||||
|
parsefunc = self._parse_dollar
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
read, closed = parsefunc(buf, result, eof)
|
||||||
|
|
||||||
|
buf[:read] = []
|
||||||
|
if closed:
|
||||||
|
if len(stack)>1:
|
||||||
|
#Merge in parent expression
|
||||||
|
parsed = stack.pop()
|
||||||
|
stack[-1] += [parsed]
|
||||||
|
stack[-1] += ['']
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
recurse = True
|
||||||
|
|
||||||
|
def normalize_wordtree(wtree):
|
||||||
|
"""Fold back every literal sequence (delimited with empty strings) into
|
||||||
|
parent sequence.
|
||||||
|
"""
|
||||||
|
def normalize(wtree):
|
||||||
|
result = []
|
||||||
|
for part in wtree[1:-1]:
|
||||||
|
if isinstance(part, list):
|
||||||
|
part = normalize(part)
|
||||||
|
if part[0]=='':
|
||||||
|
#Move the part content back at current level
|
||||||
|
result += part[1:-1]
|
||||||
|
continue
|
||||||
|
elif not part:
|
||||||
|
#Remove empty strings
|
||||||
|
continue
|
||||||
|
result.append(part)
|
||||||
|
if not result:
|
||||||
|
result = ['']
|
||||||
|
return [wtree[0]] + result + [wtree[-1]]
|
||||||
|
|
||||||
|
return normalize(wtree)
|
||||||
|
|
||||||
|
|
||||||
|
def make_wordtree(token, here_document=False):
|
||||||
|
"""Parse a delimited token and return a tree similar to the ones returned by
|
||||||
|
WordLexer. token may contain any combinations of expansion/quoted fields and
|
||||||
|
non-ones.
|
||||||
|
"""
|
||||||
|
tree = ['']
|
||||||
|
remaining = token
|
||||||
|
delimiters = '\\$`'
|
||||||
|
if not here_document:
|
||||||
|
delimiters += '\'"'
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
pos, sep = find_chars(remaining, delimiters)
|
||||||
|
if pos==-1:
|
||||||
|
tree += [remaining, '']
|
||||||
|
return normalize_wordtree(tree)
|
||||||
|
tree.append(remaining[:pos])
|
||||||
|
remaining = remaining[pos:]
|
||||||
|
|
||||||
|
try:
|
||||||
|
result, remaining = WordLexer(heredoc = here_document).add(remaining, True)
|
||||||
|
except NeedMore:
|
||||||
|
raise ShellSyntaxError('Invalid token "%s"')
|
||||||
|
tree.append(result)
|
||||||
|
|
||||||
|
|
||||||
|
def wordtree_as_string(wtree):
|
||||||
|
"""Rewrite an expression tree generated by make_wordtree as string."""
|
||||||
|
def visit(node, output):
|
||||||
|
for child in node:
|
||||||
|
if isinstance(child, list):
|
||||||
|
visit(child, output)
|
||||||
|
else:
|
||||||
|
output.append(child)
|
||||||
|
|
||||||
|
output = []
|
||||||
|
visit(wtree, output)
|
||||||
|
return ''.join(output)
|
||||||
|
|
||||||
|
|
||||||
|
def unquote_wordtree(wtree):
|
||||||
|
"""Fold the word tree while removing quotes everywhere. Other expansion
|
||||||
|
sequences are joined as such.
|
||||||
|
"""
|
||||||
|
def unquote(wtree):
|
||||||
|
unquoted = []
|
||||||
|
if wtree[0] in ('', "'", '"', '\\'):
|
||||||
|
wtree = wtree[1:-1]
|
||||||
|
|
||||||
|
for part in wtree:
|
||||||
|
if isinstance(part, list):
|
||||||
|
part = unquote(part)
|
||||||
|
unquoted.append(part)
|
||||||
|
return ''.join(unquoted)
|
||||||
|
|
||||||
|
return unquote(wtree)
|
||||||
|
|
||||||
|
|
||||||
|
class HereDocLexer:
|
||||||
|
"""HereDocLexer delimits whatever comes from the here-document starting newline
|
||||||
|
not included to the closing delimiter line included.
|
||||||
|
"""
|
||||||
|
def __init__(self, op, delim):
|
||||||
|
assert op in ('<<', '<<-')
|
||||||
|
if not delim:
|
||||||
|
raise ShellSyntaxError('invalid here document delimiter %s' % str(delim))
|
||||||
|
|
||||||
|
self._op = op
|
||||||
|
self._delim = delim
|
||||||
|
self._buffer = []
|
||||||
|
self._token = []
|
||||||
|
|
||||||
|
def add(self, data, eof):
|
||||||
|
"""If the here-document was delimited, return a tuple (content, remaining).
|
||||||
|
Raise NeedMore() otherwise.
|
||||||
|
"""
|
||||||
|
self._buffer += list(data)
|
||||||
|
self._parse(eof)
|
||||||
|
token = ''.join(self._token)
|
||||||
|
remaining = ''.join(self._buffer)
|
||||||
|
self._token, self._remaining = [], []
|
||||||
|
return token, remaining
|
||||||
|
|
||||||
|
def _parse(self, eof):
|
||||||
|
while 1:
|
||||||
|
#Look for first unescaped newline. Quotes may be ignored
|
||||||
|
escaped = False
|
||||||
|
for i,c in enumerate(self._buffer):
|
||||||
|
if escaped:
|
||||||
|
escaped = False
|
||||||
|
elif c=='\\':
|
||||||
|
escaped = True
|
||||||
|
elif c=='\n':
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
i = -1
|
||||||
|
|
||||||
|
if i==-1 or self._buffer[i]!='\n':
|
||||||
|
if not eof:
|
||||||
|
raise NeedMore()
|
||||||
|
#No more data, maybe the last line is closing delimiter
|
||||||
|
line = ''.join(self._buffer)
|
||||||
|
eol = ''
|
||||||
|
self._buffer[:] = []
|
||||||
|
else:
|
||||||
|
line = ''.join(self._buffer[:i])
|
||||||
|
eol = self._buffer[i]
|
||||||
|
self._buffer[:i+1] = []
|
||||||
|
|
||||||
|
if self._op=='<<-':
|
||||||
|
line = line.lstrip('\t')
|
||||||
|
|
||||||
|
if line==self._delim:
|
||||||
|
break
|
||||||
|
|
||||||
|
self._token += [line, eol]
|
||||||
|
if i==-1:
|
||||||
|
break
|
||||||
|
|
||||||
|
class Token:
|
||||||
|
#TODO: check this is still in use
|
||||||
|
OPERATOR = 'OPERATOR'
|
||||||
|
WORD = 'WORD'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.value = ''
|
||||||
|
self.type = None
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
#Behave like a two elements tuple
|
||||||
|
if key==0:
|
||||||
|
return self.type
|
||||||
|
if key==1:
|
||||||
|
return self.value
|
||||||
|
raise IndexError(key)
|
||||||
|
|
||||||
|
|
||||||
|
class HereDoc:
|
||||||
|
def __init__(self, op, name=None):
|
||||||
|
self.op = op
|
||||||
|
self.name = name
|
||||||
|
self.pendings = []
|
||||||
|
|
||||||
|
TK_COMMA = 'COMMA'
|
||||||
|
TK_AMPERSAND = 'AMP'
|
||||||
|
TK_OP = 'OP'
|
||||||
|
TK_TOKEN = 'TOKEN'
|
||||||
|
TK_COMMENT = 'COMMENT'
|
||||||
|
TK_NEWLINE = 'NEWLINE'
|
||||||
|
TK_IONUMBER = 'IO_NUMBER'
|
||||||
|
TK_ASSIGNMENT = 'ASSIGNMENT_WORD'
|
||||||
|
TK_HERENAME = 'HERENAME'
|
||||||
|
|
||||||
|
class Lexer:
|
||||||
|
"""Main lexer.
|
||||||
|
|
||||||
|
Call add() until the script AST is returned.
|
||||||
|
"""
|
||||||
|
# Here-document handling makes the whole thing more complex because they basically
|
||||||
|
# force tokens to be reordered: here-content must come right after the operator
|
||||||
|
# and the here-document name, while some other tokens might be following the
|
||||||
|
# here-document expression on the same line.
|
||||||
|
#
|
||||||
|
# So, here-doc states are basically:
|
||||||
|
# *self._state==ST_NORMAL
|
||||||
|
# - self._heredoc.op is None: no here-document
|
||||||
|
# - self._heredoc.op is not None but name is: here-document operator matched,
|
||||||
|
# waiting for the document name/delimiter
|
||||||
|
# - self._heredoc.op and name are not None: here-document is ready, following
|
||||||
|
# tokens are being stored and will be pushed again when the document is
|
||||||
|
# completely parsed.
|
||||||
|
# *self._state==ST_HEREDOC
|
||||||
|
# - The here-document is being delimited by self._herelexer. Once it is done
|
||||||
|
# the content is pushed in front of the pending token list then all these
|
||||||
|
# tokens are pushed once again.
|
||||||
|
ST_NORMAL = 'ST_NORMAL'
|
||||||
|
ST_OP = 'ST_OP'
|
||||||
|
ST_BACKSLASH = 'ST_BACKSLASH'
|
||||||
|
ST_QUOTED = 'ST_QUOTED'
|
||||||
|
ST_COMMENT = 'ST_COMMENT'
|
||||||
|
ST_HEREDOC = 'ST_HEREDOC'
|
||||||
|
|
||||||
|
#Match end of backquote strings
|
||||||
|
RE_BACKQUOTE_END = re.compile(r'(?<!\\)(`)')
|
||||||
|
|
||||||
|
def __init__(self, parent_state = None):
|
||||||
|
self._input = []
|
||||||
|
self._pos = 0
|
||||||
|
|
||||||
|
self._token = ''
|
||||||
|
self._type = TK_TOKEN
|
||||||
|
|
||||||
|
self._state = self.ST_NORMAL
|
||||||
|
self._parent_state = parent_state
|
||||||
|
self._wordlexer = None
|
||||||
|
|
||||||
|
self._heredoc = HereDoc(None)
|
||||||
|
self._herelexer = None
|
||||||
|
|
||||||
|
### Following attributes are not used for delimiting token and can safely
|
||||||
|
### be changed after here-document detection (see _push_toke)
|
||||||
|
|
||||||
|
# Count the number of tokens following a 'For' reserved word. Needed to
|
||||||
|
# return an 'In' reserved word if it comes in third place.
|
||||||
|
self._for_count = None
|
||||||
|
|
||||||
|
def add(self, data, eof=False):
|
||||||
|
"""Feed the lexer with data.
|
||||||
|
|
||||||
|
When eof is set to True, returns unconsumed data or raise if the lexer
|
||||||
|
is in the middle of a delimiting operation.
|
||||||
|
Raise NeedMore otherwise.
|
||||||
|
"""
|
||||||
|
self._input += list(data)
|
||||||
|
self._parse(eof)
|
||||||
|
self._input[:self._pos] = []
|
||||||
|
return ''.join(self._input)
|
||||||
|
|
||||||
|
def _parse(self, eof):
|
||||||
|
while self._state:
|
||||||
|
if self._pos>=len(self._input):
|
||||||
|
if not eof:
|
||||||
|
raise NeedMore()
|
||||||
|
elif self._state not in (self.ST_OP, self.ST_QUOTED, self.ST_HEREDOC):
|
||||||
|
#Delimit the current token and leave cleanly
|
||||||
|
self._push_token('')
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
#Let the sublexer handle the eof themselves
|
||||||
|
pass
|
||||||
|
|
||||||
|
if self._state==self.ST_NORMAL:
|
||||||
|
self._parse_normal()
|
||||||
|
elif self._state==self.ST_COMMENT:
|
||||||
|
self._parse_comment()
|
||||||
|
elif self._state==self.ST_OP:
|
||||||
|
self._parse_op(eof)
|
||||||
|
elif self._state==self.ST_QUOTED:
|
||||||
|
self._parse_quoted(eof)
|
||||||
|
elif self._state==self.ST_HEREDOC:
|
||||||
|
self._parse_heredoc(eof)
|
||||||
|
else:
|
||||||
|
assert False, "Unknown state " + str(self._state)
|
||||||
|
|
||||||
|
if self._heredoc.op is not None:
|
||||||
|
raise ShellSyntaxError('missing here-document delimiter')
|
||||||
|
|
||||||
|
def _parse_normal(self):
|
||||||
|
c = self._input[self._pos]
|
||||||
|
if c=='\n':
|
||||||
|
self._push_token(c)
|
||||||
|
self._token = c
|
||||||
|
self._type = TK_NEWLINE
|
||||||
|
self._push_token('')
|
||||||
|
self._pos += 1
|
||||||
|
elif c in ('\\', '\'', '"', '`', '$'):
|
||||||
|
self._state = self.ST_QUOTED
|
||||||
|
elif is_partial_op(c):
|
||||||
|
self._push_token(c)
|
||||||
|
|
||||||
|
self._type = TK_OP
|
||||||
|
self._token += c
|
||||||
|
self._pos += 1
|
||||||
|
self._state = self.ST_OP
|
||||||
|
elif is_blank(c):
|
||||||
|
self._push_token(c)
|
||||||
|
|
||||||
|
#Discard blanks
|
||||||
|
self._pos += 1
|
||||||
|
elif self._token:
|
||||||
|
self._token += c
|
||||||
|
self._pos += 1
|
||||||
|
elif c=='#':
|
||||||
|
self._state = self.ST_COMMENT
|
||||||
|
self._type = TK_COMMENT
|
||||||
|
self._pos += 1
|
||||||
|
else:
|
||||||
|
self._pos += 1
|
||||||
|
self._token += c
|
||||||
|
|
||||||
|
def _parse_op(self, eof):
|
||||||
|
assert self._token
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
if self._pos>=len(self._input):
|
||||||
|
if not eof:
|
||||||
|
raise NeedMore()
|
||||||
|
c = ''
|
||||||
|
else:
|
||||||
|
c = self._input[self._pos]
|
||||||
|
|
||||||
|
op = self._token + c
|
||||||
|
if c and is_partial_op(op):
|
||||||
|
#Still parsing an operator
|
||||||
|
self._token = op
|
||||||
|
self._pos += 1
|
||||||
|
else:
|
||||||
|
#End of operator
|
||||||
|
self._push_token(c)
|
||||||
|
self._state = self.ST_NORMAL
|
||||||
|
break
|
||||||
|
|
||||||
|
def _parse_comment(self):
|
||||||
|
while 1:
|
||||||
|
if self._pos>=len(self._input):
|
||||||
|
raise NeedMore()
|
||||||
|
|
||||||
|
c = self._input[self._pos]
|
||||||
|
if c=='\n':
|
||||||
|
#End of comment, do not consume the end of line
|
||||||
|
self._state = self.ST_NORMAL
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self._token += c
|
||||||
|
self._pos += 1
|
||||||
|
|
||||||
|
def _parse_quoted(self, eof):
|
||||||
|
"""Precondition: the starting backquote/dollar is still in the input queue."""
|
||||||
|
if not self._wordlexer:
|
||||||
|
self._wordlexer = WordLexer()
|
||||||
|
|
||||||
|
if self._pos<len(self._input):
|
||||||
|
#Transfer input queue character into the subparser
|
||||||
|
input = self._input[self._pos:]
|
||||||
|
self._pos += len(input)
|
||||||
|
|
||||||
|
wtree, remaining = self._wordlexer.add(input, eof)
|
||||||
|
self._wordlexer = None
|
||||||
|
self._token += wordtree_as_string(wtree)
|
||||||
|
|
||||||
|
#Put unparsed character back in the input queue
|
||||||
|
if remaining:
|
||||||
|
self._input[self._pos:self._pos] = list(remaining)
|
||||||
|
self._state = self.ST_NORMAL
|
||||||
|
|
||||||
|
def _parse_heredoc(self, eof):
|
||||||
|
assert not self._token
|
||||||
|
|
||||||
|
if self._herelexer is None:
|
||||||
|
self._herelexer = HereDocLexer(self._heredoc.op, self._heredoc.name)
|
||||||
|
|
||||||
|
if self._pos<len(self._input):
|
||||||
|
#Transfer input queue character into the subparser
|
||||||
|
input = self._input[self._pos:]
|
||||||
|
self._pos += len(input)
|
||||||
|
|
||||||
|
self._token, remaining = self._herelexer.add(input, eof)
|
||||||
|
|
||||||
|
#Reset here-document state
|
||||||
|
self._herelexer = None
|
||||||
|
heredoc, self._heredoc = self._heredoc, HereDoc(None)
|
||||||
|
if remaining:
|
||||||
|
self._input[self._pos:self._pos] = list(remaining)
|
||||||
|
self._state = self.ST_NORMAL
|
||||||
|
|
||||||
|
#Push pending tokens
|
||||||
|
heredoc.pendings[:0] = [(self._token, self._type, heredoc.name)]
|
||||||
|
for token, type, delim in heredoc.pendings:
|
||||||
|
self._token = token
|
||||||
|
self._type = type
|
||||||
|
self._push_token(delim)
|
||||||
|
|
||||||
|
def _push_token(self, delim):
|
||||||
|
if not self._token:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if self._heredoc.op is not None:
|
||||||
|
if self._heredoc.name is None:
|
||||||
|
#Here-document name
|
||||||
|
if self._type!=TK_TOKEN:
|
||||||
|
raise ShellSyntaxError("expecting here-document name, got '%s'" % self._token)
|
||||||
|
self._heredoc.name = unquote_wordtree(make_wordtree(self._token))
|
||||||
|
self._type = TK_HERENAME
|
||||||
|
else:
|
||||||
|
#Capture all tokens until the newline starting the here-document
|
||||||
|
if self._type==TK_NEWLINE:
|
||||||
|
assert self._state==self.ST_NORMAL
|
||||||
|
self._state = self.ST_HEREDOC
|
||||||
|
|
||||||
|
self._heredoc.pendings.append((self._token, self._type, delim))
|
||||||
|
self._token = ''
|
||||||
|
self._type = TK_TOKEN
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# BEWARE: do not change parser state from here to the end of the function:
|
||||||
|
# when parsing between an here-document operator to the end of the line
|
||||||
|
# tokens are stored in self._heredoc.pendings. Therefore, they will not
|
||||||
|
# reach the section below.
|
||||||
|
|
||||||
|
#Check operators
|
||||||
|
if self._type==TK_OP:
|
||||||
|
#False positive because of partial op matching
|
||||||
|
op = is_op(self._token)
|
||||||
|
if not op:
|
||||||
|
self._type = TK_TOKEN
|
||||||
|
else:
|
||||||
|
#Map to the specific operator
|
||||||
|
self._type = op
|
||||||
|
if self._token in ('<<', '<<-'):
|
||||||
|
#Done here rather than in _parse_op because there is no need
|
||||||
|
#to change the parser state since we are still waiting for
|
||||||
|
#the here-document name
|
||||||
|
if self._heredoc.op is not None:
|
||||||
|
raise ShellSyntaxError("syntax error near token '%s'" % self._token)
|
||||||
|
assert self._heredoc.op is None
|
||||||
|
self._heredoc.op = self._token
|
||||||
|
|
||||||
|
if self._type==TK_TOKEN:
|
||||||
|
if '=' in self._token and not delim:
|
||||||
|
if self._token.startswith('='):
|
||||||
|
#Token is a WORD... a TOKEN that is.
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
prev = self._token[:self._token.find('=')]
|
||||||
|
if is_name(prev):
|
||||||
|
self._type = TK_ASSIGNMENT
|
||||||
|
else:
|
||||||
|
#Just a token (unspecified)
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
reserved = get_reserved(self._token)
|
||||||
|
if reserved is not None:
|
||||||
|
if reserved=='In' and self._for_count!=2:
|
||||||
|
#Sorry, not a reserved word after all
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self._type = reserved
|
||||||
|
if reserved in ('For', 'Case'):
|
||||||
|
self._for_count = 0
|
||||||
|
elif are_digits(self._token) and delim in ('<', '>'):
|
||||||
|
#Detect IO_NUMBER
|
||||||
|
self._type = TK_IONUMBER
|
||||||
|
elif self._token==';':
|
||||||
|
self._type = TK_COMMA
|
||||||
|
elif self._token=='&':
|
||||||
|
self._type = TK_AMPERSAND
|
||||||
|
elif self._type==TK_COMMENT:
|
||||||
|
#Comments are not part of sh grammar, ignore them
|
||||||
|
self._token = ''
|
||||||
|
self._type = TK_TOKEN
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if self._for_count is not None:
|
||||||
|
#Track token count in 'For' expression to detect 'In' reserved words.
|
||||||
|
#Can only be in third position, no need to go beyond
|
||||||
|
self._for_count += 1
|
||||||
|
if self._for_count==3:
|
||||||
|
self._for_count = None
|
||||||
|
|
||||||
|
self.on_token((self._token, self._type))
|
||||||
|
self._token = ''
|
||||||
|
self._type = TK_TOKEN
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def on_token(self, token):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
tokens = [
|
||||||
|
TK_TOKEN,
|
||||||
|
# To silence yacc unused token warnings
|
||||||
|
# TK_COMMENT,
|
||||||
|
TK_NEWLINE,
|
||||||
|
TK_IONUMBER,
|
||||||
|
TK_ASSIGNMENT,
|
||||||
|
TK_HERENAME,
|
||||||
|
]
|
||||||
|
|
||||||
|
#Add specific operators
|
||||||
|
tokens += _OPERATORS.values()
|
||||||
|
#Add reserved words
|
||||||
|
tokens += _RESERVEDS.values()
|
||||||
|
|
||||||
|
class PLYLexer(Lexer):
|
||||||
|
"""Bridge Lexer and PLY lexer interface."""
|
||||||
|
def __init__(self):
|
||||||
|
Lexer.__init__(self)
|
||||||
|
self._tokens = []
|
||||||
|
self._current = 0
|
||||||
|
self.lineno = 0
|
||||||
|
|
||||||
|
def on_token(self, token):
|
||||||
|
value, type = token
|
||||||
|
|
||||||
|
self.lineno = 0
|
||||||
|
t = lex.LexToken()
|
||||||
|
t.value = value
|
||||||
|
t.type = type
|
||||||
|
t.lexer = self
|
||||||
|
t.lexpos = 0
|
||||||
|
t.lineno = 0
|
||||||
|
|
||||||
|
self._tokens.append(t)
|
||||||
|
|
||||||
|
def is_empty(self):
|
||||||
|
return not bool(self._tokens)
|
||||||
|
|
||||||
|
#PLY compliant interface
|
||||||
|
def token(self):
|
||||||
|
if self._current>=len(self._tokens):
|
||||||
|
return None
|
||||||
|
t = self._tokens[self._current]
|
||||||
|
self._current += 1
|
||||||
|
return t
|
||||||
|
|
||||||
|
|
||||||
|
def get_tokens(s):
|
||||||
|
"""Parse the input string and return a tuple (tokens, unprocessed) where
|
||||||
|
tokens is a list of parsed tokens and unprocessed is the part of the input
|
||||||
|
string left untouched by the lexer.
|
||||||
|
"""
|
||||||
|
lexer = PLYLexer()
|
||||||
|
untouched = lexer.add(s, True)
|
||||||
|
tokens = []
|
||||||
|
while 1:
|
||||||
|
token = lexer.token()
|
||||||
|
if token is None:
|
||||||
|
break
|
||||||
|
tokens.append(token)
|
||||||
|
|
||||||
|
tokens = [(t.value, t.type) for t in tokens]
|
||||||
|
return tokens, untouched
|
||||||
772
bitbake/lib/pysh/pyshyacc.py
Normal file
@@ -0,0 +1,772 @@
|
|||||||
|
# pyshyacc.py - PLY grammar definition for pysh
|
||||||
|
#
|
||||||
|
# Copyright 2007 Patrick Mezard
|
||||||
|
#
|
||||||
|
# This software may be used and distributed according to the terms
|
||||||
|
# of the GNU General Public License, incorporated herein by reference.
|
||||||
|
|
||||||
|
"""PLY grammar file.
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pyshlex
|
||||||
|
tokens = pyshlex.tokens
|
||||||
|
|
||||||
|
from ply import yacc
|
||||||
|
import sherrors
|
||||||
|
|
||||||
|
class IORedirect:
|
||||||
|
def __init__(self, op, filename, io_number=None):
|
||||||
|
self.op = op
|
||||||
|
self.filename = filename
|
||||||
|
self.io_number = io_number
|
||||||
|
|
||||||
|
class HereDocument:
|
||||||
|
def __init__(self, op, name, content, io_number=None):
|
||||||
|
self.op = op
|
||||||
|
self.name = name
|
||||||
|
self.content = content
|
||||||
|
self.io_number = io_number
|
||||||
|
|
||||||
|
def make_io_redirect(p):
|
||||||
|
"""Make an IORedirect instance from the input 'io_redirect' production."""
|
||||||
|
name, io_number, io_target = p
|
||||||
|
assert name=='io_redirect'
|
||||||
|
|
||||||
|
if io_target[0]=='io_file':
|
||||||
|
io_type, io_op, io_file = io_target
|
||||||
|
return IORedirect(io_op, io_file, io_number)
|
||||||
|
elif io_target[0]=='io_here':
|
||||||
|
io_type, io_op, io_name, io_content = io_target
|
||||||
|
return HereDocument(io_op, io_name, io_content, io_number)
|
||||||
|
else:
|
||||||
|
assert False, "Invalid IO redirection token %s" % repr(io_type)
|
||||||
|
|
||||||
|
class SimpleCommand:
|
||||||
|
"""
|
||||||
|
assigns contains (name, value) pairs.
|
||||||
|
"""
|
||||||
|
def __init__(self, words, redirs, assigns):
|
||||||
|
self.words = list(words)
|
||||||
|
self.redirs = list(redirs)
|
||||||
|
self.assigns = list(assigns)
|
||||||
|
|
||||||
|
class Pipeline:
|
||||||
|
def __init__(self, commands, reverse_status=False):
|
||||||
|
self.commands = list(commands)
|
||||||
|
assert self.commands #Grammar forbids this
|
||||||
|
self.reverse_status = reverse_status
|
||||||
|
|
||||||
|
class AndOr:
|
||||||
|
def __init__(self, op, left, right):
|
||||||
|
self.op = str(op)
|
||||||
|
self.left = left
|
||||||
|
self.right = right
|
||||||
|
|
||||||
|
class ForLoop:
|
||||||
|
def __init__(self, name, items, cmds):
|
||||||
|
self.name = str(name)
|
||||||
|
self.items = list(items)
|
||||||
|
self.cmds = list(cmds)
|
||||||
|
|
||||||
|
class WhileLoop:
|
||||||
|
def __init__(self, condition, cmds):
|
||||||
|
self.condition = list(condition)
|
||||||
|
self.cmds = list(cmds)
|
||||||
|
|
||||||
|
class UntilLoop:
|
||||||
|
def __init__(self, condition, cmds):
|
||||||
|
self.condition = list(condition)
|
||||||
|
self.cmds = list(cmds)
|
||||||
|
|
||||||
|
class FunDef:
|
||||||
|
def __init__(self, name, body):
|
||||||
|
self.name = str(name)
|
||||||
|
self.body = body
|
||||||
|
|
||||||
|
class BraceGroup:
|
||||||
|
def __init__(self, cmds):
|
||||||
|
self.cmds = list(cmds)
|
||||||
|
|
||||||
|
class IfCond:
|
||||||
|
def __init__(self, cond, if_cmds, else_cmds):
|
||||||
|
self.cond = list(cond)
|
||||||
|
self.if_cmds = if_cmds
|
||||||
|
self.else_cmds = else_cmds
|
||||||
|
|
||||||
|
class Case:
|
||||||
|
def __init__(self, name, items):
|
||||||
|
self.name = name
|
||||||
|
self.items = items
|
||||||
|
|
||||||
|
class SubShell:
|
||||||
|
def __init__(self, cmds):
|
||||||
|
self.cmds = cmds
|
||||||
|
|
||||||
|
class RedirectList:
|
||||||
|
def __init__(self, cmd, redirs):
|
||||||
|
self.cmd = cmd
|
||||||
|
self.redirs = list(redirs)
|
||||||
|
|
||||||
|
def get_production(productions, ptype):
|
||||||
|
"""productions must be a list of production tuples like (name, obj) where
|
||||||
|
name is the production string identifier.
|
||||||
|
Return the first production named 'ptype'. Raise KeyError if None can be
|
||||||
|
found.
|
||||||
|
"""
|
||||||
|
for production in productions:
|
||||||
|
if production is not None and production[0]==ptype:
|
||||||
|
return production
|
||||||
|
raise KeyError(ptype)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# PLY grammar definition
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def p_multiple_commands(p):
|
||||||
|
"""multiple_commands : newline_sequence
|
||||||
|
| complete_command
|
||||||
|
| multiple_commands complete_command"""
|
||||||
|
if len(p)==2:
|
||||||
|
if p[1] is not None:
|
||||||
|
p[0] = [p[1]]
|
||||||
|
else:
|
||||||
|
p[0] = []
|
||||||
|
else:
|
||||||
|
p[0] = p[1] + [p[2]]
|
||||||
|
|
||||||
|
def p_complete_command(p):
|
||||||
|
"""complete_command : list separator
|
||||||
|
| list"""
|
||||||
|
if len(p)==3 and p[2] and p[2][1] == '&':
|
||||||
|
p[0] = ('async', p[1])
|
||||||
|
else:
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_list(p):
|
||||||
|
"""list : list separator_op and_or
|
||||||
|
| and_or"""
|
||||||
|
if len(p)==2:
|
||||||
|
p[0] = [p[1]]
|
||||||
|
else:
|
||||||
|
#if p[2]!=';':
|
||||||
|
# raise NotImplementedError('AND-OR list asynchronous execution is not implemented')
|
||||||
|
p[0] = p[1] + [p[3]]
|
||||||
|
|
||||||
|
def p_and_or(p):
|
||||||
|
"""and_or : pipeline
|
||||||
|
| and_or AND_IF linebreak pipeline
|
||||||
|
| and_or OR_IF linebreak pipeline"""
|
||||||
|
if len(p)==2:
|
||||||
|
p[0] = p[1]
|
||||||
|
else:
|
||||||
|
p[0] = ('and_or', AndOr(p[2], p[1], p[4]))
|
||||||
|
|
||||||
|
def p_maybe_bang_word(p):
|
||||||
|
"""maybe_bang_word : Bang"""
|
||||||
|
p[0] = ('maybe_bang_word', p[1])
|
||||||
|
|
||||||
|
def p_pipeline(p):
|
||||||
|
"""pipeline : pipe_sequence
|
||||||
|
| bang_word pipe_sequence"""
|
||||||
|
if len(p)==3:
|
||||||
|
p[0] = ('pipeline', Pipeline(p[2][1:], True))
|
||||||
|
else:
|
||||||
|
p[0] = ('pipeline', Pipeline(p[1][1:]))
|
||||||
|
|
||||||
|
def p_pipe_sequence(p):
|
||||||
|
"""pipe_sequence : command
|
||||||
|
| pipe_sequence PIPE linebreak command"""
|
||||||
|
if len(p)==2:
|
||||||
|
p[0] = ['pipe_sequence', p[1]]
|
||||||
|
else:
|
||||||
|
p[0] = p[1] + [p[4]]
|
||||||
|
|
||||||
|
def p_command(p):
|
||||||
|
"""command : simple_command
|
||||||
|
| compound_command
|
||||||
|
| compound_command redirect_list
|
||||||
|
| function_definition"""
|
||||||
|
|
||||||
|
if p[1][0] in ( 'simple_command',
|
||||||
|
'for_clause',
|
||||||
|
'while_clause',
|
||||||
|
'until_clause',
|
||||||
|
'case_clause',
|
||||||
|
'if_clause',
|
||||||
|
'function_definition',
|
||||||
|
'subshell',
|
||||||
|
'brace_group',):
|
||||||
|
if len(p) == 2:
|
||||||
|
p[0] = p[1]
|
||||||
|
else:
|
||||||
|
p[0] = ('redirect_list', RedirectList(p[1], p[2][1:]))
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('%s command is not implemented' % repr(p[1][0]))
|
||||||
|
|
||||||
|
def p_compound_command(p):
|
||||||
|
"""compound_command : brace_group
|
||||||
|
| subshell
|
||||||
|
| for_clause
|
||||||
|
| case_clause
|
||||||
|
| if_clause
|
||||||
|
| while_clause
|
||||||
|
| until_clause"""
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_subshell(p):
|
||||||
|
"""subshell : LPARENS compound_list RPARENS"""
|
||||||
|
p[0] = ('subshell', SubShell(p[2][1:]))
|
||||||
|
|
||||||
|
def p_compound_list(p):
|
||||||
|
"""compound_list : term
|
||||||
|
| newline_list term
|
||||||
|
| term separator
|
||||||
|
| newline_list term separator"""
|
||||||
|
productions = p[1:]
|
||||||
|
try:
|
||||||
|
sep = get_production(productions, 'separator')
|
||||||
|
if sep[1]!=';':
|
||||||
|
raise NotImplementedError()
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
term = get_production(productions, 'term')
|
||||||
|
p[0] = ['compound_list'] + term[1:]
|
||||||
|
|
||||||
|
def p_term(p):
|
||||||
|
"""term : term separator and_or
|
||||||
|
| and_or"""
|
||||||
|
if len(p)==2:
|
||||||
|
p[0] = ['term', p[1]]
|
||||||
|
else:
|
||||||
|
if p[2] is not None and p[2][1] == '&':
|
||||||
|
p[0] = ['term', ('async', p[1][1:])] + [p[3]]
|
||||||
|
else:
|
||||||
|
p[0] = p[1] + [p[3]]
|
||||||
|
|
||||||
|
def p_maybe_for_word(p):
|
||||||
|
# Rearrange 'For' priority wrt TOKEN. See p_for_word
|
||||||
|
"""maybe_for_word : For"""
|
||||||
|
p[0] = ('maybe_for_word', p[1])
|
||||||
|
|
||||||
|
def p_for_clause(p):
|
||||||
|
"""for_clause : for_word name linebreak do_group
|
||||||
|
| for_word name linebreak in sequential_sep do_group
|
||||||
|
| for_word name linebreak in wordlist sequential_sep do_group"""
|
||||||
|
productions = p[1:]
|
||||||
|
do_group = get_production(productions, 'do_group')
|
||||||
|
try:
|
||||||
|
items = get_production(productions, 'in')[1:]
|
||||||
|
except KeyError:
|
||||||
|
raise NotImplementedError('"in" omission is not implemented')
|
||||||
|
|
||||||
|
try:
|
||||||
|
items = get_production(productions, 'wordlist')[1:]
|
||||||
|
except KeyError:
|
||||||
|
items = []
|
||||||
|
|
||||||
|
name = p[2]
|
||||||
|
p[0] = ('for_clause', ForLoop(name, items, do_group[1:]))
|
||||||
|
|
||||||
|
def p_name(p):
|
||||||
|
"""name : token""" #Was NAME instead of token
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_in(p):
|
||||||
|
"""in : In"""
|
||||||
|
p[0] = ('in', p[1])
|
||||||
|
|
||||||
|
def p_wordlist(p):
|
||||||
|
"""wordlist : wordlist token
|
||||||
|
| token"""
|
||||||
|
if len(p)==2:
|
||||||
|
p[0] = ['wordlist', ('TOKEN', p[1])]
|
||||||
|
else:
|
||||||
|
p[0] = p[1] + [('TOKEN', p[2])]
|
||||||
|
|
||||||
|
def p_case_clause(p):
|
||||||
|
"""case_clause : Case token linebreak in linebreak case_list Esac
|
||||||
|
| Case token linebreak in linebreak case_list_ns Esac
|
||||||
|
| Case token linebreak in linebreak Esac"""
|
||||||
|
if len(p) < 8:
|
||||||
|
items = []
|
||||||
|
else:
|
||||||
|
items = p[6][1:]
|
||||||
|
name = p[2]
|
||||||
|
p[0] = ('case_clause', Case(name, [c[1] for c in items]))
|
||||||
|
|
||||||
|
def p_case_list_ns(p):
|
||||||
|
"""case_list_ns : case_list case_item_ns
|
||||||
|
| case_item_ns"""
|
||||||
|
p_case_list(p)
|
||||||
|
|
||||||
|
def p_case_list(p):
|
||||||
|
"""case_list : case_list case_item
|
||||||
|
| case_item"""
|
||||||
|
if len(p)==2:
|
||||||
|
p[0] = ['case_list', p[1]]
|
||||||
|
else:
|
||||||
|
p[0] = p[1] + [p[2]]
|
||||||
|
|
||||||
|
def p_case_item_ns(p):
|
||||||
|
"""case_item_ns : pattern RPARENS linebreak
|
||||||
|
| pattern RPARENS compound_list linebreak
|
||||||
|
| LPARENS pattern RPARENS linebreak
|
||||||
|
| LPARENS pattern RPARENS compound_list linebreak"""
|
||||||
|
p_case_item(p)
|
||||||
|
|
||||||
|
def p_case_item(p):
|
||||||
|
"""case_item : pattern RPARENS linebreak DSEMI linebreak
|
||||||
|
| pattern RPARENS compound_list DSEMI linebreak
|
||||||
|
| LPARENS pattern RPARENS linebreak DSEMI linebreak
|
||||||
|
| LPARENS pattern RPARENS compound_list DSEMI linebreak"""
|
||||||
|
if len(p) < 7:
|
||||||
|
name = p[1][1:]
|
||||||
|
else:
|
||||||
|
name = p[2][1:]
|
||||||
|
|
||||||
|
try:
|
||||||
|
cmds = get_production(p[1:], "compound_list")[1:]
|
||||||
|
except KeyError:
|
||||||
|
cmds = []
|
||||||
|
|
||||||
|
p[0] = ('case_item', (name, cmds))
|
||||||
|
|
||||||
|
def p_pattern(p):
|
||||||
|
"""pattern : token
|
||||||
|
| pattern PIPE token"""
|
||||||
|
if len(p)==2:
|
||||||
|
p[0] = ['pattern', ('TOKEN', p[1])]
|
||||||
|
else:
|
||||||
|
p[0] = p[1] + [('TOKEN', p[2])]
|
||||||
|
|
||||||
|
def p_maybe_if_word(p):
|
||||||
|
# Rearrange 'If' priority wrt TOKEN. See p_if_word
|
||||||
|
"""maybe_if_word : If"""
|
||||||
|
p[0] = ('maybe_if_word', p[1])
|
||||||
|
|
||||||
|
def p_maybe_then_word(p):
|
||||||
|
# Rearrange 'Then' priority wrt TOKEN. See p_then_word
|
||||||
|
"""maybe_then_word : Then"""
|
||||||
|
p[0] = ('maybe_then_word', p[1])
|
||||||
|
|
||||||
|
def p_if_clause(p):
|
||||||
|
"""if_clause : if_word compound_list then_word compound_list else_part Fi
|
||||||
|
| if_word compound_list then_word compound_list Fi"""
|
||||||
|
else_part = []
|
||||||
|
if len(p)==7:
|
||||||
|
else_part = p[5]
|
||||||
|
p[0] = ('if_clause', IfCond(p[2][1:], p[4][1:], else_part))
|
||||||
|
|
||||||
|
def p_else_part(p):
|
||||||
|
"""else_part : Elif compound_list then_word compound_list else_part
|
||||||
|
| Elif compound_list then_word compound_list
|
||||||
|
| Else compound_list"""
|
||||||
|
if len(p)==3:
|
||||||
|
p[0] = p[2][1:]
|
||||||
|
else:
|
||||||
|
else_part = []
|
||||||
|
if len(p)==6:
|
||||||
|
else_part = p[5]
|
||||||
|
p[0] = ('elif', IfCond(p[2][1:], p[4][1:], else_part))
|
||||||
|
|
||||||
|
def p_while_clause(p):
|
||||||
|
"""while_clause : While compound_list do_group"""
|
||||||
|
p[0] = ('while_clause', WhileLoop(p[2][1:], p[3][1:]))
|
||||||
|
|
||||||
|
def p_maybe_until_word(p):
|
||||||
|
# Rearrange 'Until' priority wrt TOKEN. See p_until_word
|
||||||
|
"""maybe_until_word : Until"""
|
||||||
|
p[0] = ('maybe_until_word', p[1])
|
||||||
|
|
||||||
|
def p_until_clause(p):
|
||||||
|
"""until_clause : until_word compound_list do_group"""
|
||||||
|
p[0] = ('until_clause', UntilLoop(p[2][1:], p[3][1:]))
|
||||||
|
|
||||||
|
def p_function_definition(p):
|
||||||
|
"""function_definition : fname LPARENS RPARENS linebreak function_body"""
|
||||||
|
p[0] = ('function_definition', FunDef(p[1], p[5]))
|
||||||
|
|
||||||
|
def p_function_body(p):
|
||||||
|
"""function_body : compound_command
|
||||||
|
| compound_command redirect_list"""
|
||||||
|
if len(p)!=2:
|
||||||
|
raise NotImplementedError('functions redirections lists are not implemented')
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_fname(p):
|
||||||
|
"""fname : TOKEN""" #Was NAME instead of token
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_brace_group(p):
|
||||||
|
"""brace_group : Lbrace compound_list Rbrace"""
|
||||||
|
p[0] = ('brace_group', BraceGroup(p[2][1:]))
|
||||||
|
|
||||||
|
def p_maybe_done_word(p):
|
||||||
|
#See p_assignment_word for details.
|
||||||
|
"""maybe_done_word : Done"""
|
||||||
|
p[0] = ('maybe_done_word', p[1])
|
||||||
|
|
||||||
|
def p_maybe_do_word(p):
|
||||||
|
"""maybe_do_word : Do"""
|
||||||
|
p[0] = ('maybe_do_word', p[1])
|
||||||
|
|
||||||
|
def p_do_group(p):
|
||||||
|
"""do_group : do_word compound_list done_word"""
|
||||||
|
#Do group contains a list of AndOr
|
||||||
|
p[0] = ['do_group'] + p[2][1:]
|
||||||
|
|
||||||
|
def p_simple_command(p):
|
||||||
|
"""simple_command : cmd_prefix cmd_word cmd_suffix
|
||||||
|
| cmd_prefix cmd_word
|
||||||
|
| cmd_prefix
|
||||||
|
| cmd_name cmd_suffix
|
||||||
|
| cmd_name"""
|
||||||
|
words, redirs, assigns = [], [], []
|
||||||
|
for e in p[1:]:
|
||||||
|
name = e[0]
|
||||||
|
if name in ('cmd_prefix', 'cmd_suffix'):
|
||||||
|
for sube in e[1:]:
|
||||||
|
subname = sube[0]
|
||||||
|
if subname=='io_redirect':
|
||||||
|
redirs.append(make_io_redirect(sube))
|
||||||
|
elif subname=='ASSIGNMENT_WORD':
|
||||||
|
assigns.append(sube)
|
||||||
|
else:
|
||||||
|
words.append(sube)
|
||||||
|
elif name in ('cmd_word', 'cmd_name'):
|
||||||
|
words.append(e)
|
||||||
|
|
||||||
|
cmd = SimpleCommand(words, redirs, assigns)
|
||||||
|
p[0] = ('simple_command', cmd)
|
||||||
|
|
||||||
|
def p_cmd_name(p):
|
||||||
|
"""cmd_name : TOKEN"""
|
||||||
|
p[0] = ('cmd_name', p[1])
|
||||||
|
|
||||||
|
def p_cmd_word(p):
|
||||||
|
"""cmd_word : token"""
|
||||||
|
p[0] = ('cmd_word', p[1])
|
||||||
|
|
||||||
|
def p_maybe_assignment_word(p):
|
||||||
|
#See p_assignment_word for details.
|
||||||
|
"""maybe_assignment_word : ASSIGNMENT_WORD"""
|
||||||
|
p[0] = ('maybe_assignment_word', p[1])
|
||||||
|
|
||||||
|
def p_cmd_prefix(p):
|
||||||
|
"""cmd_prefix : io_redirect
|
||||||
|
| cmd_prefix io_redirect
|
||||||
|
| assignment_word
|
||||||
|
| cmd_prefix assignment_word"""
|
||||||
|
try:
|
||||||
|
prefix = get_production(p[1:], 'cmd_prefix')
|
||||||
|
except KeyError:
|
||||||
|
prefix = ['cmd_prefix']
|
||||||
|
|
||||||
|
try:
|
||||||
|
value = get_production(p[1:], 'assignment_word')[1]
|
||||||
|
value = ('ASSIGNMENT_WORD', value.split('=', 1))
|
||||||
|
except KeyError:
|
||||||
|
value = get_production(p[1:], 'io_redirect')
|
||||||
|
p[0] = prefix + [value]
|
||||||
|
|
||||||
|
def p_cmd_suffix(p):
|
||||||
|
"""cmd_suffix : io_redirect
|
||||||
|
| cmd_suffix io_redirect
|
||||||
|
| token
|
||||||
|
| cmd_suffix token
|
||||||
|
| maybe_for_word
|
||||||
|
| cmd_suffix maybe_for_word
|
||||||
|
| maybe_done_word
|
||||||
|
| cmd_suffix maybe_done_word
|
||||||
|
| maybe_do_word
|
||||||
|
| cmd_suffix maybe_do_word
|
||||||
|
| maybe_until_word
|
||||||
|
| cmd_suffix maybe_until_word
|
||||||
|
| maybe_assignment_word
|
||||||
|
| cmd_suffix maybe_assignment_word
|
||||||
|
| maybe_if_word
|
||||||
|
| cmd_suffix maybe_if_word
|
||||||
|
| maybe_then_word
|
||||||
|
| cmd_suffix maybe_then_word
|
||||||
|
| maybe_bang_word
|
||||||
|
| cmd_suffix maybe_bang_word"""
|
||||||
|
try:
|
||||||
|
suffix = get_production(p[1:], 'cmd_suffix')
|
||||||
|
token = p[2]
|
||||||
|
except KeyError:
|
||||||
|
suffix = ['cmd_suffix']
|
||||||
|
token = p[1]
|
||||||
|
|
||||||
|
if isinstance(token, tuple):
|
||||||
|
if token[0]=='io_redirect':
|
||||||
|
p[0] = suffix + [token]
|
||||||
|
else:
|
||||||
|
#Convert maybe_* to TOKEN if necessary
|
||||||
|
p[0] = suffix + [('TOKEN', token[1])]
|
||||||
|
else:
|
||||||
|
p[0] = suffix + [('TOKEN', token)]
|
||||||
|
|
||||||
|
def p_redirect_list(p):
|
||||||
|
"""redirect_list : io_redirect
|
||||||
|
| redirect_list io_redirect"""
|
||||||
|
if len(p) == 2:
|
||||||
|
p[0] = ['redirect_list', make_io_redirect(p[1])]
|
||||||
|
else:
|
||||||
|
p[0] = p[1] + [make_io_redirect(p[2])]
|
||||||
|
|
||||||
|
def p_io_redirect(p):
|
||||||
|
"""io_redirect : io_file
|
||||||
|
| IO_NUMBER io_file
|
||||||
|
| io_here
|
||||||
|
| IO_NUMBER io_here"""
|
||||||
|
if len(p)==3:
|
||||||
|
p[0] = ('io_redirect', p[1], p[2])
|
||||||
|
else:
|
||||||
|
p[0] = ('io_redirect', None, p[1])
|
||||||
|
|
||||||
|
def p_io_file(p):
|
||||||
|
#Return the tuple (operator, filename)
|
||||||
|
"""io_file : LESS filename
|
||||||
|
| LESSAND filename
|
||||||
|
| GREATER filename
|
||||||
|
| GREATAND filename
|
||||||
|
| DGREAT filename
|
||||||
|
| LESSGREAT filename
|
||||||
|
| CLOBBER filename"""
|
||||||
|
#Extract the filename from the file
|
||||||
|
p[0] = ('io_file', p[1], p[2][1])
|
||||||
|
|
||||||
|
def p_filename(p):
|
||||||
|
#Return the filename
|
||||||
|
"""filename : TOKEN"""
|
||||||
|
p[0] = ('filename', p[1])
|
||||||
|
|
||||||
|
def p_io_here(p):
|
||||||
|
"""io_here : DLESS here_end
|
||||||
|
| DLESSDASH here_end"""
|
||||||
|
p[0] = ('io_here', p[1], p[2][1], p[2][2])
|
||||||
|
|
||||||
|
def p_here_end(p):
|
||||||
|
"""here_end : HERENAME TOKEN"""
|
||||||
|
p[0] = ('here_document', p[1], p[2])
|
||||||
|
|
||||||
|
def p_newline_sequence(p):
|
||||||
|
# Nothing in the grammar can handle leading NEWLINE productions, so add
|
||||||
|
# this one with the lowest possible priority relatively to newline_list.
|
||||||
|
"""newline_sequence : newline_list"""
|
||||||
|
p[0] = None
|
||||||
|
|
||||||
|
def p_newline_list(p):
|
||||||
|
"""newline_list : NEWLINE
|
||||||
|
| newline_list NEWLINE"""
|
||||||
|
p[0] = None
|
||||||
|
|
||||||
|
def p_linebreak(p):
|
||||||
|
"""linebreak : newline_list
|
||||||
|
| empty"""
|
||||||
|
p[0] = None
|
||||||
|
|
||||||
|
def p_separator_op(p):
|
||||||
|
"""separator_op : COMMA
|
||||||
|
| AMP"""
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_separator(p):
|
||||||
|
"""separator : separator_op linebreak
|
||||||
|
| newline_list"""
|
||||||
|
if len(p)==2:
|
||||||
|
#Ignore newlines
|
||||||
|
p[0] = None
|
||||||
|
else:
|
||||||
|
#Keep the separator operator
|
||||||
|
p[0] = ('separator', p[1])
|
||||||
|
|
||||||
|
def p_sequential_sep(p):
|
||||||
|
"""sequential_sep : COMMA linebreak
|
||||||
|
| newline_list"""
|
||||||
|
p[0] = None
|
||||||
|
|
||||||
|
# Low priority TOKEN => for_word conversion.
|
||||||
|
# Let maybe_for_word be used as a token when necessary in higher priority
|
||||||
|
# rules.
|
||||||
|
def p_for_word(p):
|
||||||
|
"""for_word : maybe_for_word"""
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_if_word(p):
|
||||||
|
"""if_word : maybe_if_word"""
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_then_word(p):
|
||||||
|
"""then_word : maybe_then_word"""
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_done_word(p):
|
||||||
|
"""done_word : maybe_done_word"""
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_do_word(p):
|
||||||
|
"""do_word : maybe_do_word"""
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_until_word(p):
|
||||||
|
"""until_word : maybe_until_word"""
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_assignment_word(p):
|
||||||
|
"""assignment_word : maybe_assignment_word"""
|
||||||
|
p[0] = ('assignment_word', p[1][1])
|
||||||
|
|
||||||
|
def p_bang_word(p):
|
||||||
|
"""bang_word : maybe_bang_word"""
|
||||||
|
p[0] = ('bang_word', p[1][1])
|
||||||
|
|
||||||
|
def p_token(p):
|
||||||
|
"""token : TOKEN
|
||||||
|
| Fi"""
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_empty(p):
|
||||||
|
'empty :'
|
||||||
|
p[0] = None
|
||||||
|
|
||||||
|
# Error rule for syntax errors
|
||||||
|
def p_error(p):
|
||||||
|
msg = []
|
||||||
|
w = msg.append
|
||||||
|
w('%r\n' % p)
|
||||||
|
w('followed by:\n')
|
||||||
|
for i in range(5):
|
||||||
|
n = yacc.token()
|
||||||
|
if not n:
|
||||||
|
break
|
||||||
|
w(' %r\n' % n)
|
||||||
|
raise sherrors.ShellSyntaxError(''.join(msg))
|
||||||
|
|
||||||
|
# Build the parser
|
||||||
|
try:
|
||||||
|
import pyshtables
|
||||||
|
except ImportError:
|
||||||
|
yacc.yacc(tabmodule = 'pyshtables')
|
||||||
|
else:
|
||||||
|
yacc.yacc(tabmodule = 'pysh.pyshtables', write_tables = 0, debug = 0)
|
||||||
|
|
||||||
|
|
||||||
|
def parse(input, eof=False, debug=False):
|
||||||
|
"""Parse a whole script at once and return the generated AST and unconsumed
|
||||||
|
data in a tuple.
|
||||||
|
|
||||||
|
NOTE: eof is probably meaningless for now, the parser being unable to work
|
||||||
|
in pull mode. It should be set to True.
|
||||||
|
"""
|
||||||
|
lexer = pyshlex.PLYLexer()
|
||||||
|
remaining = lexer.add(input, eof)
|
||||||
|
if lexer.is_empty():
|
||||||
|
return [], remaining
|
||||||
|
if debug:
|
||||||
|
debug = 2
|
||||||
|
return yacc.parse(lexer=lexer, debug=debug), remaining
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# AST rendering helpers
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def format_commands(v):
|
||||||
|
"""Return a tree made of strings and lists. Make command trees easier to
|
||||||
|
display.
|
||||||
|
"""
|
||||||
|
if isinstance(v, list):
|
||||||
|
return [format_commands(c) for c in v]
|
||||||
|
if isinstance(v, tuple):
|
||||||
|
if len(v)==2 and isinstance(v[0], str) and not isinstance(v[1], str):
|
||||||
|
if v[0] == 'async':
|
||||||
|
return ['AsyncList', map(format_commands, v[1])]
|
||||||
|
else:
|
||||||
|
#Avoid decomposing tuples like ('pipeline', Pipeline(...))
|
||||||
|
return format_commands(v[1])
|
||||||
|
return format_commands(list(v))
|
||||||
|
elif isinstance(v, IfCond):
|
||||||
|
name = ['IfCond']
|
||||||
|
name += ['if', map(format_commands, v.cond)]
|
||||||
|
name += ['then', map(format_commands, v.if_cmds)]
|
||||||
|
name += ['else', map(format_commands, v.else_cmds)]
|
||||||
|
return name
|
||||||
|
elif isinstance(v, ForLoop):
|
||||||
|
name = ['ForLoop']
|
||||||
|
name += [repr(v.name)+' in ', map(str, v.items)]
|
||||||
|
name += ['commands', map(format_commands, v.cmds)]
|
||||||
|
return name
|
||||||
|
elif isinstance(v, AndOr):
|
||||||
|
return [v.op, format_commands(v.left), format_commands(v.right)]
|
||||||
|
elif isinstance(v, Pipeline):
|
||||||
|
name = 'Pipeline'
|
||||||
|
if v.reverse_status:
|
||||||
|
name = '!' + name
|
||||||
|
return [name, format_commands(v.commands)]
|
||||||
|
elif isinstance(v, SimpleCommand):
|
||||||
|
name = ['SimpleCommand']
|
||||||
|
if v.words:
|
||||||
|
name += ['words', map(str, v.words)]
|
||||||
|
if v.assigns:
|
||||||
|
assigns = [tuple(a[1]) for a in v.assigns]
|
||||||
|
name += ['assigns', map(str, assigns)]
|
||||||
|
if v.redirs:
|
||||||
|
name += ['redirs', map(format_commands, v.redirs)]
|
||||||
|
return name
|
||||||
|
elif isinstance(v, RedirectList):
|
||||||
|
name = ['RedirectList']
|
||||||
|
if v.redirs:
|
||||||
|
name += ['redirs', map(format_commands, v.redirs)]
|
||||||
|
name += ['command', format_commands(v.cmd)]
|
||||||
|
return name
|
||||||
|
elif isinstance(v, IORedirect):
|
||||||
|
return ' '.join(map(str, (v.io_number, v.op, v.filename)))
|
||||||
|
elif isinstance(v, HereDocument):
|
||||||
|
return ' '.join(map(str, (v.io_number, v.op, repr(v.name), repr(v.content))))
|
||||||
|
elif isinstance(v, SubShell):
|
||||||
|
return ['SubShell', map(format_commands, v.cmds)]
|
||||||
|
else:
|
||||||
|
return repr(v)
|
||||||
|
|
||||||
|
def print_commands(cmds, output=sys.stdout):
|
||||||
|
"""Pretty print a command tree."""
|
||||||
|
def print_tree(cmd, spaces, output):
|
||||||
|
if isinstance(cmd, list):
|
||||||
|
for c in cmd:
|
||||||
|
print_tree(c, spaces + 3, output)
|
||||||
|
else:
|
||||||
|
print >>output, ' '*spaces + str(cmd)
|
||||||
|
|
||||||
|
formatted = format_commands(cmds)
|
||||||
|
print_tree(formatted, 0, output)
|
||||||
|
|
||||||
|
|
||||||
|
def stringify_commands(cmds):
|
||||||
|
"""Serialize a command tree as a string.
|
||||||
|
|
||||||
|
Returned string is not pretty and is currently used for unit tests only.
|
||||||
|
"""
|
||||||
|
def stringify(value):
|
||||||
|
output = []
|
||||||
|
if isinstance(value, list):
|
||||||
|
formatted = []
|
||||||
|
for v in value:
|
||||||
|
formatted.append(stringify(v))
|
||||||
|
formatted = ' '.join(formatted)
|
||||||
|
output.append(''.join(['<', formatted, '>']))
|
||||||
|
else:
|
||||||
|
output.append(value)
|
||||||
|
return ' '.join(output)
|
||||||
|
|
||||||
|
return stringify(format_commands(cmds))
|
||||||
|
|
||||||
|
|
||||||
|
def visit_commands(cmds, callable):
|
||||||
|
"""Visit the command tree and execute callable on every Pipeline and
|
||||||
|
SimpleCommand instances.
|
||||||
|
"""
|
||||||
|
if isinstance(cmds, (tuple, list)):
|
||||||
|
map(lambda c: visit_commands(c,callable), cmds)
|
||||||
|
elif isinstance(cmds, (Pipeline, SimpleCommand)):
|
||||||
|
callable(cmds)
|
||||||
41
bitbake/lib/pysh/sherrors.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# sherrors.py - shell errors and signals
|
||||||
|
#
|
||||||
|
# Copyright 2007 Patrick Mezard
|
||||||
|
#
|
||||||
|
# This software may be used and distributed according to the terms
|
||||||
|
# of the GNU General Public License, incorporated herein by reference.
|
||||||
|
|
||||||
|
"""Define shell exceptions and error codes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class ShellError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ShellSyntaxError(ShellError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class UtilityError(ShellError):
|
||||||
|
"""Raised upon utility syntax error (option or operand error)."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ExpansionError(ShellError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class CommandNotFound(ShellError):
|
||||||
|
"""Specified command was not found."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class RedirectionError(ShellError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class VarAssignmentError(ShellError):
|
||||||
|
"""Variable assignment error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ExitSignal(ShellError):
|
||||||
|
"""Exit signal."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ReturnSignal(ShellError):
|
||||||
|
"""Exit signal."""
|
||||||
|
pass
|
||||||
77
bitbake/lib/pysh/subprocess_fix.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# subprocess - Subprocesses with accessible I/O streams
|
||||||
|
#
|
||||||
|
# For more information about this module, see PEP 324.
|
||||||
|
#
|
||||||
|
# This module should remain compatible with Python 2.2, see PEP 291.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2003-2005 by Peter Astrand <astrand@lysator.liu.se>
|
||||||
|
#
|
||||||
|
# Licensed to PSF under a Contributor Agreement.
|
||||||
|
# See http://www.python.org/2.4/license for licensing details.
|
||||||
|
|
||||||
|
def list2cmdline(seq):
|
||||||
|
"""
|
||||||
|
Translate a sequence of arguments into a command line
|
||||||
|
string, using the same rules as the MS C runtime:
|
||||||
|
|
||||||
|
1) Arguments are delimited by white space, which is either a
|
||||||
|
space or a tab.
|
||||||
|
|
||||||
|
2) A string surrounded by double quotation marks is
|
||||||
|
interpreted as a single argument, regardless of white space
|
||||||
|
contained within. A quoted string can be embedded in an
|
||||||
|
argument.
|
||||||
|
|
||||||
|
3) A double quotation mark preceded by a backslash is
|
||||||
|
interpreted as a literal double quotation mark.
|
||||||
|
|
||||||
|
4) Backslashes are interpreted literally, unless they
|
||||||
|
immediately precede a double quotation mark.
|
||||||
|
|
||||||
|
5) If backslashes immediately precede a double quotation mark,
|
||||||
|
every pair of backslashes is interpreted as a literal
|
||||||
|
backslash. If the number of backslashes is odd, the last
|
||||||
|
backslash escapes the next double quotation mark as
|
||||||
|
described in rule 3.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# See
|
||||||
|
# http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
|
||||||
|
result = []
|
||||||
|
needquote = False
|
||||||
|
for arg in seq:
|
||||||
|
bs_buf = []
|
||||||
|
|
||||||
|
# Add a space to separate this argument from the others
|
||||||
|
if result:
|
||||||
|
result.append(' ')
|
||||||
|
|
||||||
|
needquote = (" " in arg) or ("\t" in arg) or ("|" in arg) or arg == ""
|
||||||
|
if needquote:
|
||||||
|
result.append('"')
|
||||||
|
|
||||||
|
for c in arg:
|
||||||
|
if c == '\\':
|
||||||
|
# Don't know if we need to double yet.
|
||||||
|
bs_buf.append(c)
|
||||||
|
elif c == '"':
|
||||||
|
# Double backspaces.
|
||||||
|
result.append('\\' * len(bs_buf)*2)
|
||||||
|
bs_buf = []
|
||||||
|
result.append('\\"')
|
||||||
|
else:
|
||||||
|
# Normal char
|
||||||
|
if bs_buf:
|
||||||
|
result.extend(bs_buf)
|
||||||
|
bs_buf = []
|
||||||
|
result.append(c)
|
||||||
|
|
||||||
|
# Add remaining backspaces, if any.
|
||||||
|
if bs_buf:
|
||||||
|
result.extend(bs_buf)
|
||||||
|
|
||||||
|
if needquote:
|
||||||
|
result.extend(bs_buf)
|
||||||
|
result.append('"')
|
||||||
|
|
||||||
|
return ''.join(result)
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
|
|
||||||
# changes incompatibly
|
|
||||||
LCONF_VERSION = "1"
|
|
||||||
|
|
||||||
BBFILES ?= ""
|
|
||||||
BBLAYERS = " \
|
|
||||||
${OEROOT}/meta \
|
|
||||||
${OEROOT}/meta-moblin \
|
|
||||||
"
|
|
||||||
38
documentation/poky-ref-manual/Makefile
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
all: html pdf tarball
|
||||||
|
|
||||||
|
pdf:
|
||||||
|
../tools/poky-docbook-to-pdf poky-ref-manual.xml ../template
|
||||||
|
../tools/poky-docbook-to-pdf bsp-guide.xml ../template
|
||||||
|
|
||||||
|
XSLTOPTS = --stringparam html.stylesheet style.css \
|
||||||
|
--stringparam chapter.autolabel 1 \
|
||||||
|
--stringparam appendix.autolabel A \
|
||||||
|
--stringparam section.autolabel 1 \
|
||||||
|
--stringparam section.label.includes.component.label 1 \
|
||||||
|
--xinclude
|
||||||
|
|
||||||
|
##
|
||||||
|
# These URI should be rewritten by your distribution's xml catalog to
|
||||||
|
# match your localy installed XSL stylesheets.
|
||||||
|
XSL_BASE_URI = http://docbook.sourceforge.net/release/xsl/current
|
||||||
|
XSL_XHTML_URI = $(XSL_BASE_URI)/xhtml/docbook.xsl
|
||||||
|
|
||||||
|
html:
|
||||||
|
# See http://www.sagehill.net/docbookxsl/HtmlOutput.html
|
||||||
|
xsltproc $(XSLTOPTS) -o poky-ref-manual.html $(XSL_XHTML_URI) poky-ref-manual.xml
|
||||||
|
xsltproc $(XSLTOPTS) -o bsp-guide.html $(XSL_XHTML_URI) bsp-guide.xml
|
||||||
|
|
||||||
|
tarball: html
|
||||||
|
tar -cvzf poky-ref-manual.tgz poky-ref-manual.html style.css figures/yocto-project-transp.png figures/poky-ref-manual.png
|
||||||
|
|
||||||
|
validate:
|
||||||
|
xmllint --postvalid --xinclude --noout poky-ref-manual.xml
|
||||||
|
|
||||||
|
OUTPUTS = poky-ref-manual.tgz poky-ref-manual.html poky-ref-manual.pdf bsp-guide.pdf bsp-guide.html
|
||||||
|
SOURCES = *.png *.xml *.css *.svg
|
||||||
|
|
||||||
|
publish:
|
||||||
|
scp -r $(OUTPUTS) $(SOURCES) o-hand.com:/srv/www/pokylinux.org/doc/
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OUTPUTS)
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<mediaobject>
|
<mediaobject>
|
||||||
<imageobject>
|
<imageobject>
|
||||||
<imagedata fileref='common/poky-handbook.png'
|
<imagedata fileref='poky-ref-manual.png'
|
||||||
format='SVG'
|
format='SVG'
|
||||||
align='center' scalefit='1' width='100%'/>
|
align='center' scalefit='1' width='100%'/>
|
||||||
</imageobject>
|
</imageobject>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
<copyright>
|
<copyright>
|
||||||
<year>2010</year>
|
<year>2010</year>
|
||||||
<holder>Intel Corporation</holder>
|
<holder>Linux Foundation</holder>
|
||||||
</copyright>
|
</copyright>
|
||||||
|
|
||||||
<legalnotice>
|
<legalnotice>
|
||||||
451
documentation/poky-ref-manual/bsp.xml
Normal file
@@ -0,0 +1,451 @@
|
|||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<chapter id='bsp'>
|
||||||
|
|
||||||
|
<title>Board Support Packages (BSP) - Developers Guide</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A Board Support Package (BSP) is a collection of information which together
|
||||||
|
defines how to support a particular hardware device, set of devices, or
|
||||||
|
hardware platform. It will include information about the hardware features
|
||||||
|
present on the device and kernel configuration information along with any
|
||||||
|
additional hardware drivers required. It will also list any additional software
|
||||||
|
components required in addition to a generic Linux software stack for both
|
||||||
|
essential and optional platform features.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The intent of this document is to define a structure for these components
|
||||||
|
so that BSPs follow a commonly understood layout, allowing them to be
|
||||||
|
provided in a common form that everyone understands. It also allows end-users
|
||||||
|
to become familiar with one common format and encourages standardisation
|
||||||
|
of software support of hardware.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The proposed format does have elements that are specific to the Poky and
|
||||||
|
OpenEmbedded build systems. It is intended that this information can be
|
||||||
|
used by other systems besides Poky/OpenEmbedded and that it will be simple
|
||||||
|
to extract information and convert to other formats if required. The format
|
||||||
|
described can be directly accepted as a layer by Poky using its standard
|
||||||
|
layers mechanism, but it is important to recognise that the BSP captures all
|
||||||
|
the hardware specific details in one place in a standard format, which is
|
||||||
|
useful for any person wishing to use the hardware platform regardless of
|
||||||
|
the build system in use.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The BSP specification does not include a build system or other tools -
|
||||||
|
it is concerned with the hardware specific components only. At the end
|
||||||
|
distribution point the BSP may be shipped combined with a build system
|
||||||
|
and other tools, but it is important to maintain the distinction that these
|
||||||
|
are separate components which may just be combined in certain end products.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id='bsp-filelayout'>
|
||||||
|
<title>Example Filesystem Layout</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The BSP consists of a file structure inside a base directory, meta-bsp in this example, where "bsp" is a placeholder for the machine or platform name. Examples of some files that it could contain are:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
meta-bsp/
|
||||||
|
meta-bsp/binary/zImage
|
||||||
|
meta-bsp/binary/poky-image-minimal.directdisk
|
||||||
|
meta-bsp/conf/layer.conf
|
||||||
|
meta-bsp/conf/machine/*.conf
|
||||||
|
meta-bsp/conf/machine/include/tune-*.inc
|
||||||
|
meta-bsp/packages/bootloader/bootloader_0.1.bb
|
||||||
|
meta-bsp/packages/linux/linux-bsp-2.6.50/*.patch
|
||||||
|
meta-bsp/packages/linux/linux-bsp-2.6.50/defconfig-bsp
|
||||||
|
meta-bsp/packages/linux/linux-bsp_2.6.50.bb
|
||||||
|
meta-bsp/packages/modem/modem-driver_0.1.bb
|
||||||
|
meta-bsp/packages/modem/modem-daemon_0.1.bb
|
||||||
|
meta-bsp/packages/image-creator/image-creator-native_0.1.bb
|
||||||
|
meta-bsp/prebuilds/
|
||||||
|
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The following sections detail what these files and directories could contain.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bsp-filelayout-binary'>
|
||||||
|
<title>Prebuilt User Binaries (meta-bsp/binary/*)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This optional area contains useful prebuilt kernels and userspace filesystem
|
||||||
|
images appropriate to the target system. Users could use these to get a system
|
||||||
|
running and quickly get started on development tasks. The exact types of binaries
|
||||||
|
present will be highly hardware-dependent but a README file should be present
|
||||||
|
explaining how to use them with the target hardware. If prebuilt binaries are
|
||||||
|
present, source code to meet licensing requirements must also be provided in
|
||||||
|
some form.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bsp-filelayout-layer'>
|
||||||
|
<title>Layer Configuration (meta-bsp/conf/layer.conf)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This file identifies the structure as a Poky layer. This file identifies the
|
||||||
|
contents of the layer and contains information about how Poky should use
|
||||||
|
it. In general it will most likely be a standard boilerplate file consisting of:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
# We have a conf directory, add to BBPATH
|
||||||
|
BBPATH := "${BBPATH}${LAYERDIR}"
|
||||||
|
|
||||||
|
# We have a recipes directory containing .bb and .bbappend files, add to BBFILES
|
||||||
|
BBFILES := "${BBFILES} ${LAYERDIR}/recipes/*/*.bb ${LAYERDIR}/recipes/*/*.bbappend"
|
||||||
|
|
||||||
|
BBFILE_COLLECTIONS += "bsp"
|
||||||
|
BBFILE_PATTERN_bsp := "^${LAYERDIR}/"
|
||||||
|
BBFILE_PRIORITY_bsp = "5"
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
which simply makes bitbake aware of the recipes and conf directories.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This file is required for recognition of the BSP by Poky.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bsp-filelayout-machine'>
|
||||||
|
<title>Hardware Configuration Options (meta-bsp/conf/machine/*.conf)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The machine files bind together all the information contained elsewhere
|
||||||
|
in the BSP into a format that Poky/OpenEmbedded can understand. If
|
||||||
|
the BSP supports multiple machines, multiple machine configuration files
|
||||||
|
can be present. These filenames correspond to the values users set the
|
||||||
|
MACHINE variable to.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These files would define things like which kernel package to use
|
||||||
|
(PREFERRED_PROVIDER of virtual/kernel), which hardware drivers to
|
||||||
|
include in different types of images, any special software components
|
||||||
|
that are needed, any bootloader information, and also any special image
|
||||||
|
format requirements.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
At least one machine file is required for a Poky BSP layer but more than one may be present.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bsp-filelayout-tune'>
|
||||||
|
<title>Hardware Optimisation Options (meta-bsp/conf/machine/include/tune-*.inc)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These are shared hardware "tuning" definitions and are commonly used to
|
||||||
|
pass specific optimisation flags to the compiler. An example is
|
||||||
|
tune-atom.inc:
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
BASE_PACKAGE_ARCH = "core2"
|
||||||
|
TARGET_CC_ARCH = "-m32 -march=core2 -msse3 -mtune=generic -mfpmath=sse"
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
which defines a new package architecture called "core2" and uses the
|
||||||
|
optimization flags specified, which are carefully chosen to give best
|
||||||
|
performance on atom cpus.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The tune file would be included by the machine definition and can be
|
||||||
|
contained in the BSP or reference one from the standard core set of
|
||||||
|
files included with Poky itself.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
These files are optional for a Poky BSP layer.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
<section id='bsp-filelayout-kernel'>
|
||||||
|
<title>Linux Kernel Configuration (meta-bsp/packages/linux/*)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These files make up the definition of a kernel to use with this
|
||||||
|
hardware. In this case it is a complete self-contained kernel with its own
|
||||||
|
configuration and patches but kernels can be shared between many
|
||||||
|
machines as well. Taking some specific example files:
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
meta-bsp/packages/linux/linux-bsp_2.6.50.bb
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
which is the core kernel recipe which firstly details where to get the kernel
|
||||||
|
source from. All standard source code locations are supported so this could
|
||||||
|
be a release tarball, some git repository, or source included in
|
||||||
|
the directory within the BSP itself. It then contains information about which
|
||||||
|
patches to apply and how to configure and build it. It can reuse the main
|
||||||
|
Poky kernel build class, so the definitions here can remain very simple.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
linux-bsp-2.6.50/*.patch
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
which are patches which may be applied against the base kernel, wherever
|
||||||
|
they may have been obtained from.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
meta-bsp/packages/linux/linux-bsp-2.6.50/defconfig-bsp
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
which is the configuration information to use to configure the kernel.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Examples of kernel recipes are available in Poky itself. These files are
|
||||||
|
optional since a kernel from Poky itself could be selected, although it
|
||||||
|
would be unusual not to have a kernel configuration.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bsp-filelayout-packages'>
|
||||||
|
<title>Other Software (meta-bsp/packages/*)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This area includes other pieces of software which the hardware may need for best
|
||||||
|
operation. These are just examples of the kind of things that may be
|
||||||
|
encountered. These are standard .bb file recipes in the usual Poky format,
|
||||||
|
so for examples, see standard Poky recipes. The source can be included directly,
|
||||||
|
referred to in source control systems or release tarballs of external software projects.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
meta-bsp/packages/bootloader/bootloader_0.1.bb
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Some kind of bootloader recipe which may be used to generate a new
|
||||||
|
bootloader binary. Sometimes these are included in the final image
|
||||||
|
format and needed to reflash hardware.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
meta-bsp/packages/modem/modem-driver_0.1.bb
|
||||||
|
meta-bsp/packages/modem/modem-daemon_0.1.bb
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
These are examples of a hardware driver and also a hardware daemon which
|
||||||
|
may need to be included in images to make the hardware useful. "modem"
|
||||||
|
is one example but there may be other components needed like firmware.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
meta-bsp/packages/image-creator/image-creator-native_0.1.bb
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Sometimes the device will need an image in a very specific format for
|
||||||
|
its update mechanism to accept and reflash with it. Recipes to build the
|
||||||
|
tools needed to do this can be included with the BSP.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
These files only need be provided if the platform requires them.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bs-filelayout-bbappend'>
|
||||||
|
<title>Append BSP specific information to existing recipes</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Say you have a recipe like pointercal which has machine-specific information in it,
|
||||||
|
and then you have your new BSP code in a layer. Before the .bbappend extension was
|
||||||
|
introduced, you'd have to copy the whole pointercal recipe and files into your layer,
|
||||||
|
and then add the single file for your machine, which is ugly.
|
||||||
|
|
||||||
|
.bbappend makes the above work much easier, to allow BSP-specific information to be merged
|
||||||
|
with the original recipe easily. When bitbake finds any X.bbappend files, they will be
|
||||||
|
included after bitbake loads X.bb but before finalise or anonymous methods run.
|
||||||
|
This allows the BSP layer to poke around and do whatever it might want to customise
|
||||||
|
the original recipe.
|
||||||
|
|
||||||
|
If your recipe needs to reference extra files it can use the FILESEXTRAPATH variable
|
||||||
|
to specify their location. The example below shows extra files contained in a folder
|
||||||
|
called ${PN} (the package name).
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
FILESEXTRAPATHS := "${THISDIR}/${PN}"
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Then the BSP could add machine-specific config files in layer directory, which will be
|
||||||
|
added by bitbake. You can look at meta-emenlow/packages/formfactor as an example.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bsp-filelayout-prebuilds'>
|
||||||
|
<title>Prebuild Data (meta-bsp/prebuilds/*)</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The location can contain a precompiled representation of the source code
|
||||||
|
contained elsewhere in the BSP layer. It can be processed and used by
|
||||||
|
Poky to provide much faster build times, assuming a compatible configuration is used.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These files are optional.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='bsp-click-through-licensing'>
|
||||||
|
<title>BSP 'Click-through' Licensing Procedure</title>
|
||||||
|
|
||||||
|
<note><para> This section is here as a description of how
|
||||||
|
click-through licensing is expected to work, and is
|
||||||
|
not yet not impemented.
|
||||||
|
</para></note>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In some cases, a BSP may contain separately licensed IP
|
||||||
|
(Intellectual Property) for a component, which imposes
|
||||||
|
upon the user a requirement to accept the terms of a
|
||||||
|
'click-through' license. Once the license is accepted
|
||||||
|
(in whatever form that may be, see details below) the
|
||||||
|
Poky build system can then build and include the
|
||||||
|
corresponding component in the final BSP image. Some
|
||||||
|
affected components may be essential to the normal
|
||||||
|
functioning of the system and have no 'free' replacement
|
||||||
|
i.e. the resulting system would be non-functional
|
||||||
|
without them. Other components may be simply
|
||||||
|
'good-to-have' or purely elective, or if essential
|
||||||
|
nonetheless have a 'free' (possibly less-capable)
|
||||||
|
version which may substituted for in the BSP recipe.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For the latter cases, where it is possible to do so from
|
||||||
|
a functionality perspective, the Poky website will make
|
||||||
|
available a 'de-featured' BSP completely free of
|
||||||
|
encumbered IP, which can be used directly and without
|
||||||
|
any further licensing requirements. If present, this
|
||||||
|
fully 'de-featured' BSP will be named meta-bsp (i.e. the
|
||||||
|
normal default naming convention). This is the simplest
|
||||||
|
and therefore preferred option if available, assuming
|
||||||
|
the resulting functionality meets requirements.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If however, a non-encumbered version is unavailable or
|
||||||
|
the 'free' version would provide unsuitable
|
||||||
|
functionality or quality, an encumbered version can be
|
||||||
|
used. Encumbered versions of a BSP are given names of
|
||||||
|
the form meta-bsp-nonfree. There are several ways
|
||||||
|
within the Poky build system to satisfy the licensing
|
||||||
|
requirements for an encumbered BSP, in roughly the
|
||||||
|
following order of preference:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Get a license key (or keys) for the encumbered BSP
|
||||||
|
by
|
||||||
|
visiting <ulink url='https://pokylinux.org/bsp-keys.html'>https://pokylinux.org/bsp-keys.html</ulink>
|
||||||
|
and give the web form there the name of the BSP
|
||||||
|
and your e-mail address.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
[screenshot of dialog box]
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
After agreeing to any applicable license terms, the
|
||||||
|
BSP key(s) will be immediately sent to the address
|
||||||
|
given and can be used by specifying BSPKEY_<keydomain>
|
||||||
|
environment variables when building the image:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
$ BSPKEY_<keydomain>=<key> bitbake poky-image-sato
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This will allow the encumbered image to be built
|
||||||
|
with no change at all to the normal build process.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Equivalently and probably more conveniently, a line
|
||||||
|
for each key can instead be put into the user's
|
||||||
|
local.conf file.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <keydomain> component of the
|
||||||
|
BSPKEY_<keydomain> is required because there
|
||||||
|
may be multiple licenses in effect for a give BSP; a
|
||||||
|
given <keydomain> in such cases corresponds to
|
||||||
|
a particular license. In order for an encumbered
|
||||||
|
BSP encompassing multiple key domains to be built
|
||||||
|
successfully, a <keydomain> entry for each
|
||||||
|
applicable license must be present in local.conf or
|
||||||
|
supplied on the command-line.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Do nothing - build as you normally would, and follow
|
||||||
|
any license prompts that originate from the
|
||||||
|
encumbered BSP (the build will cleanly stop at this
|
||||||
|
point). These usually take the form of instructions
|
||||||
|
needed to manually fetch the encumbered package(s)
|
||||||
|
and md5 sums into e.g. the poky/build/downloads
|
||||||
|
directory. Once the manual package fetch has been
|
||||||
|
completed, restarting the build will continue where
|
||||||
|
it left off, this time without the prompt since the
|
||||||
|
license requirements will have been satisfied.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Get a full-featured BSP recipe rather than a key, by
|
||||||
|
visiting
|
||||||
|
<ulink url='https://pokylinux.org/bsps.html'>https://pokylinux.org/bsps.html</ulink>.
|
||||||
|
Accepting the license agreement(s) presented will
|
||||||
|
subsequently allow you to download a tarball
|
||||||
|
containing a full-featured BSP legally cleared for
|
||||||
|
your use by the just-given license agreement(s).
|
||||||
|
This method will also allow the encumbered image to
|
||||||
|
be built with no change at all to the normal build
|
||||||
|
process.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
<para>
|
||||||
|
Note that method 3 is also the only option available
|
||||||
|
when downloading pre-compiled images generated from
|
||||||
|
non-free BSPs. Those images are likewise available at
|
||||||
|
<ulink url='https://pokylinux.org/bsps.html'>https://pokylinux.org/bsps.html</ulink>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</chapter>
|
||||||
1004
documentation/poky-ref-manual/development.xml
Normal file
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Before writing a recipe from scratch it is often useful to check
|
Before writing a recipe from scratch it is often useful to check
|
||||||
someone else hasn't written one already. OpenEmbedded is a good place
|
whether someone else has written one already. OpenEmbedded is a good place
|
||||||
to look as it has a wider scope and hence a wider range of packages.
|
to look as it has a wider scope and hence a wider range of packages.
|
||||||
Poky aims to be compatible with OpenEmbedded so most recipes should
|
Poky aims to be compatible with OpenEmbedded so most recipes should
|
||||||
just work in Poky.
|
just work in Poky.
|
||||||
@@ -43,8 +43,8 @@
|
|||||||
<title>Single .c File Package (Hello World!)</title>
|
<title>Single .c File Package (Hello World!)</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To build an application from a single file stored locally requires a
|
To build an application from a single file stored locally (e.g. under "files/")
|
||||||
recipe which has the file listed in the <glossterm><link
|
requires a recipe which has the file listed in the <glossterm><link
|
||||||
linkend='var-SRC_URI'>SRC_URI</link></glossterm> variable. In addition
|
linkend='var-SRC_URI'>SRC_URI</link></glossterm> variable. In addition
|
||||||
the <function>do_compile</function> and <function>do_install</function>
|
the <function>do_compile</function> and <function>do_install</function>
|
||||||
tasks need to be manually written. The <glossterm><link linkend='var-S'>
|
tasks need to be manually written. The <glossterm><link linkend='var-S'>
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
DESCRIPTION = "Simple helloworld application"
|
DESCRIPTION = "Simple helloworld application"
|
||||||
SECTION = "examples"
|
SECTION = "examples"
|
||||||
LICENSE = "MIT"
|
LICENSE = "MIT"
|
||||||
LIC_FILES_CHKSUM = "file://COPYING;md5=ae764cfda68da96df20af9fbf9fe49bd"
|
PR = "r0"
|
||||||
|
|
||||||
SRC_URI = "file://helloworld.c"
|
SRC_URI = "file://helloworld.c"
|
||||||
|
|
||||||
@@ -73,8 +73,9 @@ do_install() {
|
|||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
As a result of the build process "helloworld" and "helloworld-dbg"
|
As a result of the build process "helloworld", "helloworld-dbg" and "hellworld-dev"
|
||||||
packages will be built.
|
packages will be built by default. It is possible to<link linkend='usingpoky-extend-addpkg-files'>
|
||||||
|
customise the packaging process</link>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -93,20 +94,28 @@ do_install() {
|
|||||||
The result of the build will be automatically packaged and if
|
The result of the build will be automatically packaged and if
|
||||||
the application uses NLS to localise then packages with
|
the application uses NLS to localise then packages with
|
||||||
locale information will be generated (one package per
|
locale information will be generated (one package per
|
||||||
language).
|
language). Below is one example (hello_2.2.bb)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
DESCRIPTION = "GNU Helloworld application"
|
DESCRIPTION = "GNU Helloworld application"
|
||||||
SECTION = "examples"
|
SECTION = "examples"
|
||||||
LICENSE = "GPLv2"
|
LICENSE = "GPLv2+"
|
||||||
LIC_FILES_CHKSUM = "file://COPYING;md5=ae764cfda68da96df20af9fbf9fe49bd"
|
LIC_FILES_CHKSUM = "file://COPYING;md5=751419260aa954499f7abaabaa882bbe"
|
||||||
|
PR = "r0"
|
||||||
|
|
||||||
SRC_URI = "${GNU_MIRROR}/hello/hello-${PV}.tar.bz2"
|
SRC_URI = "${GNU_MIRROR}/hello/hello-${PV}.tar.gz"
|
||||||
|
|
||||||
inherit autotools
|
inherit autotools gettext
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<glossterm><link linkend='var-LIC_FILES_CHKSUM'>LIC_FILES_CHKSUM</link>
|
||||||
|
</glossterm> is used to <link linkend='usingpoky-configuring-LIC_FILES_CHKSUM'>
|
||||||
|
track source license change</link>. Autotool based recipe can be quickly
|
||||||
|
created this way like above example.
|
||||||
|
</para>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id='usingpoky-extend-addpkg-makefile'>
|
<section id='usingpoky-extend-addpkg-makefile'>
|
||||||
@@ -132,23 +141,38 @@ inherit autotools
|
|||||||
Some applications may require extra parameters to be passed to
|
Some applications may require extra parameters to be passed to
|
||||||
the compiler, for example an additional header path. This can
|
the compiler, for example an additional header path. This can
|
||||||
be done buy adding to the <glossterm><link
|
be done buy adding to the <glossterm><link
|
||||||
linkend='var-CFLAGS'>CFLAGS</link></glossterm> variable, as in the example below.
|
linkend='var-CFLAGS'>CFLAGS</link></glossterm> variable, as in the example below:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
CFLAGS_prepend = "-I ${S}/include "
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
mtd-utils is an example as Makefile-based:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
DESCRIPTION = "Tools for managing memory technology devices."
|
DESCRIPTION = "Tools for managing memory technology devices."
|
||||||
SECTION = "base"
|
SECTION = "base"
|
||||||
DEPENDS = "zlib"
|
DEPENDS = "zlib lzo e2fsprogs util-linux"
|
||||||
HOMEPAGE = "http://www.linux-mtd.infradead.org/"
|
HOMEPAGE = "http://www.linux-mtd.infradead.org/"
|
||||||
LICENSE = "GPLv2"
|
LICENSE = "GPLv2"
|
||||||
LIC_FILES_CHKSUM = "file://COPYING;md5=ae764cfda68da96df20af9fbf9fe49bd"
|
|
||||||
|
|
||||||
SRC_URI = "ftp://ftp.infradead.org/pub/mtd-utils/mtd-utils-${PV}.tar.gz"
|
SRC_URI = "git://git.infradead.org/mtd-utils.git;protocol=git;tag=v${PV}"
|
||||||
|
|
||||||
CFLAGS_prepend = "-I ${S}/include "
|
S = "${WORKDIR}/git/"
|
||||||
|
|
||||||
do_install() {
|
EXTRA_OEMAKE = "'CC=${CC}' 'CFLAGS=${CFLAGS} -I${S}/include -DWITHOUT_XATTR' \
|
||||||
oe_runmake install DESTDIR=${D}
|
'BUILDDIR=${S}'"
|
||||||
|
|
||||||
|
do_install () {
|
||||||
|
oe_runmake install DESTDIR=${D} SBINDIR=${sbindir} MANDIR=${mandir} \
|
||||||
|
INCLUDEDIR=${includedir}
|
||||||
|
install -d ${D}${includedir}/mtd/
|
||||||
|
for f in ${S}/include/mtd/*.h; do
|
||||||
|
install -m 0644 $f ${D}${includedir}/mtd/
|
||||||
|
done
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
@@ -165,7 +189,7 @@ do_install() {
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Below the "libXpm" recipe is used as an example. By
|
Below the "libXpm" recipe (libxpm_3.5.7.bb) is used as an example. By
|
||||||
default the "libXpm" recipe generates one package
|
default the "libXpm" recipe generates one package
|
||||||
which contains the library
|
which contains the library
|
||||||
and also a few binaries. The recipe can be adapted to
|
and also a few binaries. The recipe can be adapted to
|
||||||
@@ -177,8 +201,9 @@ require xorg-lib-common.inc
|
|||||||
|
|
||||||
DESCRIPTION = "X11 Pixmap library"
|
DESCRIPTION = "X11 Pixmap library"
|
||||||
LICENSE = "X-BSD"
|
LICENSE = "X-BSD"
|
||||||
LIC_FILES_CHKSUM = "file://COPYING;md5=ae764cfda68da96df20af9fbf9fe49bd"
|
DEPENDS += "libxext libsm libxt"
|
||||||
DEPENDS += "libxext"
|
PR = "r3"
|
||||||
|
PE = "1"
|
||||||
|
|
||||||
XORG_PN = "libXpm"
|
XORG_PN = "libXpm"
|
||||||
|
|
||||||
@@ -194,9 +219,12 @@ FILES_sxpm = "${bindir}/sxpm"
|
|||||||
package as standard we prepend the <glossterm><link
|
package as standard we prepend the <glossterm><link
|
||||||
linkend='var-PACKAGES'>PACKAGES</link></glossterm> variable so
|
linkend='var-PACKAGES'>PACKAGES</link></glossterm> variable so
|
||||||
additional package names are added to the start of list. The
|
additional package names are added to the start of list. The
|
||||||
extra <glossterm><link linkend='var-PN'>FILES</link></glossterm>_*
|
extra <glossterm><link linkend='var-FILES'>FILES</link></glossterm>_*
|
||||||
variables then contain information to specify which files and
|
variables then contain information to specify which files and
|
||||||
directories goes into which package.
|
directories goes into which package. Files included by earlier
|
||||||
|
package are skipped by latter packages, and thus main <glossterm>
|
||||||
|
<link linkend='var-PN'>PN</link></glossterm> will not include
|
||||||
|
above listed files
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -208,7 +236,10 @@ FILES_sxpm = "${bindir}/sxpm"
|
|||||||
a <function>pkg_postinst_PACKAGENAME()</function>
|
a <function>pkg_postinst_PACKAGENAME()</function>
|
||||||
function to the .bb file
|
function to the .bb file
|
||||||
where PACKAGENAME is the name of the package to attach
|
where PACKAGENAME is the name of the package to attach
|
||||||
the postinst script to. A post-installation function has the following structure:
|
the postinst script to. Normally <glossterm><link
|
||||||
|
linkend='var-PN'>PN</link></glossterm> can be used which expands
|
||||||
|
to PACKAGENAME automatically. A post-installation function has the
|
||||||
|
following structure:
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
pkg_postinst_PACKAGENAME () {
|
pkg_postinst_PACKAGENAME () {
|
||||||
@@ -236,9 +267,9 @@ pkg_postinst_PACKAGENAME () {
|
|||||||
pkg_postinst_PACKAGENAME () {
|
pkg_postinst_PACKAGENAME () {
|
||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
if [ x"$D" = "x" ]; then
|
if [ x"$D" = "x" ]; then
|
||||||
# Actions to carry out on the device go here
|
# Actions to carry out on the device go here
|
||||||
else
|
else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
@@ -349,7 +380,7 @@ RRECOMMENDS_task-custom-tools = "\
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
In this example, two tasks packages are created, task-custom-apps and
|
In this example, two task packages are created, task-custom-apps and
|
||||||
task-custom-tools with the dependencies and recommended package dependencies
|
task-custom-tools with the dependencies and recommended package dependencies
|
||||||
listed. To build an image using these task packages, you would then add
|
listed. To build an image using these task packages, you would then add
|
||||||
"task-custom-apps" and/or "task-custom-tools" to <glossterm><link
|
"task-custom-apps" and/or "task-custom-tools" to <glossterm><link
|
||||||
@@ -367,8 +398,9 @@ RRECOMMENDS_task-custom-tools = "\
|
|||||||
variable. To create these, the best reference is <filename>meta/classes/poky-image.bbclass</filename>
|
variable. To create these, the best reference is <filename>meta/classes/poky-image.bbclass</filename>
|
||||||
which illustrates how poky achieves this. In summary, the file looks at the contents of the
|
which illustrates how poky achieves this. In summary, the file looks at the contents of the
|
||||||
<glossterm><link linkend='var-IMAGE_FEATURES'>IMAGE_FEATURES</link></glossterm>
|
<glossterm><link linkend='var-IMAGE_FEATURES'>IMAGE_FEATURES</link></glossterm>
|
||||||
variable and based on this generates the <glossterm><link linkend='var-IMAGE_INSTALL'>
|
variable and then maps this into a set of tasks or packages. Based on this then the
|
||||||
IMAGE_INSTALL</link></glossterm> variable automatically. Extra features can be added by
|
<glossterm><link linkend='var-IMAGE_INSTALL'> IMAGE_INSTALL</link></glossterm>
|
||||||
|
variable is generated automatically. Extra features can be added by
|
||||||
extending the class or creating a custom class for use with specialised image .bb files.
|
extending the class or creating a custom class for use with specialised image .bb files.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
@@ -397,11 +429,11 @@ DISTRO_EXTRA_RDEPENDS += "strace"
|
|||||||
DISTRO_EXTRA_RDEPENDS</link></glossterm> variable is for
|
DISTRO_EXTRA_RDEPENDS</link></glossterm> variable is for
|
||||||
distribution maintainers this method does not make
|
distribution maintainers this method does not make
|
||||||
adding packages as simple as a custom .bb file. Using
|
adding packages as simple as a custom .bb file. Using
|
||||||
this method, a few packages will need to be recreated
|
this method, a few packages will need to be recreated if they have been
|
||||||
and the the image built.
|
created before and then the image is rebuilt.
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
bitbake -cclean task-boot task-base task-poky
|
bitbake -c clean task-boot task-base task-poky
|
||||||
bitbake poky-image-sato
|
bitbake poky-image-sato
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
@@ -410,7 +442,7 @@ bitbake poky-image-sato
|
|||||||
<glossterm><link linkend='var-DISTRO_EXTRA_RDEPENDS'>
|
<glossterm><link linkend='var-DISTRO_EXTRA_RDEPENDS'>
|
||||||
DISTRO_EXTRA_RDEPENDS</link></glossterm> variable. There is no need to
|
DISTRO_EXTRA_RDEPENDS</link></glossterm> variable. There is no need to
|
||||||
build them by hand as Poky images depend on the packages they contain so
|
build them by hand as Poky images depend on the packages they contain so
|
||||||
dependencies will be built automatically. For this reason we don't use the
|
dependencies will be built automatically when building the image. For this reason we don't use the
|
||||||
"rebuild" task in this case since "rebuild" does not care about
|
"rebuild" task in this case since "rebuild" does not care about
|
||||||
dependencies - it only rebuilds the specified package.
|
dependencies - it only rebuilds the specified package.
|
||||||
</para>
|
</para>
|
||||||
@@ -451,7 +483,8 @@ bitbake poky-image-sato
|
|||||||
</glossterm> (e.g. "zImage") and <glossterm><link linkend='var-IMAGE_FSTYPES'>
|
</glossterm> (e.g. "zImage") and <glossterm><link linkend='var-IMAGE_FSTYPES'>
|
||||||
IMAGE_FSTYPES</link></glossterm> (e.g. "tar.gz jffs2") might also be
|
IMAGE_FSTYPES</link></glossterm> (e.g. "tar.gz jffs2") might also be
|
||||||
needed. Full details on what these variables do and the meaning of
|
needed. Full details on what these variables do and the meaning of
|
||||||
their contents is available through the links.
|
their contents is available through the links. There're lots of existing
|
||||||
|
machine .conf files which can be easily leveraged from meta/conf/machine/.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -461,10 +494,10 @@ bitbake poky-image-sato
|
|||||||
Poky needs to be able to build a kernel for the machine. You need
|
Poky needs to be able to build a kernel for the machine. You need
|
||||||
to either create a new kernel recipe for this machine or extend an
|
to either create a new kernel recipe for this machine or extend an
|
||||||
existing recipe. There are plenty of kernel examples in the
|
existing recipe. There are plenty of kernel examples in the
|
||||||
packages/linux directory which can be used as references.
|
meta/recipes-kernel/linux directory which can be used as references.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
If creating a new recipe the "normal" recipe writing rules apply
|
If creating a new recipe the "normal" recipe writing rules apply
|
||||||
for setting up a <glossterm><link linkend='var-SRC_URI'>SRC_URI
|
for setting up a <glossterm><link linkend='var-SRC_URI'>SRC_URI
|
||||||
</link></glossterm> including any patches and setting <glossterm>
|
</link></glossterm> including any patches and setting <glossterm>
|
||||||
<link linkend='var-S'>S</link></glossterm> to point at the source
|
<link linkend='var-S'>S</link></glossterm> to point at the source
|
||||||
@@ -481,8 +514,11 @@ bitbake poky-image-sato
|
|||||||
machine's defconfig files in a given kernel, possibly listing it in
|
machine's defconfig files in a given kernel, possibly listing it in
|
||||||
the SRC_URI and adding the machine to the expression in <glossterm>
|
the SRC_URI and adding the machine to the expression in <glossterm>
|
||||||
<link linkend='var-COMPATIBLE_MACHINE'>COMPATIBLE_MACHINE</link>
|
<link linkend='var-COMPATIBLE_MACHINE'>COMPATIBLE_MACHINE</link>
|
||||||
</glossterm>.
|
</glossterm>:
|
||||||
</para>
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
COMPATIBLE_MACHINE = '(qemux86|qemumips)'
|
||||||
|
</programlisting>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="platdev-newmachine-formfactor">
|
<section id="platdev-newmachine-formfactor">
|
||||||
@@ -502,8 +538,21 @@ bitbake poky-image-sato
|
|||||||
under <filename>meta/packages/formfactor/files/MACHINENAME/</filename>
|
under <filename>meta/packages/formfactor/files/MACHINENAME/</filename>
|
||||||
where <literal>MACHINENAME</literal> is the name for which this infomation
|
where <literal>MACHINENAME</literal> is the name for which this infomation
|
||||||
applies. For information about the settings available and the defaults, please see
|
applies. For information about the settings available and the defaults, please see
|
||||||
<filename>meta/packages/formfactor/files/config</filename>.
|
<filename>meta/packages/formfactor/files/config</filename>. Below is one
|
||||||
|
example for qemuarm:
|
||||||
</para>
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
HAVE_TOUCHSCREEN=1
|
||||||
|
HAVE_KEYBOARD=1
|
||||||
|
|
||||||
|
DISPLAY_CAN_ROTATE=0
|
||||||
|
DISPLAY_ORIENTATION=0
|
||||||
|
#DISPLAY_WIDTH_PIXELS=640
|
||||||
|
#DISPLAY_HEIGHT_PIXELS=480
|
||||||
|
#DISPLAY_BPP=16
|
||||||
|
DISPLAY_DPI=150
|
||||||
|
DISPLAY_SUBPIXEL_ORDER=vrgb
|
||||||
|
</programlisting>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -535,51 +584,52 @@ bitbake poky-image-sato
|
|||||||
supported and non-invasive fashion.
|
supported and non-invasive fashion.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The Poky tree includes two additional layers which demonstrate
|
The Poky tree includes several additional layers which demonstrate
|
||||||
this functionality, meta-moblin and meta-extras.
|
this functionality, such as meta-emenlow and meta-extras.
|
||||||
The meta-extras repostory is not enabled by default but enabling
|
The meta-emenlow layer is an example layer enabled by default. The meta-extras
|
||||||
it is as easy as adding the layers path to the BBLAYERS variable in
|
repostory is not enabled by default but enabling any layer is as easy as adding
|
||||||
your bblayers.conf, this is how all layers are enabled in Poky builds:
|
the layers path to the BBLAYERS variable in your bblayers.conf. this is how
|
||||||
|
meta-extras are enabled in Poky builds:
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
<literallayout class='monospaced'>LCONF_VERSION = "1"
|
<literallayout class='monospaced'>LCONF_VERSION = "1"
|
||||||
|
|
||||||
BBFILES ?= ""
|
BBFILES ?= ""
|
||||||
BBLAYERS = " \
|
BBLAYERS = " \
|
||||||
${OEROOT}/meta \
|
/path/to/poky/meta \
|
||||||
${OEROOT}/meta-moblin \
|
/path/to/poky/meta-emenlow \
|
||||||
${OEROOT}/meta-extras \
|
/path/to/poky/meta-extras \
|
||||||
"
|
"
|
||||||
</literallayout>
|
</literallayout>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Bitbake parses the conf/layer.conf of each of the layers in BBLAYERS
|
Bitbake parses the conf/layer.conf of each of the layers in BBLAYERS
|
||||||
to add the layers packages, classes and configuration to Poky.
|
to add the recipes, classes and configuration contained within the layer to Poky.
|
||||||
To create your own layer, independent of the main Poky repository,
|
To create your own layer, independent of the main Poky repository,
|
||||||
you need only create a directory with a conf/layer.conf file and
|
you need only create a directory with a conf/layer.conf file and
|
||||||
add the directory to your bblayers.conf.
|
add the directory to your bblayers.conf.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The meta-extras layer.conf demonstrates the required syntax:
|
The meta-emenlow/conf/layer.conf demonstrates the required syntax:
|
||||||
<literallayout class='monospaced'># We have a conf and classes directory, add to BBPATH
|
<literallayout class='monospaced'># We have a conf and classes directory, add to BBPATH
|
||||||
BBPATH := "${BBPATH}${LAYERDIR}"
|
BBPATH := "${BBPATH}:${LAYERDIR}"
|
||||||
|
|
||||||
# We have a packages directory, add to BBFILES
|
# We have a recipes directory containing both .bb and .bbappend files, add to BBFILES
|
||||||
BBFILES := "${BBFILES} ${LAYERDIR}/packages/*/*.bb"
|
BBFILES := "${BBFILES} ${LAYERDIR}/recipes/*/*.bb \
|
||||||
|
${LAYERDIR}/recipes/*/*.bbappend"
|
||||||
|
|
||||||
BBFILE_COLLECTIONS += "extras"
|
BBFILE_COLLECTIONS += "emenlow"
|
||||||
BBFILE_PATTERN_extras := "^${LAYERDIR}/"
|
BBFILE_PATTERN_emenlow := "^${LAYERDIR}/"
|
||||||
BBFILE_PRIORITY_extras = "5"
|
BBFILE_PRIORITY_emenlow = "6"
|
||||||
|
|
||||||
require conf/distro/include/poky-extras-src-revisions.inc
|
|
||||||
</literallayout>
|
</literallayout>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
As can be seen, the layers recipes are added to BBFILES. The
|
As can be seen, the layers recipes are added to
|
||||||
|
<glossterm> <link linkend='var-BBFILES'>BBFILES</link></glossterm>. The
|
||||||
BBFILE_COLLECTIONS variable is then appended to with the
|
BBFILE_COLLECTIONS variable is then appended to with the
|
||||||
layer name. The BBFILE_PATTERN variable is immediately expanded
|
layer name. The BBFILE_PATTERN variable is immediately expanded
|
||||||
with a regular expression used to match files from BBFILES into
|
with a regular expression used to match files from BBFILES into
|
||||||
@@ -588,15 +638,18 @@ require conf/distro/include/poky-extras-src-revisions.inc
|
|||||||
priorities to the files in different layers. This is useful
|
priorities to the files in different layers. This is useful
|
||||||
in situations where the same package might appear in multiple
|
in situations where the same package might appear in multiple
|
||||||
layers and allows you to choose which layer should 'win'.
|
layers and allows you to choose which layer should 'win'.
|
||||||
Note the use of LAYERDIR with the immediate expansion operator.
|
Note the use of <glossterm><link linkend='var-LAYERDIR'>
|
||||||
LAYERDIR expands to the directory of the current layer and
|
LAYERDIR</link></glossterm> with the immediate expansion operator.
|
||||||
|
<glossterm><link linkend='var-LAYERDIR'>LAYERDIR</link></glossterm>
|
||||||
|
expands to the directory of the current layer and
|
||||||
requires use of the immediate expansion operator so that Bitbake
|
requires use of the immediate expansion operator so that Bitbake
|
||||||
does not lazily expand the variable when it's parsing a
|
does not lazily expand the variable when it's parsing a
|
||||||
different directory.
|
different directory.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Extra bbclasses and configuration are added to the BBPATH
|
Additional bbclass and configuration files can be locationed by
|
||||||
|
bitbake through the addition to the BBPATH
|
||||||
environment variable. In this case, the first file with the
|
environment variable. In this case, the first file with the
|
||||||
matching name found in BBPATH is the one that is used, just
|
matching name found in BBPATH is the one that is used, just
|
||||||
like the PATH variable for binaries. It is therefore recommended
|
like the PATH variable for binaries. It is therefore recommended
|
||||||
@@ -609,7 +662,7 @@ require conf/distro/include/poky-extras-src-revisions.inc
|
|||||||
git repository of the format meta-prvt-XXXX and have this repository
|
git repository of the format meta-prvt-XXXX and have this repository
|
||||||
cloned alongside the other meta directories in the Poky tree.
|
cloned alongside the other meta directories in the Poky tree.
|
||||||
This way you can keep your Poky tree and it's configuration entirely
|
This way you can keep your Poky tree and it's configuration entirely
|
||||||
inside OEROOT.
|
inside POKYBASE.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -630,9 +683,19 @@ require conf/distro/include/poky-extras-src-revisions.inc
|
|||||||
summarises the change and starts with the name of any package affected
|
summarises the change and starts with the name of any package affected
|
||||||
work well. Not all changes are to specific packages so the prefix could
|
work well. Not all changes are to specific packages so the prefix could
|
||||||
also be a machine name or class name instead. If a change needs a longer
|
also be a machine name or class name instead. If a change needs a longer
|
||||||
description this should follow the summary.
|
description this should follow the summary:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<literallayout class='monospaced'>
|
||||||
|
bitbake/data.py: Add emit_func() and generate_dependencies() functions
|
||||||
|
|
||||||
|
These functions allow generation of dependency data between funcitons and
|
||||||
|
variables allowing moves to be made towards generating checksums and allowing
|
||||||
|
use of the dependency information in other parts of bitbake.
|
||||||
|
|
||||||
|
Signed-off-by: Richard Purdie rpurdie@linux.intel.com
|
||||||
|
</literallayout>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Any commit should be self contained in that it should leave the
|
Any commit should be self contained in that it should leave the
|
||||||
metadata in a consistent state, buildable before and after the
|
metadata in a consistent state, buildable before and after the
|
||||||
@@ -650,10 +713,12 @@ require conf/distro/include/poky-extras-src-revisions.inc
|
|||||||
</glossterm> variable needs to be increased (commonly referred to
|
</glossterm> variable needs to be increased (commonly referred to
|
||||||
as 'bumped') as part of that commit. Only integer values are used
|
as 'bumped') as part of that commit. Only integer values are used
|
||||||
and <glossterm><link linkend='var-PR'>PR</link></glossterm> =
|
and <glossterm><link linkend='var-PR'>PR</link></glossterm> =
|
||||||
"r0" should not be added into new recipes as this is default value.
|
"r0" should be added into new recipes as, while this is the
|
||||||
|
default value, not having the variable defined in a recipe makes
|
||||||
|
it easy to miss incrementing it when updating the recipe.
|
||||||
When upgrading the version of a package (<glossterm><link
|
When upgrading the version of a package (<glossterm><link
|
||||||
linkend='var-PV'>PV</link></glossterm>), the <glossterm><link
|
linkend='var-PV'>PV</link></glossterm>), the <glossterm><link
|
||||||
linkend='var-PR'>PR</link></glossterm> variable should be removed.
|
linkend='var-PR'>PR</link></glossterm> variable should be reset to "r0".
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -673,7 +738,7 @@ require conf/distro/include/poky-extras-src-revisions.inc
|
|||||||
the repository and don't have to remember to rebuild any sections.
|
the repository and don't have to remember to rebuild any sections.
|
||||||
The second is to ensure that target users are able to upgrade their
|
The second is to ensure that target users are able to upgrade their
|
||||||
devices via their package manager such as with the <command>
|
devices via their package manager such as with the <command>
|
||||||
opkg update;opkg upgrade</command> commands (or similar for
|
opkg upgrade</command> commands (or similar for
|
||||||
dpkg/apt or rpm based systems). The aim is to ensure Poky has
|
dpkg/apt or rpm based systems). The aim is to ensure Poky has
|
||||||
upgradable packages in all cases.
|
upgradable packages in all cases.
|
||||||
</para>
|
</para>
|
||||||
@@ -706,6 +771,8 @@ require conf/distro/include/poky-extras-src-revisions.inc
|
|||||||
are builds that build everything from the ground up and test everything.
|
are builds that build everything from the ground up and test everything.
|
||||||
They usually happen at preset times such as at night when the machine
|
They usually happen at preset times such as at night when the machine
|
||||||
load isn't high from the incremental builds.
|
load isn't high from the incremental builds.
|
||||||
|
<ulink url='http://autobuilder.pokylinux.org:8010'>poky autobuilder</ulink>
|
||||||
|
is an example implementation with buildbot.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -781,11 +848,14 @@ src/gz beagleboard http://www.mysite.com/somedir/deploy/ipk/beagleboard</literal
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
bitbake --cmd compile --force NAME_OF_PACKAGE
|
bitbake -c compile -f NAME_OF_PACKAGE
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Other tasks may also be called this way.
|
"-f" or "--force" is used to force re-execution of the specified task.
|
||||||
|
Other tasks may also be called this way. But note that all the modifications
|
||||||
|
in <glossterm><link linkend='var-WORKDIR'>WORKDIR</link></glossterm>
|
||||||
|
are gone once you executes "-c clean" for a package.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<section id='usingpoky-modifying-packages-quilt'>
|
<section id='usingpoky-modifying-packages-quilt'>
|
||||||
@@ -838,10 +908,11 @@ SRC_URI += "file://NAME-OF-PATCH.patch"
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
<section id='usingpoky-configuring-LIC_FILES_CHKSUM'>
|
<section id='usingpoky-configuring-LIC_FILES_CHKSUM'>
|
||||||
<title>Configuring the LIC_FILES_CHKSUM variable</title>
|
<title>Track license change</title>
|
||||||
<para>
|
<para>
|
||||||
The changes in the license text inside source code files is tracked
|
The license of one upstream project may change in the future, and Poky provides
|
||||||
using the LIC_FILES_CHKSUM metadata variable.
|
one mechanism to track such license change - <glossterm>
|
||||||
|
<link linkend='var-LIC_FILES_CHKSUM'>LIC_FILES_CHKSUM</link></glossterm> variable.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<section id='usingpoky-specifying-LIC_FILES_CHKSUM'>
|
<section id='usingpoky-specifying-LIC_FILES_CHKSUM'>
|
||||||
@@ -853,6 +924,26 @@ LIC_FILES_CHKSUM = "file://COPYING; md5=xxxx \
|
|||||||
file://licfile2.txt; endline=50;md5=zzzz \
|
file://licfile2.txt; endline=50;md5=zzzz \
|
||||||
..."
|
..."
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<glossterm><link linkend='var-S'>S</link></glossterm> is the default directory
|
||||||
|
for searching files listed in <glossterm><link linkend='var-LIC_FILES_CHKSUM'>
|
||||||
|
LIC_FILES_CHKSUM</link></glossterm>. Relative path could be used too:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
LIC_FILES_CHKSUM = "file://src/ls.c;startline=5;endline=16;\
|
||||||
|
md5=bb14ed3c4cda583abc85401304b5cd4e"
|
||||||
|
LIC_FILES_CHKSUM = "file://../license.html;md5=5c94767cedb5d6987c902ac850ded2c6"
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The first line locates a file in <glossterm><link linkend='var-S'>
|
||||||
|
S</link></glossterm>/src/ls.c, and the second line refers to a file in
|
||||||
|
<glossterm><link linkend='var-WORKDIR'>WORKDIR</link></glossterm>, which is the parent
|
||||||
|
of <glossterm><link linkend='var-S'>S</link></glossterm>
|
||||||
|
</para>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id='usingpoky-LIC_FILES_CHKSUM-explanation-of-syntax'>
|
<section id='usingpoky-LIC_FILES_CHKSUM-explanation-of-syntax'>
|
||||||
@@ -871,12 +962,12 @@ to specify "beginline" and "endline" parameters.
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The "md5" parameter stores the md5 checksum of the license text. So if
|
The "md5" parameter stores the md5 checksum of the license text. So if
|
||||||
the license text changes in any way from a file, then it's md5 sum will differ and will not
|
the license text changes in any way from a file, then its md5 sum will differ and will not
|
||||||
match with the previously stored md5 checksum. This mismatch will trigger build
|
match with the previously stored md5 checksum. This mismatch will trigger build
|
||||||
failure, notifying developer about the license text md5 mismatch, and allowing
|
failure, notifying developer about the license text md5 mismatch, and allowing
|
||||||
the developer to review the license text changes. Also note that if md5 checksum
|
the developer to review the license text changes. Also note that if md5 checksum
|
||||||
is not matched while building, the correct md5 checksum is printed in the build
|
is not matched while building, the correct md5 checksum is printed in the build
|
||||||
log.
|
log which can be easily copied to .bb file.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
There is no limit on how many files can be specified on this parameter. But generally every
|
There is no limit on how many files can be specified on this parameter. But generally every
|
||||||
@@ -889,7 +980,7 @@ is valid then tracking only that file would be enough.
|
|||||||
<para>
|
<para>
|
||||||
1. If you specify empty or invalid "md5" parameter; then while building
|
1. If you specify empty or invalid "md5" parameter; then while building
|
||||||
the package, bitbake will give md5 not matched error, and also show the correct
|
the package, bitbake will give md5 not matched error, and also show the correct
|
||||||
"md5" parameter value in the build log
|
"md5" parameter value both on the screen and in the build log
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
2. If the whole file contains only license text, then there is no need to
|
2. If the whole file contains only license text, then there is no need to
|
||||||
@@ -899,25 +990,26 @@ specify "beginline" and "endline" parameters.
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id='usingpoky-configuring-DISTRO_PN_ALIAS'>
|
<section id='usingpoky-configuring-DISTRO_PN_ALIAS'>
|
||||||
<title>Configuring the DISTRO_PN_ALIAS variable</title>
|
<title>Handle package name alias</title>
|
||||||
<para>
|
<para>
|
||||||
Sometimes the names of the same packages are different in different
|
Poky implements a distro_check task which automatically connects to major distributions
|
||||||
linux distributions; and that can becomes an issue for the distro_check
|
and checks whether they contains same package. Sometimes the same package has different
|
||||||
task to check if the given recipe package exists in other linux distros.
|
names in different distributions, which results in a mismatch from distro_check task
|
||||||
This issue is avoided by defining per distro recipe name alias:
|
This can be solved by defining per distro recipe name alias -
|
||||||
DISTRO_PN_ALIAS
|
<glossterm><link linkend='var-DISTRO_PN_ALIAS'>DISTRO_PN_ALIAS</link></glossterm>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<section id='usingpoky-specifying-DISTRO_PN_ALIAS'>
|
<section id='usingpoky-specifying-DISTRO_PN_ALIAS'>
|
||||||
<title>Specifying the DISTRO_PN_ALIAS variable </title>
|
<title>Specifying the DISTRO_PN_ALIAS variable </title>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
DISTRO_PN_ALIAS = "distro1=package_name_alias1; distro2=package_name_alias2 \
|
DISTRO_PN_ALIAS_pn-PACKAGENAME = "distro1=package_name_alias1 \
|
||||||
distro3=package_name_alias3; \
|
distro2=package_name_alias2 \
|
||||||
..."
|
distro3=package_name_alias3 \
|
||||||
|
..."
|
||||||
</programlisting>
|
</programlisting>
|
||||||
<para>
|
<para>
|
||||||
Look at the meta/packages/xorg-app/xset_1.0.4.bb recipe file for an example.
|
Use space as the delimiter if there're multiple distro aliases
|
||||||
</para>
|
</para>
|
||||||
<tip>
|
<tip>
|
||||||
<para>
|
<para>
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
We have a Buildbot which provides continuous build and integration tests
|
We have an autobuilder which provides continuous build and integration tests
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
@@ -207,7 +207,7 @@
|
|||||||
<qandaentry>
|
<qandaentry>
|
||||||
<question>
|
<question>
|
||||||
<para>
|
<para>
|
||||||
I see lots of 404 responses for files on http://folks.o-hand.com/~richard/poky/sources/*. Is something wrong?
|
I see lots of 404 responses for files on http://pokylinux.org/sources/*. Is something wrong?
|
||||||
</para>
|
</para>
|
||||||
</question>
|
</question>
|
||||||
<answer>
|
<answer>
|
||||||
@@ -278,7 +278,7 @@
|
|||||||
</question>
|
</question>
|
||||||
<answer>
|
<answer>
|
||||||
<para>
|
<para>
|
||||||
The *-native targets are designed to run on the system the buil is running on. These are usually tools that are needed to assist the build in some way such as quilt-native which is used to apply patches. The non-native version is the one that would run on the target device.
|
The *-native targets are designed to run on the system the build is running on. These are usually tools that are needed to assist the build in some way such as quilt-native which is used to apply patches. The non-native version is the one that would run on the target device.
|
||||||
</para>
|
</para>
|
||||||
</answer>
|
</answer>
|
||||||
</qandaentry>
|
</qandaentry>
|
||||||
BIN
documentation/poky-ref-manual/figures/cropped-yocto-project-bw.png
Executable file
|
After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
BIN
documentation/poky-ref-manual/figures/yocto-project-transp.png
Executable file
|
After Width: | Height: | Size: 8.4 KiB |
155
documentation/poky-ref-manual/introduction.xml
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<chapter id='intro'>
|
||||||
|
<title>Introduction</title>
|
||||||
|
|
||||||
|
<section id='intro-welcome'>
|
||||||
|
<title>Welcome to Poky!</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Poky is the the build tool in Yocto Project.
|
||||||
|
It is at the heart of Yocto Project.
|
||||||
|
You use Poky within Yocto Project to build the images (kernel software) for targeted hardware.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Before jumping into Poky you should have an understanding of Yokto Project.
|
||||||
|
Be sure you are familiar with the information in the Yocto Project Quick Start.
|
||||||
|
You can find this documentation on the public <ulink rul='http://yoctoproject.org/'>Yocto Project Website</ulink>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>What is Poky?</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Poky provides an open source Linux, X11, Matchbox, GTK+, Pimlico, Clutter, and other <ulink url='http://gnome.org/mobile'>GNOME Mobile</ulink> technologies based full platform build tool within Yocto Project.
|
||||||
|
It creates a focused, stable, subset of OpenEmbedded that can be easily and reliably built and developed upon.
|
||||||
|
Poky fully supports a wide range of x86 ARM, MIPS and PowerPC hardware and device virtulisation.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Poky is primarily a platform builder which generates filesystem images
|
||||||
|
based on open source software such as the Kdrive X server, the Matchbox
|
||||||
|
window manager, the GTK+ toolkit and the D-Bus message bus system. Images
|
||||||
|
for many kinds of devices can be generated, however the standard example
|
||||||
|
machines target QEMU full system emulation(x86, ARM, MIPS and PowerPC) and
|
||||||
|
real reference boards for each of these architectures.
|
||||||
|
Poky's ability to boot inside a QEMU
|
||||||
|
emulator makes it particularly suitable as a test platform for development
|
||||||
|
of embedded software.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
An important component integrated within Poky is Sato, a GNOME Mobile
|
||||||
|
based user interface environment.
|
||||||
|
It is designed to work well with screens at very high DPI and restricted
|
||||||
|
size, such as those often found on smartphones and PDAs. It is coded with
|
||||||
|
focus on efficiency and speed so that it works smoothly on hand-held and
|
||||||
|
other embedded hardware. It will sit neatly on top of any device
|
||||||
|
using the GNOME Mobile stack, providing a well defined user experience.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<screenshot>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="screenshots/ss-sato.png" format="PNG" align='center' scalefit='1' width="100%" contentdepth="100%"/>
|
||||||
|
</imageobject>
|
||||||
|
<caption>
|
||||||
|
<para>The Sato Desktop - A screenshot from a machine running a Poky built image</para>
|
||||||
|
</caption>
|
||||||
|
</mediaobject>
|
||||||
|
</screenshot>
|
||||||
|
|
||||||
|
|
||||||
|
<para>
|
||||||
|
|
||||||
|
Poky has a growing open source community and is also backed up by commercial organisations including <ulink url="http://www.intel.com/">Intel Corporation</ulink>.
|
||||||
|
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='intro-manualoverview'>
|
||||||
|
<title>Documentation Overview</title>
|
||||||
|
<para>
|
||||||
|
The Poky User Guide is split into sections covering different aspects of Poky.
|
||||||
|
The <link linkend='usingpoky'>'Using Poky' section</link> gives an overview of the components that make up Poky followed by information about using Poky and debugging images created in Yocto Project.
|
||||||
|
The <link linkend='extendpoky'>'Extending Poky' section</link> gives information about how to extend and customise Poky along with advice on how to manage these changes.
|
||||||
|
The <link linkend='platdev'>'Platform Development with Poky' section</link> gives information about interaction between Poky and target hardware for common platform development tasks such as software development, debugging and profiling.
|
||||||
|
The rest of the manual consists of several reference sections each giving details on a specific section of Poky functionality.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This manual applies to Poky Release 3.3 (Green).
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<section id='intro-requirements'>
|
||||||
|
<title>System Requirements</title>
|
||||||
|
<para>
|
||||||
|
We recommend Debian-based distributions, in particular a recent Ubuntu
|
||||||
|
release (10.04 or newer), as the host system for Poky. Nothing in Poky is
|
||||||
|
distribution specific and other distributions will most likely work as long
|
||||||
|
as the appropriate prerequisites are installed - we know of Poky being used
|
||||||
|
successfully on Redhat, SUSE, Gentoo and Slackware host systems.
|
||||||
|
For information on what you need to develop images using Yocto Project and Poky
|
||||||
|
you should see the Yocto Project Quick Start on the public
|
||||||
|
<ulink rul='http://yoctoproject.org/'>Yocto Project Website</ulink>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='intro-getit'>
|
||||||
|
<title>Obtaining Poky</title>
|
||||||
|
|
||||||
|
<section id='intro-getit-releases'>
|
||||||
|
<title>Releases</title>
|
||||||
|
|
||||||
|
<para>Periodically, we make releases of Poky and these are available
|
||||||
|
at <ulink url='http://pokylinux.org/releases/'/>.
|
||||||
|
These are more stable and tested than the nightly development images.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='intro-getit-nightly'>
|
||||||
|
<title>Nightly Builds</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We make nightly builds of Poky for testing purposes and to make the
|
||||||
|
latest developments available. The output from these builds is available
|
||||||
|
at <ulink url='http://autobuilder.pokylinux.org/'/>
|
||||||
|
where the numbers increase for each subsequent build and can be used to reference it.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Automated builds are available for "standard" Poky and for Poky SDKs and toolchains as well
|
||||||
|
as any testing versions we might have such as poky-bleeding. The toolchains can
|
||||||
|
be used either as external standalone toolchains or can be combined with Poky as a
|
||||||
|
prebuilt toolchain to reduce build time. Using the external toolchains is simply a
|
||||||
|
case of untarring the tarball into the root of your system (it only creates files in
|
||||||
|
<filename class="directory">/opt/poky</filename>) and then enabling the option
|
||||||
|
in <filename>local.conf</filename>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='intro-getit-dev'>
|
||||||
|
<title>Development Checkouts</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Poky is available from our GIT repository located at
|
||||||
|
git://git.pokylinux.org/poky.git; a web interface to the repository
|
||||||
|
can be accessed at <ulink url='http://git.pokylinux.org/'/>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The 'master' is where the deveopment work takes place and you should use this if you're
|
||||||
|
after to work with the latest cutting edge developments. It is possible trunk
|
||||||
|
can suffer temporary periods of instability while new features are developed and
|
||||||
|
if this is undesireable we recommend using one of the release branches.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</chapter>
|
||||||
|
<!--
|
||||||
|
vim: expandtab tw=80 ts=4
|
||||||
|
-->
|
||||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
101
documentation/poky-ref-manual/poky-ref-manual.xml
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<book id='poky-ref-manual' lang='en'
|
||||||
|
xmlns:xi="http://www.w3.org/2003/XInclude"
|
||||||
|
xmlns="http://docbook.org/ns/docbook"
|
||||||
|
>
|
||||||
|
<bookinfo>
|
||||||
|
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref='figures/poky-ref-manual.png'
|
||||||
|
format='SVG'
|
||||||
|
align='center' scalefit='1' width='100%'/>
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
|
||||||
|
<title>Poky Reference Manual</title>
|
||||||
|
<subtitle>A Guide and Reference to Poky</subtitle>
|
||||||
|
<authorgroup>
|
||||||
|
<author>
|
||||||
|
<firstname>Richard</firstname> <surname>Purdie</surname>
|
||||||
|
<affiliation>
|
||||||
|
<orgname>Intel Corporation</orgname>
|
||||||
|
</affiliation>
|
||||||
|
<email>richard@linux.intel.com</email>
|
||||||
|
</author>
|
||||||
|
|
||||||
|
<author>
|
||||||
|
<firstname>Tomas</firstname> <surname>Frydrych</surname>
|
||||||
|
<affiliation>
|
||||||
|
<orgname>Intel Corporation</orgname>
|
||||||
|
</affiliation>
|
||||||
|
</author>
|
||||||
|
|
||||||
|
<author>
|
||||||
|
<firstname>Marcin</firstname> <surname>Juszkiewicz</surname>
|
||||||
|
</author>
|
||||||
|
<author>
|
||||||
|
<firstname>Dodji</firstname> <surname>Seketeli</surname>
|
||||||
|
</author>
|
||||||
|
</authorgroup>
|
||||||
|
|
||||||
|
<revhistory>
|
||||||
|
<revision>
|
||||||
|
<revnumber>4.0+git</revnumber>
|
||||||
|
<date>27 Oct 2010</date>
|
||||||
|
<revremark>Poky Master Documentation</revremark>
|
||||||
|
</revision>
|
||||||
|
</revhistory>
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
<year>2007-2010</year>
|
||||||
|
<holder>Linux Foundation</holder>
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<legalnotice>
|
||||||
|
<para>
|
||||||
|
Permission is granted to copy, distribute and/or modify this document under
|
||||||
|
the terms of the <ulink type="http" url="http://creativecommons.org/licenses/by-nc-sa/2.0/uk/">Creative Commons Attribution-Non-Commercial-Share Alike 2.0 UK: England & Wales</ulink> as published by Creative Commons.
|
||||||
|
</para>
|
||||||
|
</legalnotice>
|
||||||
|
|
||||||
|
</bookinfo>
|
||||||
|
|
||||||
|
<xi:include href="introduction.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="usingpoky.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="extendpoky.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="bsp.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="development.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="ref-structure.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="ref-bitbake.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="ref-classes.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="ref-images.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="ref-features.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="ref-variables.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="ref-varlocality.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="faq.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="resources.xml"/>
|
||||||
|
|
||||||
|
<index id='index'>
|
||||||
|
<title>Index</title>
|
||||||
|
</index>
|
||||||
|
|
||||||
|
</book>
|
||||||
|
<!--
|
||||||
|
vim: expandtab tw=80 ts=4
|
||||||
|
-->
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
<title>Reference: Bitbake</title>
|
<title>Reference: Bitbake</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Bitbake a program written in Python which interprets the metadata
|
Bitbake is a program written in Python that interprets the metadata
|
||||||
that makes up Poky. At some point, people wonder what actually happens
|
that makes up Poky. At some point, people wonder what actually happens
|
||||||
when you type <command>bitbake poky-image-sato</command>. This section
|
when you type <command>bitbake poky-image-sato</command>. This section
|
||||||
aims to give an overview of what happens behind the scenes from a
|
aims to give an overview of what happens behind the scenes from a
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<para>
|
<para>
|
||||||
It is worth noting that bitbake aims to be a generic "task" executor
|
It is worth noting that bitbake aims to be a generic "task" executor
|
||||||
capable of handling complex dependency relationships. As such it has no
|
capable of handling complex dependency relationships. As such it has no
|
||||||
real knowledge of what the tasks its executing actually do. It just
|
real knowledge of what the tasks it is executing actually do. It just
|
||||||
considers a list of tasks with dependencies and handles metadata
|
considers a list of tasks with dependencies and handles metadata
|
||||||
consisting of variables in a certain format which get passed to the
|
consisting of variables in a certain format which get passed to the
|
||||||
tasks.
|
tasks.
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
specified on the commandline) and looks for providers of that target.
|
specified on the commandline) and looks for providers of that target.
|
||||||
Once a provider is selected, BitBake resolves all the dependencies for
|
Once a provider is selected, BitBake resolves all the dependencies for
|
||||||
the target. In the case of "poky-image-sato", it would lead to
|
the target. In the case of "poky-image-sato", it would lead to
|
||||||
<filename>task-oh.bb</filename> and <filename>task-base.bb</filename>
|
<filename>task-base.bb</filename>
|
||||||
which in turn would lead to packages like <application>Contacts</application>,
|
which in turn would lead to packages like <application>Contacts</application>,
|
||||||
<application>Dates</application>, <application>BusyBox</application>
|
<application>Dates</application>, <application>BusyBox</application>
|
||||||
and these in turn depend on glibc and the toolchain.
|
and these in turn depend on glibc and the toolchain.
|
||||||
@@ -154,7 +154,8 @@
|
|||||||
"1" makes it likely the package will be used.
|
"1" makes it likely the package will be used.
|
||||||
<glossterm><link
|
<glossterm><link
|
||||||
linkend='var-PREFERRED_VERSION'>PREFERRED_VERSION</link></glossterm> overrides
|
linkend='var-PREFERRED_VERSION'>PREFERRED_VERSION</link></glossterm> overrides
|
||||||
any default preference. <glossterm><link
|
any <glossterm><link
|
||||||
|
linkend='var-DEFAULT_PREFERENCE'>DEFAULT_PREFERENCE</link></glossterm>. <glossterm><link
|
||||||
linkend='var-DEFAULT_PREFERENCE'>DEFAULT_PREFERENCE</link></glossterm>
|
linkend='var-DEFAULT_PREFERENCE'>DEFAULT_PREFERENCE</link></glossterm>
|
||||||
is often used to mark more
|
is often used to mark more
|
||||||
experimental new versions of packages until they've undergone sufficient
|
experimental new versions of packages until they've undergone sufficient
|
||||||
@@ -176,7 +177,7 @@
|
|||||||
multi-core systems, BitBake considers each task as an independent
|
multi-core systems, BitBake considers each task as an independent
|
||||||
entity with a set of dependencies. There are many variables that
|
entity with a set of dependencies. There are many variables that
|
||||||
are used to signify these dependencies and more information can be found
|
are used to signify these dependencies and more information can be found
|
||||||
found about these in the <ulink url='http://bitbake.berlios.de/manual/'>
|
about these in the <ulink url='http://bitbake.berlios.de/manual/'>
|
||||||
BitBake manual</ulink>. At a basic level it is sufficient to know
|
BitBake manual</ulink>. At a basic level it is sufficient to know
|
||||||
that BitBake uses the <glossterm><link
|
that BitBake uses the <glossterm><link
|
||||||
linkend='var-DEPENDS'>DEPENDS</link></glossterm> and
|
linkend='var-DEPENDS'>DEPENDS</link></glossterm> and
|
||||||
@@ -196,7 +197,7 @@
|
|||||||
order. The build now starts with BitBake forking off threads up to
|
order. The build now starts with BitBake forking off threads up to
|
||||||
the limit set in the <glossterm><link
|
the limit set in the <glossterm><link
|
||||||
linkend='var-BB_NUMBER_THREADS'>BB_NUMBER_THREADS</link></glossterm> variable
|
linkend='var-BB_NUMBER_THREADS'>BB_NUMBER_THREADS</link></glossterm> variable
|
||||||
as long there are tasks ready to run, i.e. tasks with all their
|
as long as there are tasks ready to run, i.e. tasks with all their
|
||||||
dependencies met.
|
dependencies met.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@@ -271,9 +272,9 @@ Options:
|
|||||||
target that failed, and those that depend on it,
|
target that failed, and those that depend on it,
|
||||||
cannot be remade, the other dependencies of these
|
cannot be remade, the other dependencies of these
|
||||||
targets can be processed all the same.
|
targets can be processed all the same.
|
||||||
|
-a, --tryaltconfigs continue with builds by trying to use alternative
|
||||||
|
providers where possible.
|
||||||
-f, --force force run of specified cmd, regardless of stamp status
|
-f, --force force run of specified cmd, regardless of stamp status
|
||||||
-i, --interactive drop into the interactive mode also called the BitBake
|
|
||||||
shell.
|
|
||||||
-c CMD, --cmd=CMD Specify task to execute. Note that this only executes
|
-c CMD, --cmd=CMD Specify task to execute. Note that this only executes
|
||||||
the specified task for the providee and the packages
|
the specified task for the providee and the packages
|
||||||
it depends on, i.e. 'compile' does not implicitly call
|
it depends on, i.e. 'compile' does not implicitly call
|
||||||
@@ -286,6 +287,9 @@ Options:
|
|||||||
-D, --debug Increase the debug level. You can specify this more
|
-D, --debug Increase the debug level. You can specify this more
|
||||||
than once.
|
than once.
|
||||||
-n, --dry-run don't execute, just go through the motions
|
-n, --dry-run don't execute, just go through the motions
|
||||||
|
-S, --dump-signatures
|
||||||
|
don't execute, just dump out the signature
|
||||||
|
construction information
|
||||||
-p, --parse-only quit after parsing the BB files (developers only)
|
-p, --parse-only quit after parsing the BB files (developers only)
|
||||||
-d, --disable-psyco disable using the psyco just-in-time compiler (not
|
-d, --disable-psyco disable using the psyco just-in-time compiler (not
|
||||||
recommended)
|
recommended)
|
||||||
@@ -294,13 +298,16 @@ Options:
|
|||||||
what used to be bbread)
|
what used to be bbread)
|
||||||
-g, --graphviz emit the dependency trees of the specified packages in
|
-g, --graphviz emit the dependency trees of the specified packages in
|
||||||
the dot syntax
|
the dot syntax
|
||||||
-I IGNORED_DOT_DEPS, --ignore-deps=IGNORED_DOT_DEPS
|
-I EXTRA_ASSUME_PROVIDED, --ignore-deps=EXTRA_ASSUME_PROVIDED
|
||||||
Stop processing at the given list of dependencies when
|
Assume these dependencies don't exist and are already
|
||||||
generating dependency graphs. This can help to make
|
provided (equivalent to ASSUME_PROVIDED). Useful to
|
||||||
the graph more appealing
|
make dependency graphs more appealing
|
||||||
-l DEBUG_DOMAINS, --log-domains=DEBUG_DOMAINS
|
-l DEBUG_DOMAINS, --log-domains=DEBUG_DOMAINS
|
||||||
Show debug logging for the specified logging domains
|
Show debug logging for the specified logging domains
|
||||||
-P, --profile profile the command and print a report</screen>
|
-P, --profile profile the command and print a report
|
||||||
|
-u UI, --ui=UI userinterface to use
|
||||||
|
--revisions-changed Set the exit code depending on whether upstream
|
||||||
|
floating revisions have changed or not</screen>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
file. Class files are identified by the extension
|
file. Class files are identified by the extension
|
||||||
<filename class="extension">.bbclass</filename> and are usually placed
|
<filename class="extension">.bbclass</filename> and are usually placed
|
||||||
in a <filename class="directory">classes/</filename> directory beneath the
|
in a <filename class="directory">classes/</filename> directory beneath the
|
||||||
<filename class="directory">meta/</filename> directory or the <filename
|
<filename class="directory">meta*/</filename> directory or the directory pointed
|
||||||
class="directory">build/</filename> directory in the same way as <filename
|
by BUILDDIR (e.g. <filename class="directory">build/</filename>)in the same way as
|
||||||
class="extension">.conf</filename> files in the <filename
|
<filename class="extension">.conf</filename> files in the <filename
|
||||||
class="directory">conf</filename> directory. Class files are searched for
|
class="directory">conf</filename> directory. Class files are searched for
|
||||||
in BBPATH in the same was as <filename class="extension">.conf</filename> files too.
|
in BBPATH in the same was as <filename class="extension">.conf</filename> files too.
|
||||||
</para>
|
</para>
|
||||||
@@ -34,10 +34,8 @@
|
|||||||
(runs any Makefile present), installing (empty by default) and packaging
|
(runs any Makefile present), installing (empty by default) and packaging
|
||||||
(empty by default). These are often overridden or extended by other classes
|
(empty by default). These are often overridden or extended by other classes
|
||||||
such as <filename>autotools.bbclass</filename> or
|
such as <filename>autotools.bbclass</filename> or
|
||||||
<filename>package.bbclass</filename>. The class contains some commonly
|
<filename>package.bbclass</filename>. The class also contains some commonly
|
||||||
some commonly used functions such as <function>oe_libinstall</function>
|
used functions such as <function>oe_runmake</function>.
|
||||||
and <function>oe_runmake</function>. The end of the class file has a
|
|
||||||
list of standard mirrors for software projects for use by the fetcher code.
|
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -55,14 +53,14 @@
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Its useful to have some idea of the tasks this class defines work and
|
It's useful to have some idea of how the tasks defined by this class work
|
||||||
what they do behind the scenes.
|
and what they do behind the scenes.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
'do_configure' regenearates the configure script and
|
'do_configure' regenearates the configure script (using autoreconf) and
|
||||||
then launches it with a standard set of arguments used during
|
then launches it with a standard set of arguments used during
|
||||||
cross-compilation. Additional parameters can be passed to
|
cross-compilation. Additional parameters can be passed to
|
||||||
<command>configure</command> through the <glossterm><link
|
<command>configure</command> through the <glossterm><link
|
||||||
@@ -86,16 +84,6 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>
|
|
||||||
By default the class does not stage headers and libraries so
|
|
||||||
the recipe author needs to add their own <function>do_stage()</function>
|
|
||||||
task. For typical recipes the following example code will usually be
|
|
||||||
enough:
|
|
||||||
<programlisting>
|
|
||||||
do_stage() {
|
|
||||||
autotools_stage_all
|
|
||||||
}</programlisting>
|
|
||||||
</para>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id='ref-classes-update-alternatives'>
|
<section id='ref-classes-update-alternatives'>
|
||||||
@@ -150,6 +138,10 @@ autotools_stage_all
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Currently, only one binary per package is supported.
|
||||||
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id='ref-classes-update-rc.d'>
|
<section id='ref-classes-update-rc.d'>
|
||||||
@@ -171,7 +163,7 @@ autotools_stage_all
|
|||||||
<title>Binary config scripts - <filename>binconfig.bbclass</filename></title>
|
<title>Binary config scripts - <filename>binconfig.bbclass</filename></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Before pkg-config became widespread, libraries shipped shell
|
Before pkg-config had become widespread, libraries shipped shell
|
||||||
scripts to give information about the libraries and include paths needed
|
scripts to give information about the libraries and include paths needed
|
||||||
to build software (usually named 'LIBNAME-config'). This class assists
|
to build software (usually named 'LIBNAME-config'). This class assists
|
||||||
any recipe using such scripts.
|
any recipe using such scripts.
|
||||||
@@ -305,8 +297,8 @@ autotools_stage_all
|
|||||||
output. The core generic functionality is in
|
output. The core generic functionality is in
|
||||||
<filename>package.bbclass</filename>, code specific to particular package
|
<filename>package.bbclass</filename>, code specific to particular package
|
||||||
types is contained in various sub classes such as
|
types is contained in various sub classes such as
|
||||||
<filename>package_deb.bbclass</filename> and <filename>package_ipk.bbclass</filename>.
|
<filename>package_deb.bbclass</filename>, <filename>package_ipk.bbclass</filename>
|
||||||
Most users will
|
and <filename>package_rpm.bbclass</filename>. Most users will
|
||||||
want one or more of these classes and this is controlled by the <glossterm>
|
want one or more of these classes and this is controlled by the <glossterm>
|
||||||
<link linkend='var-PACKAGE_CLASSES'>PACKAGE_CLASSES</link></glossterm>
|
<link linkend='var-PACKAGE_CLASSES'>PACKAGE_CLASSES</link></glossterm>
|
||||||
variable. The first class listed in this variable will be used for image
|
variable. The first class listed in this variable will be used for image
|
||||||
@@ -326,10 +318,10 @@ autotools_stage_all
|
|||||||
directory to allow building of out-of-tree modules using <filename>module.bbclass</filename>.
|
directory to allow building of out-of-tree modules using <filename>module.bbclass</filename>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The means that each kerel module built is packaged separately and inter-module dependencies are
|
This means that each kernel module built is packaged separately and inter-module dependencies are
|
||||||
created by parsing the <command>modinfo</command> output. If all modules are
|
created by parsing the <command>modinfo</command> output. If all modules are
|
||||||
required then installing the "kernel-modules" package will install all
|
required then installing the "kernel-modules" package will install all
|
||||||
packages with modules and various other kernel packages such as "kernel-vmlinux" are also generated.
|
packages with modules and various other kernel packages such as "kernel-vmlinux".
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -362,11 +354,11 @@ autotools_stage_all
|
|||||||
<title>Host System sanity checks - <filename>sanity.bbclass</filename></title>
|
<title>Host System sanity checks - <filename>sanity.bbclass</filename></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This class checks prerequisite software is present to try and identify
|
This class checks prerequisite software is present to
|
||||||
and notify the user of problems which will affect their build. It also
|
notify the users of potential problems that will affect their build. It
|
||||||
performs basic checks of the users configuration from local.conf to
|
also performs basic checks of the user configuration from local.conf to
|
||||||
prevent common mistakes and resulting build failures. Its usually up to
|
prevent common mistakes resulting in build failures. It's usually up to
|
||||||
distribution policy to include this class (Poky does).
|
distribution policy whether to include this class (Poky does).
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -376,10 +368,9 @@ autotools_stage_all
|
|||||||
<para>
|
<para>
|
||||||
This class adds a step to package generation which sanity checks the
|
This class adds a step to package generation which sanity checks the
|
||||||
packages generated by Poky. There are an ever increasing range of checks
|
packages generated by Poky. There are an ever increasing range of checks
|
||||||
this makes, checking for common problems which break builds/packages/images,
|
it performs, checking for common problems which break builds/packages/images,
|
||||||
see the bbclass file for more information. Its usually up to distribution
|
see the bbclass file for more information. It's usually up to distribution
|
||||||
policy to include this class (Poky does).
|
policy whether to include this class (Poky does).
|
||||||
to soon).
|
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -421,6 +412,7 @@ autotools_stage_all
|
|||||||
bootimg.bbclass
|
bootimg.bbclass
|
||||||
ccache.inc
|
ccache.inc
|
||||||
ccdv.bbclass
|
ccdv.bbclass
|
||||||
|
cmake.bbclass
|
||||||
cml1.bbclass
|
cml1.bbclass
|
||||||
cross.bbclass
|
cross.bbclass
|
||||||
flow-lossage.bbclass
|
flow-lossage.bbclass
|
||||||
@@ -430,6 +422,7 @@ autotools_stage_all
|
|||||||
gtk-icon-cache.bbclass
|
gtk-icon-cache.bbclass
|
||||||
icecc.bbclass
|
icecc.bbclass
|
||||||
lib_package.bbclass
|
lib_package.bbclass
|
||||||
|
mirrors.bbclass
|
||||||
mozilla.bbclass
|
mozilla.bbclass
|
||||||
multimachine.bbclass
|
multimachine.bbclass
|
||||||
native.bbclass
|
native.bbclass
|
||||||
@@ -450,6 +443,7 @@ autotools_stage_all
|
|||||||
syslinux.bbclass
|
syslinux.bbclass
|
||||||
tinderclient.bbclass
|
tinderclient.bbclass
|
||||||
tmake.bbclass
|
tmake.bbclass
|
||||||
|
utils.bbclass
|
||||||
xfce.bbclass
|
xfce.bbclass
|
||||||
xlibs.bbclass
|
xlibs.bbclass
|
||||||
-->
|
-->
|
||||||
@@ -6,9 +6,12 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Poky has several standard images covering most people's standard needs. A full
|
Poky has several standard images covering most people's standard needs. A full
|
||||||
list of image targets can be found by looking in the <filename class="directory">
|
list of image targets can be found by looking in the directories
|
||||||
meta/packages/images/</filename> directory. The standard images are listed below
|
<filename class="directory"> meta/recipes-core/images/</filename>,
|
||||||
along with details of what they contain:
|
<filename class="directory"> meta/recipes-extended/images/</filename>,
|
||||||
|
<filename class="directory"> meta/recipes-sato/images/</filename> and
|
||||||
|
<filename class="directory"> meta/recipes-tbd/meta/</filename>. The standard
|
||||||
|
images are listed below along with details of what they contain:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
@@ -48,7 +51,7 @@
|
|||||||
<para>
|
<para>
|
||||||
<emphasis>meta-toolchain</emphasis> - This generates a tarball containing
|
<emphasis>meta-toolchain</emphasis> - This generates a tarball containing
|
||||||
a standalone toolchain which can be used externally to Poky. It is self
|
a standalone toolchain which can be used externally to Poky. It is self
|
||||||
contained and unpacks to the <filename class="directory">/usr/local/poky</filename>
|
contained and unpacks to the <filename class="directory">/opt/poky</filename>
|
||||||
directory. It also contains a copy of QEMU and the scripts neccessary to run
|
directory. It also contains a copy of QEMU and the scripts neccessary to run
|
||||||
poky QEMU images.
|
poky QEMU images.
|
||||||
</para>
|
</para>
|
||||||
505
documentation/poky-ref-manual/ref-structure.xml
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<appendix id='ref-structure'>
|
||||||
|
|
||||||
|
<title>Reference: Directory Structure</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Poky consists of several components and understanding what these are
|
||||||
|
and where they're located is one of the keys to using it. This section walks
|
||||||
|
through the Poky directory structure giving information about the various
|
||||||
|
files and directories.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id='structure-core'>
|
||||||
|
<title>Top level core components</title>
|
||||||
|
|
||||||
|
<section id='structure-core-bitbake'>
|
||||||
|
<title><filename class="directory">bitbake/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A copy of BitBake is included within Poky for ease of use, and should
|
||||||
|
usually match the current BitBake stable release from the BitBake project.
|
||||||
|
Bitbake, a metadata interpreter, reads the Poky metadata and runs the tasks
|
||||||
|
defined in the Poky metadata. Failures are usually from the metadata, not
|
||||||
|
BitBake itself, so most users don't need to worry about BitBake. The
|
||||||
|
<filename class="directory">bitbake/bin/</filename> directory is placed
|
||||||
|
into the PATH environment variable by the <link
|
||||||
|
linkend="structure-core-script">poky-init-build-env</link> script.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
For more information on BitBake please see the BitBake project site at
|
||||||
|
<ulink url="http://bitbake.berlios.de/"/>
|
||||||
|
and the BitBake on-line manual at <ulink url="http://bitbake.berlios.de/manual/"/>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-core-build'>
|
||||||
|
<title><filename class="directory">build/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This directory contains user configuration files and the output
|
||||||
|
generated by Poky in its standard configuration where the source tree is
|
||||||
|
combined with the output. It is also possible to place output and configuration
|
||||||
|
files in a directory separate from the Poky source, see the section <link
|
||||||
|
linkend='structure-core-script'>seperate output directory</link>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-core-meta'>
|
||||||
|
<title><filename class="directory">meta/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This directory contains the core metadata, a key part of Poky. Within this
|
||||||
|
directory there are definitions of the machines, the Poky distribution
|
||||||
|
and the packages that make up a given system.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-core-meta-extras'>
|
||||||
|
<title><filename class="directory">meta-extras/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This directory is similar to <filename class="directory">meta/</filename>,
|
||||||
|
and contains some extra metadata not included in standard Poky. These are
|
||||||
|
disabled by default, and are not supported as part of Poky.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-core-meta-***'>
|
||||||
|
<title><filename class="directory">meta-***/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These directories are optional layers to be added to core metadata, which
|
||||||
|
are enabled by adding them to conf/bblayers.conf.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-core-scripts'>
|
||||||
|
<title><filename class="directory">scripts/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This directory contains various integration scripts which implement
|
||||||
|
extra functionality in the Poky environment, such as the QEMU
|
||||||
|
scripts. This directory is appended to the PATH environment variable by the
|
||||||
|
<link linkend="structure-core-script">poky-init-build-env</link> script.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-core-sources'>
|
||||||
|
<title><filename class="directory">sources/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
While not part of a checkout, Poky will create this directory as
|
||||||
|
part of any build. Any downloads are placed in this directory (as
|
||||||
|
specified by the <glossterm><link linkend='var-DL_DIR'>DL_DIR</link>
|
||||||
|
</glossterm> variable). This directory can be shared between Poky
|
||||||
|
builds to save downloading files multiple times. SCM checkouts are
|
||||||
|
also stored here as e.g. <filename class="directory">sources/svn/
|
||||||
|
</filename>, <filename class="directory">sources/cvs/</filename> or
|
||||||
|
<filename class="directory">sources/git/</filename> and the
|
||||||
|
sources directory may contain archives of checkouts for various
|
||||||
|
revisions or dates.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
It's worth noting that BitBake creates <filename class="extension">.md5
|
||||||
|
</filename> stamp files for downloads. It uses these to mark downloads as
|
||||||
|
complete as well as for checksum and access accounting purposes. If you add
|
||||||
|
a file manually to the directory, you need to touch the corresponding
|
||||||
|
<filename class="extension">.md5</filename> file too.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This location can be overridden by setting <glossterm><link
|
||||||
|
linkend='var-DL_DIR'>DL_DIR</link></glossterm> in <filename>local.conf
|
||||||
|
</filename>. This directory can be shared between builds and even between
|
||||||
|
machines via NFS, so downloads are only made once, speeding up builds.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='handbook'>
|
||||||
|
<title><filename class="directory">documentation</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This is the location for documentaiton about poky including this handbook.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-core-script'>
|
||||||
|
<title><filename>poky-init-build-env</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This script is used to setup the Poky build environment. Sourcing this file in
|
||||||
|
a shell makes changes to PATH and sets other core BitBake variables based on the
|
||||||
|
current working directory. You need to use this before running Poky commands.
|
||||||
|
Internally it uses scripts within the <filename class="directory">scripts/
|
||||||
|
</filename> directory to do the bulk of the work. This script supports
|
||||||
|
specifying any directory as the build output:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
source POKY_SRC/poky-init-build-env [BUILDDIR]
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The above command can be typed from any directory, as long as POKY_SRC points to
|
||||||
|
the desired Poky source tree. The optional BUILDDIR could be any directory you'd
|
||||||
|
like Poky to generate the build output into.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build'>
|
||||||
|
<title><filename class="directory">build/</filename> - The Build Directory</title>
|
||||||
|
|
||||||
|
<section id='structure-build-conf-local.conf'>
|
||||||
|
<title><filename>build/conf/local.conf</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This file contains all the local user configuration of Poky. If there
|
||||||
|
is no <filename>local.conf</filename> present, it is created from
|
||||||
|
<filename>local.conf.sample</filename>. The <filename>local.conf</filename>
|
||||||
|
file contains documentation on the various configuration options. Any
|
||||||
|
variable set here overrides any variable set elsewhere within Poky unless
|
||||||
|
that variable is hardcoded within Poky (e.g. by using '=' instead of '?=').
|
||||||
|
Some variables are hardcoded for various reasons but these variables are
|
||||||
|
relatively rare.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Edit this file to set the <glossterm><link linkend='var-MACHINE'>MACHINE</link></glossterm> for which you want to build, which package types you
|
||||||
|
wish to use (PACKAGE_CLASSES) or where downloaded files should go
|
||||||
|
(<glossterm><link linkend='var-DL_DIR'>DL_DIR</link></glossterm>).
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-conf-bblayers.conf'>
|
||||||
|
<title><filename>build/conf/bblayers.conf</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This file defines layers walked by bitbake. If there's no <filename>
|
||||||
|
bblayers.conf</filename> present, it is created from <filename>bblayers.conf.sample
|
||||||
|
</filename> when the environment setup script is sourced.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp'>
|
||||||
|
<title><filename class="directory">build/tmp/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This is created by BitBake if it doesn't exist and is where all the Poky output
|
||||||
|
is placed. To clean Poky and start a build from scratch (other than downloads),
|
||||||
|
you can wipe this directory. The <filename class="directory">tmp/
|
||||||
|
</filename> directory has some important sub-components detailed below.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-cache'>
|
||||||
|
<title><filename class="directory">build/tmp/cache/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When BitBake parses the metadata it creates a cache file of the result which can
|
||||||
|
be used when subsequently running commands. These are stored here on
|
||||||
|
a per machine basis.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-deploy'>
|
||||||
|
<title><filename class="directory">build/tmp/deploy/</filename></title>
|
||||||
|
|
||||||
|
<para>Any 'end result' output from Poky is placed under here.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-deploy-deb'>
|
||||||
|
<title><filename class="directory">build/tmp/deploy/deb/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Any .deb packages emitted by Poky are placed here, sorted into feeds for
|
||||||
|
different architecture types.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-deploy-rpm'>
|
||||||
|
<title><filename class="directory">build/tmp/deploy/rpm/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Any .rpm packages emitted by Poky are placed here, sorted into feeds for
|
||||||
|
different architecture types.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-deploy-images'>
|
||||||
|
<title><filename class="directory">build/tmp/deploy/images/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Complete filesystem images are placed here. If you want to flash the resulting
|
||||||
|
image from a build onto a device, look here for them.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-deploy-ipk'>
|
||||||
|
<title><filename class="directory">build/tmp/deploy/ipk/</filename></title>
|
||||||
|
|
||||||
|
<para>Any resulting .ipk packages emitted by Poky are placed here.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-sysroots'>
|
||||||
|
<title><filename class="directory">build/tmp/sysroots/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Any package needing to share output with other packages does so within sysroots.
|
||||||
|
This means it contains any shared header files and any shared libraries amongst
|
||||||
|
other data. It is subdivided by architecture so multiple builds can run within
|
||||||
|
the one build directory.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-stamps'>
|
||||||
|
<title><filename class="directory">build/tmp/stamps/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This is used by BitBake for accounting purposes to keep track of which tasks
|
||||||
|
have been run and when. It is also subdivided by architecture. The files are
|
||||||
|
empty and the important information is the filenames and timestamps.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-log'>
|
||||||
|
<title><filename class="directory">build/tmp/log/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This contains some general logs if not placing in a package's
|
||||||
|
<glossterm><link linkend='var-WORKDIR'>WORKDIR</link></glossterm>, such as
|
||||||
|
the log output from check_pkg or distro_check tasks.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-pkgdata'>
|
||||||
|
<title><filename class="directory">build/tmp/pkgdata/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This is an intermediate place for saving packaging data, which will be used
|
||||||
|
in later packaging process. For detail please refer to <link linkend='ref-classes-package'>
|
||||||
|
package.bbclass</link>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-pstagelogs'>
|
||||||
|
<title><filename class="directory">build/tmp/pstagelogs/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This directory contains manifest for task based prebuilt. Each manifest is basically
|
||||||
|
a file list for installed files from a given task, which would be useful for later
|
||||||
|
packaging or cleanup process.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-build-tmp-work'>
|
||||||
|
<title><filename class="directory">build/tmp/work/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This directory contains various subdirectories for each architecture, and each package built by BitBake has its own work directory under the appropriate architecture subdirectory. All tasks are executed from this work directory. As an example, the source for a particular package will be unpacked, patched, configured and compiled all within its own work directory.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
It is worth considering the structure of a typical work directory. An
|
||||||
|
example is the linux-rp kernel, version 2.6.20 r7 on the machine spitz
|
||||||
|
built within Poky. For this package a work directory of <filename
|
||||||
|
class="directory">tmp/work/spitz-poky-linux-gnueabi/linux-rp-2.6.20-r7/
|
||||||
|
</filename>, referred to as <glossterm><link linkend='var-WORKDIR'>WORKDIR
|
||||||
|
</link></glossterm>, is created. Within this directory, the source is
|
||||||
|
unpacked to linux-2.6.20 and then patched by quilt (see <link
|
||||||
|
linkend="usingpoky-modifying-packages-quilt">Section 3.5.1</link>).
|
||||||
|
Within the <filename class="directory">linux-2.6.20</filename> directory,
|
||||||
|
standard Quilt directories <filename class="directory">linux-2.6.20/patches</filename>
|
||||||
|
and <filename class="directory">linux-2.6.20/.pc</filename> are created,
|
||||||
|
and standard quilt commands can be used.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
There are other directories generated within <glossterm><link
|
||||||
|
linkend='var-WORKDIR'>WORKDIR</link></glossterm>. The most important
|
||||||
|
is <glossterm><link linkend='var-WORKDIR'>WORKDIR</link></glossterm><filename class="directory">/temp/</filename> which has log files for each
|
||||||
|
task (<filename>log.do_*.pid</filename>) and the scripts BitBake runs for
|
||||||
|
each task (<filename>run.do_*.pid</filename>). The <glossterm><link
|
||||||
|
linkend='var-WORKDIR'>WORKDIR</link></glossterm><filename
|
||||||
|
class="directory">/image/</filename> directory is where <command>make
|
||||||
|
install</command> places its output which is then split into subpackages
|
||||||
|
within <glossterm><link linkend='var-WORKDIR'>WORKDIR</link></glossterm>
|
||||||
|
<filename class="directory">/packages-split/</filename>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta'>
|
||||||
|
<title><filename class="directory">meta/</filename> - The Metadata</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As mentioned previously, this is the core of Poky. It has several
|
||||||
|
important subdivisions:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<section id='structure-meta-classes'>
|
||||||
|
<title><filename class="directory">meta/classes/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Contains the <filename class="extension">*.bbclass</filename> files. Class
|
||||||
|
files are used to abstract common code allowing it to be reused by multiple
|
||||||
|
packages. The <filename>base.bbclass</filename> file is inherited by every
|
||||||
|
package. Examples of other important classes are
|
||||||
|
<filename>autotools.bbclass</filename> that in theory allows any
|
||||||
|
Autotool-enabled package to work with Poky with minimal effort, or
|
||||||
|
<filename>kernel.bbclass</filename> that contains common code and functions
|
||||||
|
for working with the linux kernel. Functions like image generation or
|
||||||
|
packaging also have their specific class files (<filename>image.bbclass
|
||||||
|
</filename>, <filename>rootfs_*.bbclass</filename> and
|
||||||
|
<filename>package*.bbclass</filename>).
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-conf'>
|
||||||
|
<title><filename class="directory">meta/conf/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This is the core set of configuration files which start from
|
||||||
|
<filename>bitbake.conf</filename> and from which all other configuration
|
||||||
|
files are included (see the includes at the end of the file, even
|
||||||
|
<filename>local.conf</filename> is loaded from there!). While
|
||||||
|
<filename>bitbake.conf</filename> sets up the defaults, these can often be
|
||||||
|
overridden by user (<filename>local.conf</filename>), machine or
|
||||||
|
distribution configuration files.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-conf-machine'>
|
||||||
|
<title><filename class="directory">meta/conf/machine/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Contains all the machine configuration files. If you set MACHINE="spitz", the
|
||||||
|
end result is Poky looking for a <filename>spitz.conf</filename> file in this directory. The includes
|
||||||
|
directory contains various data common to multiple machines. If you want to add
|
||||||
|
support for a new machine to Poky, this is the directory to look in.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-conf-distro'>
|
||||||
|
<title><filename class="directory">meta/conf/distro/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Any distribution specific configuration is controlled from here. OpenEmbedded
|
||||||
|
supports multiple distributions of which Poky is one. Poky only contains the
|
||||||
|
Poky distribution so poky.conf is the main file here. This includes the
|
||||||
|
versions and SRCDATES for applications which are configured here. An example of
|
||||||
|
an alternative configuration is poky-bleeding.conf although this mainly inherits
|
||||||
|
its configuration from Poky itself.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-bsp'>
|
||||||
|
<title><filename class="directory">meta/recipes-bsp/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Anything linking to specific hardware or hardware configuration information
|
||||||
|
are placed here, such as uboot, grub, etc.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-connectivity'>
|
||||||
|
<title><filename class="directory">meta/recipes-connectivity/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Libraries and applications related to communication with other devices
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-core'>
|
||||||
|
<title><filename class="directory">meta/recipes-core/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
What's needed to build a basic working Linux image including commonly used dependencies
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-devtools'>
|
||||||
|
<title><filename class="directory">meta/recipes-devtools/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Tools primarily used by the build system (but can also be used on targets)
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-extended'>
|
||||||
|
<title><filename class="directory">meta/recipes-extended/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Applications which whilst not essential add features compared to the alternatives in
|
||||||
|
core. May be needed for full tool functionality or LSB compliance.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-gnome'>
|
||||||
|
<title><filename class="directory">meta/recipes-gnome/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
All things related to the GTK+ application framework
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-graphics'>
|
||||||
|
<title><filename class="directory">meta/recipes-graphics/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
X and other graphically related system libraries
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-kernel'>
|
||||||
|
<title><filename class="directory">meta/recipes-kernel/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The kernel and generic applications/libraries with strong kernel dependencies
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-multimedia'>
|
||||||
|
<title><filename class="directory">meta/recipes-multimedia/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Codecs and support utilties for audio, images and video
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-qt'>
|
||||||
|
<title><filename class="directory">meta/recipes-qt/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
All things related to the QT application framework
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-recipes-sato'>
|
||||||
|
<title><filename class="directory">meta/recipes-sato/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The Sato demo/reference UI/UX, its associated apps and configuration
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id='structure-meta-site'>
|
||||||
|
<title><filename class="directory">meta/site/</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Certain autoconf test results cannot be determined when cross compiling since it
|
||||||
|
can't run tests on a live system. This directory therefore contains a list of
|
||||||
|
cached results for various architectures which is passed to autoconf.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</appendix>
|
||||||
|
<!--
|
||||||
|
vim: expandtab tw=80 ts=4
|
||||||
|
-->
|
||||||
@@ -107,32 +107,23 @@
|
|||||||
<glossentry id='var-COMPATIBLE_MACHINE'><glossterm>COMPATIBLE_MACHINE</glossterm>
|
<glossentry id='var-COMPATIBLE_MACHINE'><glossterm>COMPATIBLE_MACHINE</glossterm>
|
||||||
<glossdef>
|
<glossdef>
|
||||||
<para>A regular expression which evalutates to match the machines the recipe
|
<para>A regular expression which evalutates to match the machines the recipe
|
||||||
works with. It stops recipes being run on machines they're incompatible with
|
works with. It stops recipes being run on machines they're incompatible with,
|
||||||
which is partciuarly useful with kernels. It also helps to to increase parsing
|
which is partciuarly useful with kernels. It also helps to increase parsing
|
||||||
speed as if its found the current machine is not compatible, further parsing
|
speed as further parsing of the recipe is skipped as if it found the current
|
||||||
of the recipe is skipped.</para>
|
machine is not compatible.</para>
|
||||||
</glossdef>
|
</glossdef>
|
||||||
</glossentry>
|
</glossentry>
|
||||||
|
|
||||||
<glossentry id='var-CONFIG_SITE'><glossterm>CONFIG_SITE</glossterm>
|
<glossentry id='var-CONFIG_SITE'><glossterm>CONFIG_SITE</glossterm>
|
||||||
<glossdef>
|
<glossdef>
|
||||||
<para>
|
<para>
|
||||||
Contains a list of files which containing autoconf test results relevant
|
A list of files which contains autoconf test results relevant
|
||||||
to the current build. This variable is used by the autotools utilities
|
to the current build. This variable is used by the autotools utilities
|
||||||
when running configure.
|
when running configure.
|
||||||
</para>
|
</para>
|
||||||
</glossdef>
|
</glossdef>
|
||||||
</glossentry>
|
</glossentry>
|
||||||
|
|
||||||
|
|
||||||
<glossentry id='var-CVS_TARBALL_STASH'><glossterm>CVS_TARBALL_STASH</glossterm>
|
|
||||||
<glossdef>
|
|
||||||
<para>Location to search for
|
|
||||||
pre-generated tarballs when fetching from remote SCM
|
|
||||||
repositories (CVS/SVN/GIT)</para>
|
|
||||||
</glossdef>
|
|
||||||
</glossentry>
|
|
||||||
|
|
||||||
</glossdiv>
|
</glossdiv>
|
||||||
|
|
||||||
<glossdiv id='var-glossary-d'><title>D</title>
|
<glossdiv id='var-glossary-d'><title>D</title>
|
||||||
@@ -226,7 +217,6 @@
|
|||||||
<glossentry id='var-DISTRO_PN_ALIAS'><glossterm>DISTRO_PN_ALIAS</glossterm>
|
<glossentry id='var-DISTRO_PN_ALIAS'><glossterm>DISTRO_PN_ALIAS</glossterm>
|
||||||
<glossdef>
|
<glossdef>
|
||||||
<para>Alias names of the recipe in various Linux distributions. </para>
|
<para>Alias names of the recipe in various Linux distributions. </para>
|
||||||
<para>See the "meta/package/xorg-app/xset_1.0.4.bb" file for an example</para>
|
|
||||||
<para>More information in
|
<para>More information in
|
||||||
<link
|
<link
|
||||||
linkend='usingpoky-configuring-DISTRO_PN_ALIAS'>
|
linkend='usingpoky-configuring-DISTRO_PN_ALIAS'>
|
||||||
@@ -260,6 +250,12 @@
|
|||||||
</glossdef>
|
</glossdef>
|
||||||
</glossentry>
|
</glossentry>
|
||||||
|
|
||||||
|
<glossentry id='var-EXTRA_OECMAKE'><glossterm>EXTRA_OECMAKE</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>Additional cmake options</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
|
||||||
<glossentry id='var-EXTRA_OECONF'><glossterm>EXTRA_OECONF</glossterm>
|
<glossentry id='var-EXTRA_OECONF'><glossterm>EXTRA_OECONF</glossterm>
|
||||||
<glossdef>
|
<glossdef>
|
||||||
<para>Additional 'configure' script options</para>
|
<para>Additional 'configure' script options</para>
|
||||||
@@ -428,13 +424,13 @@
|
|||||||
<glossdef>
|
<glossdef>
|
||||||
<para>Checksums of the license text in the recipe source code.
|
<para>Checksums of the license text in the recipe source code.
|
||||||
</para>
|
</para>
|
||||||
<para>This variables tracks changes in license text of the source
|
<para>This variable tracks changes in license text of the source
|
||||||
code files. If the license text is changed it triggers the build
|
code files. If the license text is changed, it will trigger the build
|
||||||
failure. Which gives developer an oppurtunity to review any
|
failure, which gives developer an opportunity to review any
|
||||||
license changes</para>
|
license change</para>
|
||||||
<para> This is an optional variable now. And the plan is to make
|
<para> This is an optional variable now, and the plan is to make
|
||||||
it a required variable in the future </para>
|
it a required variable in the future </para>
|
||||||
<para>See the "meta/package/zlib/zlib_${PV}.bb" file for an example</para>
|
<para>See "meta/package/zlib/zlib_${PV}.bb" file for an example</para>
|
||||||
|
|
||||||
<para>More information in <link
|
<para>More information in <link
|
||||||
linkend='usingpoky-configuring-LIC_FILES_CHKSUM'>
|
linkend='usingpoky-configuring-LIC_FILES_CHKSUM'>
|
||||||
@@ -458,7 +454,7 @@
|
|||||||
</glossdef>
|
</glossdef>
|
||||||
</glossentry>
|
</glossentry>
|
||||||
|
|
||||||
<glossentry id='var-MACHINE_ESSENTIAL_RRECOMMENDS'><glossterm>MACHINE_ESSENTIAL_RRECOOMENDS</glossterm>
|
<glossentry id='var-MACHINE_ESSENTIAL_RRECOMMENDS'><glossterm>MACHINE_ESSENTIAL_RRECOMMENDS</glossterm>
|
||||||
<glossdef>
|
<glossdef>
|
||||||
<para>List of packages required to boot device (usually
|
<para>List of packages required to boot device (usually
|
||||||
additional kernel modules)</para>
|
additional kernel modules)</para>
|
||||||
@@ -595,7 +591,7 @@
|
|||||||
|
|
||||||
<glossentry id='var-POKYLIBC'><glossterm>POKYLIBC</glossterm>
|
<glossentry id='var-POKYLIBC'><glossterm>POKYLIBC</glossterm>
|
||||||
<glossdef>
|
<glossdef>
|
||||||
<para>Libc implementation selector - glibc or uclibc can be selected.</para>
|
<para>Libc implementation selector - glibc, eglibc, or uclibc can be selected.</para>
|
||||||
</glossdef>
|
</glossdef>
|
||||||
</glossentry>
|
</glossentry>
|
||||||
|
|
||||||
@@ -616,9 +612,9 @@
|
|||||||
|
|
||||||
<glossentry id='var-RCONFLICTS'><glossterm>RCONFLICTS</glossterm>
|
<glossentry id='var-RCONFLICTS'><glossterm>RCONFLICTS</glossterm>
|
||||||
<glossdef>
|
<glossdef>
|
||||||
<para>List of packages which which conflict with this
|
<para>List of packages which conflict with this
|
||||||
one. Package will not be installed if they will not
|
one. Package will not be installed if they are not
|
||||||
be removed first.</para>
|
removed first.</para>
|
||||||
</glossdef>
|
</glossdef>
|
||||||
</glossentry>
|
</glossentry>
|
||||||
|
|
||||||
@@ -646,7 +642,7 @@
|
|||||||
|
|
||||||
<glossentry id='var-RRECOMMENDS'><glossterm>RRECOMMENDS</glossterm>
|
<glossentry id='var-RRECOMMENDS'><glossterm>RRECOMMENDS</glossterm>
|
||||||
<glossdef>
|
<glossdef>
|
||||||
<para>List of packages which extend usability of
|
<para>List of packages which extend usability of the
|
||||||
package. Those packages will be automatically
|
package. Those packages will be automatically
|
||||||
installed but can be removed by user.</para>
|
installed but can be removed by user.</para>
|
||||||
</glossdef>
|
</glossdef>
|
||||||
@@ -703,16 +699,7 @@
|
|||||||
<glossdef>
|
<glossdef>
|
||||||
<para>
|
<para>
|
||||||
A list of commands to run within the a shell, used by <glossterm><link
|
A list of commands to run within the a shell, used by <glossterm><link
|
||||||
linkend='var-TERMCMDRUN'>TERMCMDRUN</link></glossterm>. It defaults to
|
linkend='var-TERMCMDRUN'>TERMCMDRUN</link></glossterm>.
|
||||||
<glossterm><link linkend='var-SHELLRCCMD'>SHELLRCCMD</link></glossterm>.
|
|
||||||
</para>
|
|
||||||
</glossdef>
|
|
||||||
</glossentry>
|
|
||||||
|
|
||||||
<glossentry id='var-SHELLRCCMD'><glossterm>SHELLRCCMD</glossterm>
|
|
||||||
<glossdef>
|
|
||||||
<para>
|
|
||||||
How to launch a shell, defaults to bash.
|
|
||||||
</para>
|
</para>
|
||||||
</glossdef>
|
</glossdef>
|
||||||
</glossentry>
|
</glossentry>
|
||||||
@@ -790,6 +777,12 @@
|
|||||||
</glossdef>
|
</glossdef>
|
||||||
</glossentry>
|
</glossentry>
|
||||||
|
|
||||||
|
<glossentry id='var-SUMMARY'><glossterm>SUMMARY</glossterm>
|
||||||
|
<glossdef>
|
||||||
|
<para>Short (72 char suggested) Summary of binary package for packaging sytems such as ipkg, rpm or debian, inherits DESCRIPTION by default</para>
|
||||||
|
</glossdef>
|
||||||
|
</glossentry>
|
||||||
|
|
||||||
</glossdiv>
|
</glossdiv>
|
||||||
|
|
||||||
<glossdiv id='var-glossary-t'><title>T</title>
|
<glossdiv id='var-glossary-t'><title>T</title>
|
||||||
@@ -108,9 +108,6 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para><glossterm linkend='var-BBINCLUDELOGS'><link linkend='var-BBINCLUDELOGS'>BBINCLUDELOGS</link></glossterm></para>
|
<para><glossterm linkend='var-BBINCLUDELOGS'><link linkend='var-BBINCLUDELOGS'>BBINCLUDELOGS</link></glossterm></para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
|
||||||
<para><glossterm linkend='var-CVS_TARBALL_STASH'><link linkend='var-CVS_TARBALL_STASH'>CVS_TARBALL_STASH</link></glossterm></para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para><glossterm linkend='var-ENABLE_BINARY_LOCALE_GENERATION'><link linkend='var-ENABLE_BINARY_LOCALE_GENERATION'>ENABLE_BINARY_LOCALE_GENERATION</link></glossterm></para>
|
<para><glossterm linkend='var-ENABLE_BINARY_LOCALE_GENERATION'><link linkend='var-ENABLE_BINARY_LOCALE_GENERATION'>ENABLE_BINARY_LOCALE_GENERATION</link></glossterm></para>
|
||||||
</listitem>
|
</listitem>
|
||||||
@@ -191,6 +188,9 @@
|
|||||||
<para><glossterm><link
|
<para><glossterm><link
|
||||||
linkend='var-DISTRO_PN_ALIAS'>DISTRO_PN_ALIAS</link></glossterm></para>
|
linkend='var-DISTRO_PN_ALIAS'>DISTRO_PN_ALIAS</link></glossterm></para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><glossterm><link linkend='var-EXTRA_OECMAKE'>EXTRA_OECMAKE</link></glossterm></para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para><glossterm><link linkend='var-EXTRA_OECONF'>EXTRA_OECONF</link></glossterm></para>
|
<para><glossterm><link linkend='var-EXTRA_OECONF'>EXTRA_OECONF</link></glossterm></para>
|
||||||
</listitem>
|
</listitem>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Problems with Poky should be reported in the
|
Problems with Poky should be reported in the
|
||||||
<ulink url='http://bugzilla.o-hand.com/'>bug tracker</ulink>.
|
<ulink url='http://bugzilla.pokylinux.org/'>bug tracker</ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -127,10 +127,10 @@ poky+subscribe <at> openedhand <dot> com
|
|||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
A Poky contributions tree (poky-contrib) exists for people to stage
|
A Poky contributions tree (poky-contrib, git://git.pokylinux.org/poky-contrib.git)
|
||||||
contributions in, for regular contributors. If people desire such
|
exists for people to stage contributions in, for regular contributors.
|
||||||
access, please ask on the mailing list. Usually access will be given
|
If people desire such access, please ask on the mailing list. Usually
|
||||||
to anyone with a proven track record of good patches.
|
access will be given to anyone with a proven track record of good patches.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |