Compare commits
800 commits
pexpect-ti
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
42673b7e6d | ||
|
3178799798 | ||
|
0ad4189798 | ||
|
3d8f6879ce | ||
|
643d19af4e | ||
|
f9b1acf4a0 | ||
|
b9245f33ab | ||
|
966d6f2fdd | ||
|
593319c3ba | ||
|
2464434e4b | ||
|
8c2b1d9641 | ||
|
530974e08c | ||
|
8673e59cfd | ||
|
b7e312255d | ||
|
0a8e401877 | ||
|
f81d21adac | ||
|
ddf68cec0b | ||
|
ead2d9f29f | ||
|
56d047875c | ||
|
6dcbe7ab9f | ||
|
290735a672 | ||
|
82ab5b3f48 | ||
|
e587305308 | ||
|
1a3fb61b37 | ||
|
d2944ad54c | ||
|
b24b77b36e | ||
|
7ebc048c97 | ||
|
605cf522fd | ||
|
487a5979bf | ||
|
53bacca6ef | ||
|
54b2975f57 | ||
|
cd380cc87b | ||
|
eecb248101 | ||
|
52facfa280 | ||
|
b60055cdc0 | ||
|
bc5b92e11f | ||
|
3e008a4609 | ||
|
5f74603349 | ||
|
84d9390805 | ||
|
513ad560b7 | ||
|
5d75e75376 | ||
|
2f07073759 | ||
|
2c445735bf | ||
|
fdb3d78739 | ||
|
3198f244f2 | ||
|
0d9b536407 | ||
|
d27020fe4e | ||
|
c9345fa06a | ||
|
7b35b3d030 | ||
|
7bf9f39709 | ||
|
4a18fb321e | ||
|
236cdaee16 | ||
|
79e16e23ee | ||
|
be801e0ab8 | ||
|
459807465a | ||
|
3f851ec924 | ||
|
f858adfa7e | ||
|
a9fc2fce61 | ||
|
1323c057e1 | ||
|
ece5748982 | ||
|
a967c0912e | ||
|
020a5504f3 | ||
|
af577b6138 | ||
|
afab91caf8 | ||
|
a3704e7fb7 | ||
|
40c79e5a93 | ||
|
e8b20d5beb | ||
|
25a5a11b64 | ||
|
3081af7cca | ||
|
2d9c05af58 | ||
|
ff55af5a05 | ||
|
47630e848b | ||
|
ffe73a67b5 | ||
|
5d7610cf6c | ||
|
94cfcb8d59 | ||
|
4a2bf27cda | ||
|
ce114822df | ||
|
435d6a21eb | ||
|
697139d1f5 | ||
|
4bffaa64a1 | ||
|
32c5b8379c | ||
|
7a9bbeb9a8 | ||
|
dccb7e82e3 | ||
|
5dcc879bfb | ||
|
a6d3b3ec56 | ||
|
9527f2ab96 | ||
|
5b541de4d8 | ||
|
5b00b613f9 | ||
|
a815afc5e0 | ||
|
a09beb0542 | ||
|
43214d4dd4 | ||
|
c0ccfda405 | ||
|
4333b9c048 | ||
|
10a2fb9848 | ||
|
ac6c339fe0 | ||
|
9a9d591ec4 | ||
|
a11f2b8b20 | ||
|
bb5c0ccbde | ||
|
b677c8ed77 | ||
|
a69346af0a | ||
|
f700d80f79 | ||
|
008f494e11 | ||
|
0ddf6e0909 | ||
|
cf89c32042 | ||
|
3d7f47e70b | ||
|
1d707d9471 | ||
|
446492f440 | ||
|
0eb99dd9f1 | ||
|
4141a20f99 | ||
|
d8c4e917bd | ||
|
49a3491220 | ||
|
5517322766 | ||
|
f2d31ccd32 | ||
|
8d2a9df928 | ||
|
f564e1b688 | ||
|
5f099a8650 | ||
|
20bfa24005 | ||
|
d0323c165d | ||
|
d74aef3dcd | ||
|
5f80316cb0 | ||
|
1f8c88fe7b | ||
|
891e24b6f2 | ||
|
504efcc243 | ||
|
cd11167067 | ||
|
d3fd1ad9e3 | ||
|
b566125f71 | ||
|
757941aabb | ||
|
35cce59e63 | ||
|
d3361bbcfb | ||
|
ee34d7e95b | ||
|
5f35e8b409 | ||
|
422f951931 | ||
|
58774d8aac | ||
|
6b03c54832 | ||
|
ef63f13111 | ||
|
3f1b44de6f | ||
|
556724f62d | ||
|
0c4116c469 | ||
|
7daf3d028c | ||
|
090cb5b36e | ||
|
21d4157573 | ||
|
a155929bdc | ||
|
916dc6ba2a | ||
|
05f0024b26 | ||
|
c7d0a5a7c3 | ||
|
c9004f1d77 | ||
|
cceab3c2ce | ||
|
439a3619e4 | ||
|
1ff55c4fca | ||
|
a294071a60 | ||
|
4165a38897 | ||
|
d97d60f67c | ||
|
7578fea609 | ||
|
e5cc1855da | ||
|
b40bd68d6e | ||
|
384cea43a1 | ||
|
1b2e981892 | ||
|
664faa7583 | ||
|
636bc2fe15 | ||
|
8c88e3cc7d | ||
|
5351e7d041 | ||
|
8fa06fe3d9 | ||
|
5f67c04b69 | ||
|
69d418491f | ||
|
526607e17d | ||
|
b4fd5d933b | ||
|
a3ae25fa00 | ||
|
4799f7d931 | ||
|
c70fb74366 | ||
|
345168cbb7 | ||
|
c3617ff0ab | ||
|
2fb4399767 | ||
|
b6981f8c57 | ||
|
bc11bd6066 | ||
|
81c31c4d1e | ||
|
8e56f880ce | ||
|
9fcf28ba44 | ||
|
d483847bb5 | ||
|
99ad83a2b9 | ||
|
f01d09cdaf | ||
|
569c012676 | ||
|
e58ad280bd | ||
|
fa117686c8 | ||
|
31d35e5785 | ||
|
2af534652d | ||
|
c92b3ef925 | ||
|
581a1ba2da | ||
|
e95844e1b3 | ||
|
8d4ad8b60f | ||
|
182d13f102 | ||
|
8dd22bd4d4 | ||
|
7a0ef4f10c | ||
|
3583bb2ad7 | ||
|
cfdcad4857 | ||
|
c782e65556 | ||
|
e2c3e6656c | ||
|
1d1b0b7c80 | ||
|
1fac86dbff | ||
|
1e7cc7f9c4 | ||
|
dbe02e3106 | ||
|
2adb7e157c | ||
|
6ce80697f8 | ||
|
81c825f6c6 | ||
|
3deca91485 | ||
|
1bb1c56784 | ||
|
f271dda98d | ||
|
f9b5b07b4f | ||
|
5ede887a4e | ||
|
c0d625252e | ||
|
678b1bf52c | ||
|
11b733cbd9 | ||
|
f729829788 | ||
|
c803e68687 | ||
|
81b6ac51a3 | ||
|
586152c6ce | ||
|
53b16c933f | ||
|
4183428daa | ||
|
ec1ede62d2 | ||
|
5540f84452 | ||
|
dfd2ceb324 | ||
|
f8f96e4eb7 | ||
|
33854f82a3 | ||
|
06a964dbe4 | ||
|
2b09e1a0bb | ||
|
1edbb7e0e5 | ||
|
5cde0b0f92 | ||
|
4c2152b36e | ||
|
831d85a5e0 | ||
|
2b4046145f | ||
|
eabbf2b95e | ||
|
4ec6040e42 | ||
|
366aff9c60 | ||
|
37d6a55f7d | ||
|
71aae60e31 | ||
|
1d2b675729 | ||
|
61182d6b8b | ||
|
cf880a390c | ||
|
cf62bf8a89 | ||
|
3e4e2266c8 | ||
|
6142acfa40 | ||
|
93af45c46d | ||
|
17e8e81bca | ||
|
46bcf9575c | ||
|
956d7b94ae | ||
|
3b023a2d49 | ||
|
07a6a41f04 | ||
|
9c137b06a7 | ||
|
8fcbd21eef | ||
|
afebba5f3c | ||
|
4fb7f6e88b | ||
|
197be74037 | ||
|
fbf4a1fe2f | ||
|
0d22e60e2e | ||
|
c88f048739 | ||
|
4ff4bac945 | ||
|
205f1f62ed | ||
|
4983e8f08d | ||
|
e0d29f993b | ||
|
91ba12d437 | ||
|
3263983d6b | ||
|
742491d9d0 | ||
|
c0849ba2b2 | ||
|
756d6e6243 | ||
|
88e4a4b0c7 | ||
|
0efcf452d6 | ||
|
5db8187fd4 | ||
|
e24e571ba6 | ||
|
7c9239dd59 | ||
|
115e6ca4e2 | ||
|
63926eb981 | ||
|
a780cc470a | ||
|
f815965159 | ||
|
100bf932e7 | ||
|
6d1d5e9b0d | ||
|
965204910c | ||
|
632731cc98 | ||
|
31b1eaeb43 | ||
|
07c8b9ec8e | ||
|
165dde84b1 | ||
|
4936d31828 | ||
|
74e26fe6f2 | ||
|
f304ada796 | ||
|
07b910c62b | ||
|
9bc08dc731 | ||
|
b520c00c82 | ||
|
c8e888dbbf | ||
|
ee833cfe98 | ||
|
f3256cf847 | ||
|
e8ad30e103 | ||
|
da9d59f96e | ||
|
823018eb07 | ||
|
5a912a7949 | ||
|
27d8880411 | ||
|
d354782dc2 | ||
|
bf6b88de3d | ||
|
0407331084 | ||
|
58faefa243 | ||
|
be52c21467 | ||
|
c66af5dc0b | ||
|
46cc8f715b | ||
|
152d5417b0 | ||
|
44bbd13b47 | ||
|
532077e2a3 | ||
|
6b004f9778 | ||
|
ebfc90eecc | ||
|
7fb6535c08 | ||
|
05cdd90e20 | ||
|
2be2d77ffa | ||
|
98a7395ebf | ||
|
4296edc472 | ||
|
9fd345951c | ||
|
c4c632f7da | ||
|
635f0ddc0d | ||
|
d77d9714ff | ||
|
9bb9dd590c | ||
|
98c2f36a11 | ||
|
96bbbebf0b | ||
|
92291353a5 | ||
|
50cc61681e | ||
|
70440b0d92 | ||
|
ece71cdac6 | ||
|
e14207e3ed | ||
|
6d447817aa | ||
|
d2550ee5c3 | ||
|
88eaa7f332 | ||
|
ecc499c23a | ||
|
c05c7d437c | ||
|
0c9fbb9783 | ||
|
761727a9b2 | ||
|
a6cd679c5c | ||
|
6447933ed3 | ||
|
c8093da21e | ||
|
8bfb6331e9 | ||
|
d60abf0ff9 | ||
|
6e6a889479 | ||
|
58bec60ecd | ||
|
4f4d8eb4e5 | ||
|
4e87eaa795 | ||
|
8abcf26fbb | ||
|
0e1c1263fd | ||
|
e4182fea1c | ||
|
b922dee09b | ||
|
eb9007dc78 | ||
|
01a4d92ea5 | ||
|
52ece9ba0f | ||
|
862f7f4377 | ||
|
94ee397117 | ||
|
9ea40e6c48 | ||
|
502dcd3aa7 | ||
|
fec6610fbd | ||
|
0abbee5661 | ||
|
618faa076d | ||
|
10a3915c67 | ||
|
a63979279f | ||
|
5af135fca4 | ||
|
f2e6c19e81 | ||
|
4a1253e00a | ||
|
79a713273b | ||
|
6df7acd675 | ||
|
48f9b74691 | ||
|
a3d4e07465 | ||
|
71dbc6673c | ||
|
6b4a3331e3 | ||
|
b1ec6e8703 | ||
|
36ea4ba265 | ||
|
7b3a4c760f | ||
|
c502370af6 | ||
|
c997016d98 | ||
|
d1688178df | ||
|
f6dfa3f09a | ||
|
068bf9c42e | ||
|
84561c3aa8 | ||
|
794461190c | ||
|
b154b7d84e | ||
|
a8f764f786 | ||
|
42fddafe2b | ||
|
52df08c8e2 | ||
|
ab2f895bab | ||
|
cb57e4ea1c | ||
|
2e583b349b | ||
|
d3628f1568 | ||
|
f3560b4f84 | ||
|
ef5e5865fc | ||
|
59ae01db21 | ||
|
94691c0138 | ||
|
94e9172f47 | ||
|
3ddaf220d0 | ||
|
b00ee94225 | ||
|
fccef474cf | ||
|
7b48f20341 | ||
|
9307e8c06c | ||
|
1edad89683 | ||
|
63c24587af | ||
|
773a38cd34 | ||
|
7753c93ed0 | ||
|
83ad94d626 | ||
|
fc95dcb2af | ||
|
93e958f46e | ||
|
7a41562038 | ||
|
34168f58b2 | ||
|
d816451c4b | ||
|
be0ec3b52b | ||
|
2e1675164e | ||
|
57b18edec6 | ||
|
4935739c84 | ||
|
ea3c3b58db | ||
|
db228a640b | ||
|
0fa30c8032 | ||
|
103cd11478 | ||
|
b79fdb1a88 | ||
|
ff8cf7893f | ||
|
3771bf46c2 | ||
|
1b1dfb0c75 | ||
|
3a93783aa8 | ||
|
6a8209d081 | ||
|
43f293cdde | ||
|
a424fb7194 | ||
|
f672f258fe | ||
|
3b204cbb93 | ||
|
4ab270f8fe | ||
|
6f62acc957 | ||
|
a8b0d3e3fc | ||
|
a0ece89e75 | ||
|
075e11ab3b | ||
|
827f943698 | ||
|
457ee51a07 | ||
|
bd63c8f317 | ||
|
c256fd294f | ||
|
8f3f1bc3e9 | ||
|
760ca8ee97 | ||
|
e24b843bae | ||
|
7b87d80560 | ||
|
8a4db79ecc | ||
|
480e726011 | ||
|
92ef490f63 | ||
|
6fcbb4eb21 | ||
|
ad0a8132ae | ||
|
8f9ab2208c | ||
|
127c581f5b | ||
|
b656922f6b | ||
|
e2b46c0502 | ||
|
a71e1ff600 | ||
|
11f9dfaa50 | ||
|
48ea268636 | ||
|
9685bff223 | ||
|
f55147e300 | ||
|
93cf05eb8c | ||
|
a06707dac7 | ||
|
c704b81ccf | ||
|
49f8bf4558 | ||
|
855937e593 | ||
|
de9eeefbaf | ||
|
129570c0fe | ||
|
70995b1989 | ||
|
b522bf9c49 | ||
|
f02b1d4a73 | ||
|
3d4791df7e | ||
|
a9de15a905 | ||
|
bb643ce15b | ||
|
7b2a2712db | ||
|
1c469abb46 | ||
|
3231c05079 | ||
|
1d7fca59bf | ||
|
63b3d8aebc | ||
|
d7f15a9311 | ||
|
d323d43be9 | ||
|
38f4b294c1 | ||
|
fca0848f94 | ||
|
baaf8ad3fc | ||
|
5c7fac3dcf | ||
|
8bdb2fe750 | ||
|
29965a6e08 | ||
|
9602ea2959 | ||
|
4cd2e17d19 | ||
|
75d2730a4c | ||
|
bbd1836b9d | ||
|
8d177faa16 | ||
|
517bb71508 | ||
|
5538431f33 | ||
|
13e3c2266b | ||
|
5e4cd5a947 | ||
|
31e8a5ace0 | ||
|
925ef6c49f | ||
|
2ec50fd84f | ||
|
7ee7150a73 | ||
|
959bdb3d7f | ||
|
61009a2e3d | ||
|
904c9c70d7 | ||
|
c6061bdfc0 | ||
|
a6b4c6be20 | ||
|
a4994afb0f | ||
|
d1c0560a67 | ||
|
81b1a498dd | ||
|
3e931fc706 | ||
|
d7e5e98bec | ||
|
f3baa64f63 | ||
|
da461e4906 | ||
|
afa0c78857 | ||
|
aa3745842f | ||
|
8ddabd405e | ||
|
99431ee74c | ||
|
0dd1c5df9c | ||
|
9848996e07 | ||
|
11bac03791 | ||
|
03ba127b66 | ||
|
e718520c6c | ||
|
b1f34c75fd | ||
|
90981b4e55 | ||
|
cd93f9bfe9 | ||
|
ec81eed43f | ||
|
332aa15ce9 | ||
|
c4b03d9f4f | ||
|
07b67d5a09 | ||
|
a52236237d | ||
|
0192884222 | ||
|
e9419c0df0 | ||
|
68a6c8e04c | ||
|
53c9bddb8c | ||
|
0a8c644d74 | ||
|
335a845c8d | ||
|
474db95dd4 | ||
|
35ba75db51 | ||
|
68245e2dd1 | ||
|
e209cf0d3e | ||
|
1d29ab17db | ||
|
e8c7769038 | ||
|
5eb91ca156 | ||
|
e462a9c0e8 | ||
|
272e72f31b | ||
|
e0de334912 | ||
|
92008de8d1 | ||
|
7f6a2fe864 | ||
|
cc8aa97cb1 | ||
|
45967285ad | ||
|
c78acee103 | ||
|
0fe5b934a5 | ||
|
22317365f4 | ||
|
a1eb0d8c95 | ||
|
5e3e1ec0f5 | ||
|
be33b7595c | ||
|
395999306b | ||
|
e07728f7f0 | ||
|
5a1d002bb8 | ||
|
2a3fe470d2 | ||
|
15fd1cf591 | ||
|
0e852dce46 | ||
|
e90de63195 | ||
|
2403147c41 | ||
|
48cd8f206e | ||
|
77fc345015 | ||
|
c0aae22d54 | ||
|
0af7976a64 | ||
|
818e0b2825 | ||
|
d560bef7d3 | ||
|
20f5171a6d | ||
|
1f64fde8f8 | ||
|
50233a5217 | ||
|
bc58394308 | ||
|
9cd2d17a38 | ||
|
b88875021a | ||
|
dbef11b7ae | ||
|
8bd0d5e145 | ||
|
61f58d7bb7 | ||
|
f200b836a9 | ||
|
4ddd57ded2 | ||
|
b544f80e13 | ||
|
85587db73e | ||
|
fcc0c60d48 | ||
|
67d5d748db | ||
|
8489b670ad | ||
|
aab0028ea4 | ||
|
9a43b20f05 | ||
|
6c70972057 | ||
|
bbd0276a93 | ||
|
cb116c4cfc | ||
|
5c4e5f1d6c | ||
|
e58d89c7b7 | ||
|
4316383884 | ||
|
17ff7efe6c | ||
|
a113e46f26 | ||
|
49d56f0961 | ||
|
3ec383479b | ||
|
dd82576da9 | ||
|
680b2dc9ea | ||
|
0740cef5b8 | ||
|
fed06506a3 | ||
|
9030a4c03f | ||
|
2a99a64940 | ||
|
874dbe3fa5 | ||
|
442fda7a73 | ||
|
4c59f1b849 | ||
|
dfe8c567e2 | ||
|
ef2357d0dd | ||
|
fba03a8d3b | ||
|
f9cc07dfe1 | ||
|
10333efcaf | ||
|
768bb5c8f6 | ||
|
37f4dac9e7 | ||
|
a222101896 | ||
|
09b085465d | ||
|
493644673b | ||
|
0f36e6394d | ||
|
7f9fe9fe51 | ||
|
26f3830039 | ||
|
72b2039d76 | ||
|
53cc7f1bea | ||
|
0f29a24b18 | ||
|
d80814f850 | ||
|
b4f21f7f54 | ||
|
c335f42f4c | ||
|
31eb8b42a2 | ||
|
f29450bc5c | ||
|
31f2143359 | ||
|
38f80ab5e4 | ||
|
83a44887b5 | ||
|
7091cf098c | ||
|
77c5e7c08e | ||
|
69bf2823c6 | ||
|
4a10184d1f | ||
|
0362a494fa | ||
|
6986919d68 | ||
|
865928f95f | ||
|
bcefc5395c | ||
|
8b2d2a47b0 | ||
|
4cc8bebb46 | ||
|
54e4577e78 | ||
|
45b3e10949 | ||
|
f247c2c2e8 | ||
|
658a485e09 | ||
|
7954647566 | ||
|
a1f8f4e066 | ||
|
60ec904f60 | ||
|
42387f8b1b | ||
|
97f9e293e0 | ||
|
9dec41774b | ||
|
5247ad5d3b | ||
|
c5f5c33e01 | ||
|
4dfc89711d | ||
|
3e25b69f54 | ||
|
f5a3712cf8 | ||
|
6dbc40d65f | ||
|
8e6556da73 | ||
|
c070d7984d | ||
|
7ecddd5b9a | ||
|
def8a7adfb | ||
|
62f4737136 | ||
|
42873ecee1 | ||
|
3fa83089bb | ||
|
04e3530fdb | ||
|
3fc3c63e47 | ||
|
c7fca65d04 | ||
|
ecc5698893 | ||
|
f2fc785895 | ||
|
029d5603cd | ||
|
7d8cddbbb9 | ||
|
917b37d393 | ||
|
fc6ca06278 | ||
|
b6c69a68d0 | ||
|
b20ddf810d | ||
|
279dbfe69c | ||
|
d392c3c022 | ||
|
4112910da0 | ||
|
cfbc4bb9c8 | ||
|
23310f350e | ||
|
1804bfcb92 | ||
|
d5bdf07032 | ||
|
4377649964 | ||
|
7f946a7f16 | ||
|
100d84a883 | ||
|
d97e70c44d | ||
|
732a9fac0a | ||
|
12964f488f | ||
|
e4a4d2ad1b | ||
|
c19575a7d5 | ||
|
284a69ca55 | ||
|
eaa5daf801 | ||
|
4b5ff9f67d | ||
|
ca71804897 | ||
|
c4c74050bf | ||
|
6f842d01ce | ||
|
d20dd4676c | ||
|
c99b1190fe | ||
|
3dda7f2d8e | ||
|
3a24529fc3 | ||
|
dd64f96ebd | ||
|
0c9d9ab17c | ||
|
93d35a951e | ||
|
501dcb9161 | ||
|
64c9a47d72 | ||
|
23ecb9709c | ||
|
2436562570 | ||
|
ac5c557cd2 | ||
|
1bd6579582 | ||
|
1e9f3d994b | ||
|
ce640fc1d7 | ||
|
72e660ede5 | ||
|
328bd0fe84 | ||
|
b02f074c24 | ||
|
b6d8eb9d13 | ||
|
4d76f5f0e6 | ||
|
5c9eb51c66 | ||
|
a49a9abab9 | ||
|
0c48a4aa47 | ||
|
aae2b6f2d8 | ||
|
d5610d544d | ||
|
64c5328ac7 | ||
|
2ab30b6df3 | ||
|
122252f9f7 | ||
|
b17a0ef6c1 | ||
|
4b12f34d06 | ||
|
e6f04865bb | ||
|
7990e1cfa3 | ||
|
5e39fb5539 | ||
|
5961cef9e6 | ||
|
c2626e6c53 | ||
|
e3252c5742 | ||
|
be3c5f1a90 | ||
|
0cdf4fc0bd | ||
|
a327e9249b | ||
|
86752239cf | ||
|
ff37b04a3b | ||
|
c163a14417 | ||
|
41dae4d42f | ||
|
043c7c19c7 | ||
|
0eca4a2976 | ||
|
df6e494b77 | ||
|
c6b423596f | ||
|
fdc2bb59ca | ||
|
3a3d726bf7 | ||
|
2357912b15 | ||
|
97f8ffdc4d | ||
|
89f8f92d82 | ||
|
7a6034a75e | ||
|
dbd6be6e4b | ||
|
312fb67be4 | ||
|
ca2f69da74 | ||
|
d69559fdcb | ||
|
1fc20d6b56 | ||
|
e375b93a2e | ||
|
a124e15741 | ||
|
5e26af1d08 | ||
|
142ca87ed5 | ||
|
efe4542cea | ||
|
a7c5ccc683 | ||
|
1364e6f1c0 | ||
|
d3948ab0a4 | ||
|
d36b9650f4 | ||
|
7ffd0f3ed9 | ||
|
1c0d4b960d | ||
|
0c177d9116 | ||
|
fcf0b0aaf2 | ||
|
0323f6cb18 | ||
|
170738bc80 | ||
|
b19a6fa22a | ||
|
3a523e053c | ||
|
03bb25be06 | ||
|
373f8e2245 | ||
|
819a925027 | ||
|
3d298b4195 | ||
|
025790512c | ||
|
d2129b2a19 | ||
|
7ac11c261e | ||
|
64b12f86e9 | ||
|
ca00dc04c9 | ||
|
f8573663f0 | ||
|
aba13fd265 | ||
|
965a1c21b8 | ||
|
a59748574f | ||
|
54bf4b687c | ||
|
187ebdf999 | ||
|
32f77a248c | ||
|
fbab0f2163 | ||
|
35c9a93d6e | ||
|
4ad75994d7 | ||
|
7c699033a7 | ||
|
abfddecbe7 | ||
|
2a9f4aa4d8 | ||
|
fc2f00b8b4 | ||
|
e249dac59f | ||
|
3a895d1b6f | ||
|
2e8a63c201 | ||
|
7b4efe3c0e | ||
|
e6495349b8 | ||
|
584bb0ed36 | ||
|
e8483f8c46 | ||
|
0669808f19 | ||
|
ec63e68161 | ||
|
9bafe058c4 | ||
|
18c72e2ff2 | ||
|
673685bb62 | ||
|
bb550a953c | ||
|
8191cf4dcd | ||
|
a001bb484f | ||
|
6286519d20 | ||
|
d053ef7831 | ||
|
c9bd12e0ce | ||
|
8c3e4b557f | ||
|
3c87c38f1e | ||
|
7c19679cdd | ||
|
2fb20b4fc9 |
66 changed files with 7635 additions and 2968 deletions
25
.deepsource.toml
Normal file
25
.deepsource.toml
Normal file
|
@ -0,0 +1,25 @@
|
|||
version = 1
|
||||
|
||||
test_patterns = ["tests/**"]
|
||||
|
||||
[[analyzers]]
|
||||
name = "python"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
runtime_version = "3.x.x"
|
||||
|
||||
|
||||
[[analyzers]]
|
||||
name = "docker"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
dockerfile_paths = [
|
||||
"dockerfile_dev",
|
||||
"dockerfile_prod"
|
||||
]
|
||||
|
||||
[[analyzers]]
|
||||
name = "ruby"
|
||||
enabled = true
|
38
.github/ISSUE_TEMPLATE.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
<!--
|
||||
The issue tracker is a tool to address bugs.
|
||||
For support questions, please use: https://github.com/kivy/buildozer#support
|
||||
|
||||
Before opening a new issue, make sure you do the following:
|
||||
* check that your issue isn't already filed: https://github.com/kivy/buildozer/issues
|
||||
* prepare a short, runnable example that reproduces the issue
|
||||
* make sure to have `log_level = 2` in your `buildozer.spec`
|
||||
* reproduce the problem with the latest development version of Kivy
|
||||
* double-check that the issue is indeed a bug and not a support request
|
||||
-->
|
||||
|
||||
### Versions
|
||||
|
||||
* Python:
|
||||
* OS:
|
||||
* Buildozer:
|
||||
|
||||
### Description
|
||||
|
||||
// REPLACE ME: What are you trying to get done, what has happened, what went wrong, and what did you expect?
|
||||
|
||||
### buildozer.spec
|
||||
Command:
|
||||
```sh
|
||||
// REPLACE ME: buildozer command ran? e.g. buildozer android debug
|
||||
```
|
||||
|
||||
Spec file:
|
||||
```
|
||||
// REPLACE ME: Paste your buildozer.spec file here
|
||||
```
|
||||
|
||||
### Logs
|
||||
|
||||
```
|
||||
// REPLACE ME: Paste the build ouput containing the error
|
||||
```
|
19
.github/support.yml
vendored
Normal file
19
.github/support.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Configuration for support-requests - https://github.com/dessant/support-requests
|
||||
|
||||
# Label used to mark issues as support requests
|
||||
supportLabel: support
|
||||
# Comment to post on issues marked as support requests. Add a link
|
||||
# to a support page, or set to `false` to disable
|
||||
supportComment: >
|
||||
:wave: @{issue-author}, we use the issue tracker exclusively for bug reports
|
||||
and feature requests. However, this issue appears to be a support request.
|
||||
Please use our [support channels](https://github.com/kivy/buildozer#support)
|
||||
to get help with the project.
|
||||
|
||||
|
||||
Let us know if this comment was made in error, and we'll be happy
|
||||
to reopen the issue.
|
||||
# Whether to close issues marked as support requests
|
||||
close: true
|
||||
# Whether to lock issues marked as support requests
|
||||
lock: false
|
40
.github/workflows/android.yml
vendored
Normal file
40
.github/workflows/android.yml
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
on: [push, pull_request]
|
||||
name: Android
|
||||
jobs:
|
||||
Integration:
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- 'ubuntu-latest'
|
||||
- 'macOs-latest'
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup environment
|
||||
run: |
|
||||
pip install -e .
|
||||
pip install Cython
|
||||
- run: buildozer --help
|
||||
- run: buildozer init
|
||||
- name: SDK, NDK and p4a download
|
||||
run: |
|
||||
sed -i.bak "s/# android.accept_sdk_license = False/android.accept_sdk_license = True/" buildozer.spec
|
||||
sed -i.bak "s/#p4a.branch = master/p4a.branch = develop/" buildozer.spec
|
||||
buildozer android p4a -- --help
|
||||
# Install OS specific dependencies
|
||||
- name: Install Linux dependencies
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt -y install automake
|
||||
- name: Install macOS dependencies
|
||||
if: matrix.os == 'macOS-latest'
|
||||
run: |
|
||||
brew install automake
|
||||
sudo ln -sfn /usr/local/opt/openssl /usr/local/ssl
|
||||
- name: buildozer android debug
|
||||
run: |
|
||||
touch main.py
|
||||
buildozer android debug
|
24
.github/workflows/ios.yml
vendored
Normal file
24
.github/workflows/ios.yml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
on: [push, pull_request]
|
||||
name: iOS
|
||||
jobs:
|
||||
Integration:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup environment
|
||||
run: |
|
||||
pip install -e .
|
||||
pip install Cython cookiecutter pbxproj
|
||||
- run: buildozer --help
|
||||
- run: buildozer init
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install autoconf automake libtool pkg-config
|
||||
- name: buildozer ios debug
|
||||
run: |
|
||||
touch main.py
|
||||
buildozer ios debug
|
25
.github/workflows/pypi-release.yml
vendored
Normal file
25
.github/workflows/pypi-release.yml
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
name: PyPI release
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
pypi_release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade setuptools wheel twine
|
||||
- name: Build
|
||||
run: |
|
||||
python setup.py sdist bdist_wheel
|
||||
twine check dist/*
|
||||
- name: Publish package
|
||||
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
|
||||
uses: pypa/gh-action-pypi-publish@v1.1.0
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.pypi_password }}
|
60
.github/workflows/test_python.yml
vendored
Normal file
60
.github/workflows/test_python.yml
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
on: [push, pull_request]
|
||||
name: Tests
|
||||
jobs:
|
||||
Tests:
|
||||
name: base
|
||||
strategy:
|
||||
matrix:
|
||||
python:
|
||||
- '3.6'
|
||||
- '3.7'
|
||||
- '3.8'
|
||||
os:
|
||||
- 'ubuntu-latest'
|
||||
- 'macOs-latest'
|
||||
architecture:
|
||||
- 'x64'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: Requirements
|
||||
run: |
|
||||
pip install -U coveralls setuptools tox>=2.0
|
||||
- name: Tox
|
||||
run: tox
|
||||
- name: Coveralls
|
||||
env:
|
||||
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
COVERALLS_SERVICE_NAME: github
|
||||
run: coveralls
|
||||
|
||||
Docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Docker build
|
||||
run: docker build --tag=kivy/buildozer .
|
||||
- name: Docker run
|
||||
run: docker run kivy/buildozer --version
|
||||
|
||||
Python2:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 2.7
|
||||
- uses: actions/checkout@v2
|
||||
- name: Try Python 2 install
|
||||
run: |
|
||||
# we don't want the build to fail with the exit 1 so we catch with "||"
|
||||
python2 -m pip install -e . 2> error.log || echo Failing as expected
|
||||
cat error.log
|
||||
grep "Unsupported Python version" error.log
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -14,6 +14,7 @@ var
|
|||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
.idea
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
@ -28,3 +29,5 @@ pip-log.txt
|
|||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
MANIFEST
|
||||
|
||||
release\.log\.utf-8\.tmp
|
||||
|
|
1127
CHANGELOG.md
Normal file
1127
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load diff
7
COPYING
7
COPYING
|
@ -1,7 +0,0 @@
|
|||
Copyright (c) 2012 Mathieu Virbel <mat@kivy.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
81
Dockerfile
Normal file
81
Dockerfile
Normal file
|
@ -0,0 +1,81 @@
|
|||
# Dockerfile for providing buildozer
|
||||
#
|
||||
# Build with:
|
||||
# docker build --tag=kivy/buildozer .
|
||||
#
|
||||
# In order to give the container access to your current working directory
|
||||
# it must be mounted using the --volume option.
|
||||
# Run with (e.g. `buildozer --version`):
|
||||
# docker run \
|
||||
# --volume "$HOME/.buildozer":/home/user/.buildozer \
|
||||
# --volume "$PWD":/home/user/hostcwd \
|
||||
# kivy/buildozer --version
|
||||
#
|
||||
# Or for interactive shell:
|
||||
# docker run --interactive --tty --rm \
|
||||
# --volume "$HOME/.buildozer":/home/user/.buildozer \
|
||||
# --volume "$PWD":/home/user/hostcwd \
|
||||
# --entrypoint /bin/bash \
|
||||
# kivy/buildozer
|
||||
#
|
||||
# If you get a `PermissionError` on `/home/user/.buildozer/cache`,
|
||||
# try updating the permissions from the host with:
|
||||
# sudo chown $USER -R ~/.buildozer
|
||||
# Or simply recreate the directory from the host with:
|
||||
# rm -rf ~/.buildozer && mkdir ~/.buildozer
|
||||
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV USER="user"
|
||||
ENV HOME_DIR="/home/${USER}"
|
||||
ENV WORK_DIR="${HOME_DIR}/hostcwd" \
|
||||
SRC_DIR="${HOME_DIR}/src" \
|
||||
PATH="${HOME_DIR}/.local/bin:${PATH}"
|
||||
|
||||
# configures locale
|
||||
RUN apt update -qq > /dev/null \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt install -qq --yes --no-install-recommends \
|
||||
locales && \
|
||||
locale-gen en_US.UTF-8
|
||||
ENV LANG="en_US.UTF-8" \
|
||||
LANGUAGE="en_US.UTF-8" \
|
||||
LC_ALL="en_US.UTF-8"
|
||||
|
||||
# system requirements to build most of the recipes
|
||||
RUN apt update -qq > /dev/null \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt install -qq --yes --no-install-recommends \
|
||||
autoconf \
|
||||
automake \
|
||||
build-essential \
|
||||
ccache \
|
||||
cmake \
|
||||
gettext \
|
||||
git \
|
||||
libffi-dev \
|
||||
libltdl-dev \
|
||||
libssl-dev \
|
||||
libtool \
|
||||
openjdk-13-jdk \
|
||||
patch \
|
||||
pkg-config \
|
||||
python3-pip \
|
||||
python3-setuptools \
|
||||
sudo \
|
||||
unzip \
|
||||
zip \
|
||||
zlib1g-dev
|
||||
|
||||
# prepares non root env
|
||||
RUN useradd --create-home --shell /bin/bash ${USER}
|
||||
# with sudo access and no password
|
||||
RUN usermod -append --groups sudo ${USER}
|
||||
RUN echo "%sudo ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||
|
||||
USER ${USER}
|
||||
WORKDIR ${WORK_DIR}
|
||||
COPY --chown=user:user . ${SRC_DIR}
|
||||
|
||||
# installs buildozer and dependencies
|
||||
RUN pip3 install --user --upgrade Cython==0.29.19 wheel pip virtualenv ${SRC_DIR}
|
||||
|
||||
ENTRYPOINT ["buildozer"]
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2010-2013 Kivy Team and other contributors
|
||||
Copyright (c) 2010-2017 Kivy Team and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
include *COPYING
|
||||
include *CHANGELOG.md
|
||||
include *README.md
|
||||
recursive-include buildozer *.spec
|
||||
|
|
220
README.md
Normal file
220
README.md
Normal file
|
@ -0,0 +1,220 @@
|
|||
Buildozer
|
||||
=========
|
||||
|
||||
[![Tests](https://github.com/kivy/buildozer/workflows/Tests/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3ATests)
|
||||
[![Android](https://github.com/kivy/buildozer/workflows/Android/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3AAndroid)
|
||||
[![iOS](https://github.com/kivy/buildozer/workflows/iOS/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3AiOS)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/kivy/buildozer/badge.svg)](https://coveralls.io/github/kivy/buildozer)
|
||||
[![Backers on Open Collective](https://opencollective.com/kivy/backers/badge.svg)](#backers)
|
||||
[![Sponsors on Open Collective](https://opencollective.com/kivy/sponsors/badge.svg)](#sponsors)
|
||||
|
||||
Buildozer is a tool for creating application packages easily.
|
||||
|
||||
The goal is to have one "buildozer.spec" file in your app directory, describing
|
||||
your application requirements and settings such as title, icon, included modules
|
||||
etc. Buildozer will use that spec to create a package for Android, iOS, Windows,
|
||||
OSX and/or Linux.
|
||||
|
||||
Buildozer currently supports packaging for Android via the [python-for-android](https://github.com/kivy/python-for-android/)
|
||||
project, and for iOS via the kivy-ios project. iOS and OSX are still under work.
|
||||
|
||||
For Android, buildozer will automatically download and prepare the
|
||||
build dependencies. For more information, see
|
||||
[Android-SDK-NDK-Information](https://github.com/kivy/kivy/wiki/Android-SDK-NDK-Information).
|
||||
Note that only Python 3 is supported.
|
||||
|
||||
Note that this tool has nothing to do with the eponymous online build service
|
||||
[buildozer.io](https://buildozer.io).
|
||||
|
||||
## Installing Buildozer with target Python 3 (default):
|
||||
|
||||
- Install buildozer:
|
||||
|
||||
# via pip (latest stable, recommended)
|
||||
# if you use a virtualenv, don't use the `--user` option
|
||||
pip install --user buildozer
|
||||
|
||||
# latest dev version
|
||||
# if you use a virtualenv, don't use the `--user` option
|
||||
pip install --user https://github.com/kivy/buildozer/archive/master.zip
|
||||
|
||||
# git clone, for working on buildozer
|
||||
git clone https://github.com/kivy/buildozer
|
||||
cd buildozer
|
||||
python setup.py build
|
||||
pip install -e .
|
||||
|
||||
- Check buildozer is in your path
|
||||
|
||||
`which buildozer`
|
||||
# if there is no result, and you installed with --user, add this line at the end of your `~/.bashrc` file.
|
||||
export PATH=~/.local/bin/:$PATH
|
||||
# and then run
|
||||
. ~/.bashrc
|
||||
|
||||
- Go into your application directory and run:
|
||||
|
||||
buildozer init
|
||||
# edit the buildozer.spec, then
|
||||
buildozer android debug deploy run
|
||||
|
||||
|
||||
## Buildozer Docker image
|
||||
|
||||
A Dockerfile is available to use buildozer through a Docker environment.
|
||||
|
||||
- Build with:
|
||||
|
||||
docker build --tag=buildozer .
|
||||
|
||||
- Run with:
|
||||
|
||||
docker run --volume "$(pwd)":/home/user/hostcwd buildozer --version
|
||||
|
||||
|
||||
## Buildozer GitHub action
|
||||
|
||||
Use [ArtemSBulgakov/buildozer-action@v1](https://github.com/ArtemSBulgakov/buildozer-action)
|
||||
to build your packages automatically on push or pull request.
|
||||
See [full workflow example](https://github.com/ArtemSBulgakov/buildozer-action#full-workflow).
|
||||
|
||||
|
||||
## Examples of Buildozer commands
|
||||
|
||||
```
|
||||
# buildozer target command
|
||||
buildozer android clean
|
||||
buildozer android update
|
||||
buildozer android deploy
|
||||
buildozer android debug
|
||||
buildozer android release
|
||||
|
||||
# or all in one (compile in debug, deploy on device)
|
||||
buildozer android debug deploy
|
||||
|
||||
# set the default command if nothing set
|
||||
buildozer setdefault android debug deploy run
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
Usage:
|
||||
buildozer [--profile <name>] [--verbose] [target] <command>...
|
||||
buildozer --version
|
||||
|
||||
Available targets:
|
||||
android Android target, based on python-for-android project
|
||||
ios iOS target, based on kivy-ios project
|
||||
|
||||
Global commands (without target):
|
||||
distclean Clean the whole Buildozer environment
|
||||
help Show the Buildozer help
|
||||
init Create an initial buildozer.spec in the current directory
|
||||
serve Serve the bin directory via SimpleHTTPServer
|
||||
setdefault Set the default command to run when no arguments are given
|
||||
version Show the Buildozer version
|
||||
|
||||
Target commands:
|
||||
clean Clean the target environment
|
||||
update Update the target dependencies
|
||||
debug Build the application in debug mode
|
||||
release Build the application in release mode
|
||||
deploy Deploy the application on the device
|
||||
run Run the application on the device
|
||||
serve Serve the bin directory via SimpleHTTPServer
|
||||
|
||||
Target "ios" commands:
|
||||
list_identities List the available identities to use for signing.
|
||||
xcode Open the xcode project.
|
||||
|
||||
Target "android" commands:
|
||||
adb Run adb from the Android SDK. Args must come after --, or
|
||||
use --alias to make an alias
|
||||
logcat Show the log from the device
|
||||
p4a Run p4a commands. Args must come after --, or use --alias
|
||||
to make an alias
|
||||
```
|
||||
|
||||
|
||||
## `buildozer.spec`
|
||||
|
||||
See [buildozer/default.spec](https://raw.github.com/kivy/buildozer/master/buildozer/default.spec) for an up-to-date spec file.
|
||||
|
||||
|
||||
## Default config
|
||||
|
||||
You can override the value of *any* `buildozer.spec` config token by
|
||||
setting an appropriate environment variable. These are all of the
|
||||
form ``$SECTION_TOKEN``, where SECTION is the config file section and
|
||||
TOKEN is the config token to override. Dots are replaced by
|
||||
underscores.
|
||||
|
||||
For example, here are some config tokens from the [app] section of the
|
||||
config, along with the environment variables that would override them.
|
||||
|
||||
- ``title`` -> ``$APP_TITLE``
|
||||
- ``package.name`` -> ``$APP_PACKAGE_NAME``
|
||||
- ``p4a.source_dir`` -> ``$APP_P4A_SOURCE_DIR``
|
||||
|
||||
## Support
|
||||
|
||||
If you need assistance, you can ask for help on our mailing list:
|
||||
|
||||
* User Group : https://groups.google.com/group/kivy-users
|
||||
* Email : kivy-users@googlegroups.com
|
||||
|
||||
Discord channel:
|
||||
|
||||
Server : https://chat.kivy.org
|
||||
Channel : #support
|
||||
|
||||
For [debugging on Android](https://python-for-android.readthedocs.io/en/stable/troubleshooting/?highlight=adb#debugging-on-android), don't hesitate to use ADB to get logs of your application.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
We love pull requests and discussing novel ideas. Check out our
|
||||
[contribution guide](https://kivy.org/docs/contribute.html) and
|
||||
feel free to improve buildozer.
|
||||
|
||||
The following mailing list and IRC channel are used exclusively for
|
||||
discussions about developing the Kivy framework and its sister projects:
|
||||
|
||||
* Dev Group : https://groups.google.com/group/kivy-dev
|
||||
* Email : kivy-dev@googlegroups.com
|
||||
|
||||
We also have a Discord channel:
|
||||
|
||||
* Server : https://chat.kivy.org
|
||||
* Channel : #support
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Buildozer is released under the terms of the MIT License. Please refer to the
|
||||
LICENSE file.
|
||||
|
||||
|
||||
## Backers
|
||||
|
||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/kivy#backer)]
|
||||
|
||||
<a href="https://opencollective.com/kivy#backers" target="_blank"><img src="https://opencollective.com/kivy/backers.svg?width=890"></a>
|
||||
|
||||
|
||||
## Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/kivy#sponsor)]
|
||||
|
||||
<a href="https://opencollective.com/kivy/sponsor/0/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/kivy/sponsor/1/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/kivy/sponsor/2/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/kivy/sponsor/3/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/kivy/sponsor/4/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/kivy/sponsor/5/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/kivy/sponsor/6/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/kivy/sponsor/7/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/kivy/sponsor/8/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/kivy/sponsor/9/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/9/avatar.svg"></a>
|
106
README.rst
106
README.rst
|
@ -1,106 +0,0 @@
|
|||
Buildozer
|
||||
=========
|
||||
|
||||
This tool is currently in alpha.
|
||||
|
||||
Buildozer is a tool for creating application packages easily.
|
||||
|
||||
The goal is to have one "buildozer.spec" file in your app directory, describing
|
||||
your application requirements and settings such as title, icon, included modules
|
||||
etc. Buildozer will use that spec to create a package for Android, iOS, Windows,
|
||||
OSX and/or Linux.
|
||||
|
||||
Buildozer currently supports packaging for Android via the python-for-android
|
||||
project, and for iOS via the kivy-ios project. Support for other operating systems
|
||||
is intended in the future.
|
||||
|
||||
Usage example
|
||||
-------------
|
||||
|
||||
#. Install buildozer::
|
||||
|
||||
# latest dev
|
||||
git clone git://github.com/kivy/buildozer
|
||||
cd buildozer
|
||||
sudo python2.7 setup.py install
|
||||
|
||||
# via pip (latest stable)
|
||||
sudo pip install buildozer
|
||||
|
||||
# via easy_install
|
||||
sudo easy_install buildozer
|
||||
|
||||
#. Go into your application directory and do::
|
||||
|
||||
buildozer init
|
||||
# edit the buildozer.spec, then
|
||||
buildozer android debug deploy run
|
||||
|
||||
Example of commands::
|
||||
|
||||
# buildozer commands
|
||||
buildozer clean
|
||||
|
||||
# buildozer target command
|
||||
buildozer android update
|
||||
buildozer android deploy
|
||||
buildozer android debug
|
||||
buildozer android release
|
||||
|
||||
# or all in one (compile in debug, deploy on device)
|
||||
buildozer android debug deploy
|
||||
|
||||
# set the default command if nothing set
|
||||
buildozer setdefault android debug deploy run
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
::
|
||||
|
||||
Usage: buildozer [--verbose] [target] [command1] [command2]
|
||||
|
||||
Available targets:
|
||||
android Android target, based on python-for-android project
|
||||
ios iOS target, based on kivy-ios project. (not working yet.)
|
||||
|
||||
Global commands (without target):
|
||||
clean Clean the whole Buildozer environment.
|
||||
help Show the Buildozer help.
|
||||
init Create a initial buildozer.spec in the current directory
|
||||
setdefault Set the default command to do when no arguments are given
|
||||
version Show the Buildozer version
|
||||
|
||||
Target commands:
|
||||
clean Clean the target environment
|
||||
update Update the target dependencies
|
||||
debug Build the application in debug mode
|
||||
release Build the application in release mode
|
||||
deploy Deploy the application on the device
|
||||
run Run the application on the device
|
||||
|
||||
|
||||
|
||||
buildozer.spec
|
||||
--------------
|
||||
|
||||
See `buildozer/default.spec <https://raw.github.com/kivy/buildozer/master/buildozer/default.spec>`_ for an up-to-date spec file.
|
||||
|
||||
|
||||
Default config
|
||||
--------------
|
||||
|
||||
You can override the value of *any* buildozer.spec config token by
|
||||
setting an appropriate environment variable. These are all of the
|
||||
form ``$SECTION_TOKEN``, where SECTION is the config file section and
|
||||
TOKEN is the config token to override. Dots are replaced by
|
||||
underscores.
|
||||
|
||||
For example, here are some config tokens from the [app] section of the
|
||||
config, along with the environment variables that would override them.
|
||||
|
||||
- ``title`` -> ``$APP_TITLE``
|
||||
- ``package.name`` -> ``$APP_PACKAGE_NAME``
|
||||
- ``android.p4a_dir`` -> ``$APP_ANDROID_P4A_DIR``
|
||||
|
File diff suppressed because it is too large
Load diff
4
buildozer/__main__.py
Normal file
4
buildozer/__main__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from buildozer.scripts.client import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -15,27 +15,32 @@ source.dir = .
|
|||
# (list) Source files to include (let empty to include all the files)
|
||||
source.include_exts = py,png,jpg,kv,atlas
|
||||
|
||||
# (list) List of inclusions using pattern matching
|
||||
#source.include_patterns = assets/*,images/*.png
|
||||
|
||||
# (list) Source files to exclude (let empty to not exclude anything)
|
||||
#source.exclude_exts = spec
|
||||
|
||||
# (list) List of directory to exclude (let empty to not exclude anything)
|
||||
#source.exclude_dirs = tests, bin
|
||||
#source.exclude_dirs = tests, bin, venv
|
||||
|
||||
# (list) List of exclusions using pattern matching
|
||||
#source.exclude_patterns = license,images/*/*.jpg
|
||||
|
||||
# (str) Application versioning (method 1)
|
||||
version.regex = __version__ = '(.*)'
|
||||
version.filename = %(source.dir)s/main.py
|
||||
version = 0.1
|
||||
|
||||
# (str) Application versioning (method 2)
|
||||
# version = 1.2.0
|
||||
# version.regex = __version__ = ['"](.*)['"]
|
||||
# version.filename = %(source.dir)s/main.py
|
||||
|
||||
# (list) Application requirements
|
||||
requirements = kivy
|
||||
# comma separated e.g. requirements = sqlite3,kivy
|
||||
requirements = python3,kivy
|
||||
|
||||
# (list) Garden requirements
|
||||
#garden_requirements =
|
||||
# (str) Custom source folders for requirements
|
||||
# Sets custom source for any requirements with recipes
|
||||
# requirements.source.kivy = ../../kivy
|
||||
|
||||
# (str) Presplash of the application
|
||||
#presplash.filename = %(source.dir)s/data/presplash.png
|
||||
|
@ -43,31 +48,69 @@ requirements = kivy
|
|||
# (str) Icon of the application
|
||||
#icon.filename = %(source.dir)s/data/icon.png
|
||||
|
||||
# (str) Supported orientation (one of landscape, portrait or all)
|
||||
orientation = landscape
|
||||
# (str) Supported orientation (one of landscape, sensorLandscape, portrait or all)
|
||||
orientation = portrait
|
||||
|
||||
# (bool) Indicate if the application should be fullscreen or not
|
||||
fullscreen = 1
|
||||
# (list) List of service to declare
|
||||
#services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY
|
||||
|
||||
#
|
||||
# OSX Specific
|
||||
#
|
||||
|
||||
#
|
||||
# author = © Copyright Info
|
||||
|
||||
# change the major version of python used by the app
|
||||
osx.python_version = 3
|
||||
|
||||
# Kivy version to use
|
||||
osx.kivy_version = 1.9.1
|
||||
|
||||
#
|
||||
# Android specific
|
||||
#
|
||||
|
||||
# (bool) Indicate if the application should be fullscreen or not
|
||||
fullscreen = 0
|
||||
|
||||
# (string) Presplash background color (for android toolchain)
|
||||
# Supported formats are: #RRGGBB #AARRGGBB or one of the following names:
|
||||
# red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray,
|
||||
# darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy,
|
||||
# olive, purple, silver, teal.
|
||||
#android.presplash_color = #FFFFFF
|
||||
|
||||
# (string) Presplash animation using Lottie format.
|
||||
# see https://lottiefiles.com/ for examples and https://airbnb.design/lottie/
|
||||
# for general documentation.
|
||||
# Lottie files can be created using various tools, like Adobe After Effect or Synfig.
|
||||
#android.presplash_lottie = "path/to/lottie/file.json"
|
||||
|
||||
# (str) Adaptive icon of the application (used if Android API level is 26+ at runtime)
|
||||
#icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png
|
||||
#icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png
|
||||
|
||||
# (list) Permissions
|
||||
#android.permissions = INTERNET
|
||||
|
||||
# (int) Android API to use
|
||||
#android.api = 14
|
||||
# (list) features (adds uses-feature -tags to manifest)
|
||||
#android.features = android.hardware.usb.host
|
||||
|
||||
# (int) Minimum API required (8 = Android 2.2 devices)
|
||||
#android.minapi = 8
|
||||
# (int) Target Android API, should be as high as possible.
|
||||
#android.api = 27
|
||||
|
||||
# (int) Minimum API your APK will support.
|
||||
#android.minapi = 21
|
||||
|
||||
# (int) Android SDK version to use
|
||||
#android.sdk = 21
|
||||
#android.sdk = 20
|
||||
|
||||
# (str) Android NDK version to use
|
||||
#android.ndk = 9c
|
||||
#android.ndk = 19b
|
||||
|
||||
# (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi.
|
||||
#android.ndk_api = 21
|
||||
|
||||
# (bool) Use --private data storage (True) or --dir public storage (False)
|
||||
#android.private_storage = True
|
||||
|
@ -78,11 +121,50 @@ fullscreen = 1
|
|||
# (str) Android SDK directory (if empty, it will be automatically downloaded.)
|
||||
#android.sdk_path =
|
||||
|
||||
# (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
|
||||
#android.p4a_dir =
|
||||
# (str) ANT directory (if empty, it will be automatically downloaded.)
|
||||
#android.ant_path =
|
||||
|
||||
# (bool) If True, then skip trying to update the Android sdk
|
||||
# This can be useful to avoid excess Internet downloads or save time
|
||||
# when an update is due and you just want to test/build your package
|
||||
# android.skip_update = False
|
||||
|
||||
# (bool) If True, then automatically accept SDK license
|
||||
# agreements. This is intended for automation only. If set to False,
|
||||
# the default, you will be shown the license when first running
|
||||
# buildozer.
|
||||
# android.accept_sdk_license = False
|
||||
|
||||
# (str) Android entry point, default is ok for Kivy-based app
|
||||
#android.entrypoint = org.renpy.android.PythonActivity
|
||||
#android.entrypoint = org.kivy.android.PythonActivity
|
||||
|
||||
# (str) Full name including package path of the Java class that implements Android Activity
|
||||
# use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity
|
||||
#android.activity_class_name = org.kivy.android.PythonActivity
|
||||
|
||||
# (str) Extra xml to write directly inside the <manifest> element of AndroidManifest.xml
|
||||
# use that parameter to provide a filename from where to load your custom XML code
|
||||
#android.extra_manifest_xml = ./src/android/extra_manifest.xml
|
||||
|
||||
# (str) Extra xml to write directly inside the <manifest><application> tag of AndroidManifest.xml
|
||||
# use that parameter to provide a filename from where to load your custom XML arguments:
|
||||
#android.extra_manifest_application_arguments = ./src/android/extra_manifest_application_arguments.xml
|
||||
|
||||
# (str) Full name including package path of the Java class that implements Python Service
|
||||
# use that parameter to set custom Java class instead of PythonService
|
||||
#android.service_class_name = org.kivy.android.PythonService
|
||||
|
||||
# (str) Android app theme, default is ok for Kivy-based app
|
||||
# android.apptheme = "@android:style/Theme.NoTitleBar"
|
||||
|
||||
# (list) Pattern to whitelist for the whole project
|
||||
#android.whitelist =
|
||||
|
||||
# (str) Path to a custom whitelist file
|
||||
#android.whitelist_src =
|
||||
|
||||
# (str) Path to a custom blacklist file
|
||||
#android.blacklist_src =
|
||||
|
||||
# (list) List of Java .jar files to add to the libs so that pyjnius can access
|
||||
# their classes. Don't add jars that you do not need, since extra jars can slow
|
||||
|
@ -94,9 +176,36 @@ fullscreen = 1
|
|||
# directory containing the files)
|
||||
#android.add_src =
|
||||
|
||||
# (str) python-for-android branch to use, if not master, useful to try
|
||||
# not yet merged features.
|
||||
#android.branch = master
|
||||
# (list) Android AAR archives to add
|
||||
#android.add_aars =
|
||||
|
||||
# (list) Gradle dependencies to add
|
||||
#android.gradle_dependencies =
|
||||
|
||||
# (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies'
|
||||
# contains an 'androidx' package, or any package from Kotlin source.
|
||||
# android.enable_androidx requires android.api >= 28
|
||||
#android.enable_androidx = False
|
||||
|
||||
# (list) add java compile options
|
||||
# this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option
|
||||
# see https://developer.android.com/studio/write/java8-support for further information
|
||||
# android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8"
|
||||
|
||||
# (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies}
|
||||
# please enclose in double quotes
|
||||
# e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }"
|
||||
#android.add_gradle_repositories =
|
||||
|
||||
# (list) packaging options to add
|
||||
# see https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html
|
||||
# can be necessary to solve conflicts in gradle_dependencies
|
||||
# please enclose in double quotes
|
||||
# e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'"
|
||||
#android.add_packaging_options =
|
||||
|
||||
# (list) Java classes to add as activities to the manifest.
|
||||
#android.add_activities = com.example.ExampleActivity
|
||||
|
||||
# (str) OUYA Console category. Should be one of GAME or APP
|
||||
# If you leave this blank, OUYA support will not be enabled
|
||||
|
@ -108,8 +217,15 @@ fullscreen = 1
|
|||
# (str) XML file to include as an intent filters in <activity> tag
|
||||
#android.manifest.intent_filters =
|
||||
|
||||
# (list) Android additionnal libraries to copy into libs/armeabi
|
||||
# (str) launchMode to set for the main activity
|
||||
#android.manifest.launch_mode = standard
|
||||
|
||||
# (list) Android additional libraries to copy into libs/armeabi
|
||||
#android.add_libs_armeabi = libs/android/*.so
|
||||
#android.add_libs_armeabi_v7a = libs/android-v7/*.so
|
||||
#android.add_libs_arm64_v8a = libs/android-v8/*.so
|
||||
#android.add_libs_x86 = libs/android-x86/*.so
|
||||
#android.add_libs_mips = libs/android-mips/*.so
|
||||
|
||||
# (bool) Indicate whether the screen should stay on
|
||||
# Don't forget to add the WAKE_LOCK permission if you set this to True
|
||||
|
@ -122,23 +238,141 @@ fullscreen = 1
|
|||
# project.properties automatically.)
|
||||
#android.library_references =
|
||||
|
||||
# (list) Android shared libraries which will be added to AndroidManifest.xml using <uses-library> tag
|
||||
#android.uses_library =
|
||||
|
||||
# (str) Android logcat filters to use
|
||||
#android.logcat_filters = *:S python:D
|
||||
|
||||
# (bool) Android logcat only display log for activity's pid
|
||||
#android.logcat_pid_only = False
|
||||
|
||||
# (str) Android additional adb arguments
|
||||
#android.adb_args = -H host.docker.internal
|
||||
|
||||
# (bool) Copy library instead of making a libpymodules.so
|
||||
#android.copy_libs = 1
|
||||
|
||||
# (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64
|
||||
android.arch = armeabi-v7a
|
||||
|
||||
# (int) overrides automatic versionCode computation (used in build.gradle)
|
||||
# this is not the same as app version and should only be edited if you know what you're doing
|
||||
# android.numeric_version = 1
|
||||
|
||||
# (bool) enables Android auto backup feature (Android API >=23)
|
||||
android.allow_backup = True
|
||||
|
||||
# (str) XML file for custom backup rules (see official auto backup documentation)
|
||||
# android.backup_rules =
|
||||
|
||||
# (str) If you need to insert variables into your AndroidManifest.xml file,
|
||||
# you can do so with the manifestPlaceholders property.
|
||||
# This property takes a map of key-value pairs. (via a string)
|
||||
# Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"]
|
||||
# android.manifest_placeholders = [:]
|
||||
|
||||
# (bool) disables the compilation of py to pyc/pyo files when packaging
|
||||
# android.no-compile-pyo = True
|
||||
|
||||
#
|
||||
# Python for android (p4a) specific
|
||||
#
|
||||
|
||||
# (str) python-for-android URL to use for checkout
|
||||
#p4a.url =
|
||||
|
||||
# (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy)
|
||||
#p4a.fork = kivy
|
||||
|
||||
# (str) python-for-android branch to use, defaults to master
|
||||
#p4a.branch = master
|
||||
|
||||
# (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch
|
||||
#p4a.commit = HEAD
|
||||
|
||||
# (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
|
||||
#p4a.source_dir =
|
||||
|
||||
# (str) The directory in which python-for-android should look for your own build recipes (if any)
|
||||
#p4a.local_recipes =
|
||||
|
||||
# (str) Filename to the hook for p4a
|
||||
#p4a.hook =
|
||||
|
||||
# (str) Bootstrap to use for android builds
|
||||
# p4a.bootstrap = sdl2
|
||||
|
||||
# (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask)
|
||||
#p4a.port =
|
||||
|
||||
# Control passing the --use-setup-py vs --ignore-setup-py to p4a
|
||||
# "in the future" --use-setup-py is going to be the default behaviour in p4a, right now it is not
|
||||
# Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py
|
||||
# NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate
|
||||
# setup.py if you're using Poetry, but you need to add "toml" to source.include_exts.
|
||||
#p4a.setup_py = false
|
||||
|
||||
|
||||
#
|
||||
# iOS specific
|
||||
#
|
||||
|
||||
# (str) Path to a custom kivy-ios folder
|
||||
#ios.kivy_ios_dir = ../kivy-ios
|
||||
# Alternately, specify the URL and branch of a git checkout:
|
||||
ios.kivy_ios_url = https://github.com/kivy/kivy-ios
|
||||
ios.kivy_ios_branch = master
|
||||
|
||||
# Another platform dependency: ios-deploy
|
||||
# Uncomment to use a custom checkout
|
||||
#ios.ios_deploy_dir = ../ios_deploy
|
||||
# Or specify URL and branch
|
||||
ios.ios_deploy_url = https://github.com/phonegap/ios-deploy
|
||||
ios.ios_deploy_branch = 1.10.0
|
||||
|
||||
# (bool) Whether or not to sign the code
|
||||
ios.codesign.allowed = false
|
||||
|
||||
# (str) Name of the certificate to use for signing the debug version
|
||||
# Get a list of available identities: buildozer ios list_identities
|
||||
#ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)"
|
||||
|
||||
# (str) The development team to use for signing the debug version
|
||||
#ios.codesign.development_team.debug = <hexstring>
|
||||
|
||||
# (str) Name of the certificate to use for signing the release version
|
||||
#ios.codesign.release = %(ios.codesign.debug)s
|
||||
|
||||
# (str) The development team to use for signing the release version
|
||||
#ios.codesign.development_team.release = <hexstring>
|
||||
|
||||
# (str) URL pointing to .ipa file to be installed
|
||||
# This option should be defined along with `display_image_url` and `full_size_image_url` options.
|
||||
#ios.manifest.app_url =
|
||||
|
||||
# (str) URL pointing to an icon (57x57px) to be displayed during download
|
||||
# This option should be defined along with `app_url` and `full_size_image_url` options.
|
||||
#ios.manifest.display_image_url =
|
||||
|
||||
# (str) URL pointing to a large icon (512x512px) to be used by iTunes
|
||||
# This option should be defined along with `app_url` and `display_image_url` options.
|
||||
#ios.manifest.full_size_image_url =
|
||||
|
||||
|
||||
[buildozer]
|
||||
|
||||
# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
|
||||
log_level = 1
|
||||
log_level = 2
|
||||
|
||||
# (int) Display warning if buildozer is run as root (0 = False, 1 = True)
|
||||
warn_on_root = 1
|
||||
|
||||
# (str) Path to build artifact storage, absolute or relative to spec file
|
||||
# build_dir = ./.buildozer
|
||||
|
||||
# (str) Path to build output (i.e. .apk, .ipa) storage
|
||||
# bin_dir = ./bin
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# List as sections
|
||||
|
|
47
buildozer/jsonstore.py
Normal file
47
buildozer/jsonstore.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
"""
|
||||
Replacement for shelve, using json.
|
||||
This was needed to correctly support db between Python 2 and 3.
|
||||
"""
|
||||
|
||||
__all__ = ["JsonStore"]
|
||||
|
||||
import io
|
||||
from json import load, dump
|
||||
from os.path import exists
|
||||
|
||||
|
||||
class JsonStore:
|
||||
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.data = {}
|
||||
if exists(filename):
|
||||
try:
|
||||
with io.open(filename, encoding='utf-8') as fd:
|
||||
self.data = load(fd)
|
||||
except ValueError:
|
||||
print("Unable to read the state.db, content will be replaced.")
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.data[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.data[key] = value
|
||||
self.sync()
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self.data[key]
|
||||
self.sync()
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self.data
|
||||
|
||||
def get(self, item, default=None):
|
||||
return self.data.get(item, default)
|
||||
|
||||
def keys(self):
|
||||
return self.data.keys()
|
||||
|
||||
def sync(self):
|
||||
with open(self.filename, 'w') as fd:
|
||||
dump(self.data, fd, ensure_ascii=False)
|
78
buildozer/libs/_structures.py
Normal file
78
buildozer/libs/_structures.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Copyright 2014 Donald Stufft
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
class Infinity:
|
||||
|
||||
def __repr__(self):
|
||||
return "Infinity"
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __lt__(self, other):
|
||||
return False
|
||||
|
||||
def __le__(self, other):
|
||||
return False
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not isinstance(other, self.__class__)
|
||||
|
||||
def __gt__(self, other):
|
||||
return True
|
||||
|
||||
def __ge__(self, other):
|
||||
return True
|
||||
|
||||
def __neg__(self):
|
||||
return NegativeInfinity
|
||||
|
||||
|
||||
Infinity = Infinity()
|
||||
|
||||
|
||||
class NegativeInfinity:
|
||||
|
||||
def __repr__(self):
|
||||
return "-Infinity"
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __lt__(self, other):
|
||||
return True
|
||||
|
||||
def __le__(self, other):
|
||||
return True
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not isinstance(other, self.__class__)
|
||||
|
||||
def __gt__(self, other):
|
||||
return False
|
||||
|
||||
def __ge__(self, other):
|
||||
return False
|
||||
|
||||
def __neg__(self):
|
||||
return Infinity
|
||||
|
||||
|
||||
NegativeInfinity = NegativeInfinity()
|
File diff suppressed because it is too large
Load diff
400
buildozer/libs/version.py
Normal file
400
buildozer/libs/version.py
Normal file
|
@ -0,0 +1,400 @@
|
|||
# Copyright 2014 Donald Stufft
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import collections
|
||||
import itertools
|
||||
import re
|
||||
|
||||
from ._structures import Infinity
|
||||
|
||||
|
||||
__all__ = [
|
||||
"parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"
|
||||
]
|
||||
|
||||
|
||||
_Version = collections.namedtuple(
|
||||
"_Version",
|
||||
["epoch", "release", "dev", "pre", "post", "local"],
|
||||
)
|
||||
|
||||
|
||||
def parse(version):
|
||||
"""
|
||||
Parse the given version string and return either a :class:`Version` object
|
||||
or a :class:`LegacyVersion` object depending on if the given version is
|
||||
a valid PEP 440 version or a legacy version.
|
||||
"""
|
||||
try:
|
||||
return Version(version)
|
||||
except InvalidVersion:
|
||||
return LegacyVersion(version)
|
||||
|
||||
|
||||
class InvalidVersion(ValueError):
|
||||
"""
|
||||
An invalid version was found, users should refer to PEP 440.
|
||||
"""
|
||||
|
||||
|
||||
class _BaseVersion:
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self._key)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._compare(other, lambda s, o: s < o)
|
||||
|
||||
def __le__(self, other):
|
||||
return self._compare(other, lambda s, o: s <= o)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._compare(other, lambda s, o: s == o)
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._compare(other, lambda s, o: s >= o)
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._compare(other, lambda s, o: s > o)
|
||||
|
||||
def __ne__(self, other):
|
||||
return self._compare(other, lambda s, o: s != o)
|
||||
|
||||
def _compare(self, other, method):
|
||||
if not isinstance(other, _BaseVersion):
|
||||
return NotImplemented
|
||||
|
||||
return method(self._key, other._key)
|
||||
|
||||
|
||||
class LegacyVersion(_BaseVersion):
|
||||
|
||||
def __init__(self, version):
|
||||
self._version = str(version)
|
||||
self._key = _legacy_cmpkey(self._version)
|
||||
|
||||
def __str__(self):
|
||||
return self._version
|
||||
|
||||
def __repr__(self):
|
||||
return "<LegacyVersion({0})>".format(repr(str(self)))
|
||||
|
||||
@property
|
||||
def public(self):
|
||||
return self._version
|
||||
|
||||
@property
|
||||
def base_version(self):
|
||||
return self._version
|
||||
|
||||
@property
|
||||
def local(self):
|
||||
return None
|
||||
|
||||
@property
|
||||
def is_prerelease(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_postrelease(self):
|
||||
return False
|
||||
|
||||
|
||||
_legacy_version_component_re = re.compile(
|
||||
r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE,
|
||||
)
|
||||
|
||||
_legacy_version_replacement_map = {
|
||||
"pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@",
|
||||
}
|
||||
|
||||
|
||||
def _parse_version_parts(s):
|
||||
for part in _legacy_version_component_re.split(s):
|
||||
part = _legacy_version_replacement_map.get(part, part)
|
||||
|
||||
if not part or part == ".":
|
||||
continue
|
||||
|
||||
if part[:1] in "0123456789":
|
||||
# pad for numeric comparison
|
||||
yield part.zfill(8)
|
||||
else:
|
||||
yield "*" + part
|
||||
|
||||
# ensure that alpha/beta/candidate are before final
|
||||
yield "*final"
|
||||
|
||||
|
||||
def _legacy_cmpkey(version):
|
||||
# We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
|
||||
# greater than or equal to 0. This will effectively put the LegacyVersion,
|
||||
# which uses the defacto standard originally implemented by setuptools,
|
||||
# as before all PEP 440 versions.
|
||||
epoch = -1
|
||||
|
||||
# This scheme is taken from pkg_resources.parse_version setuptools prior to
|
||||
# it's adoption of the packaging library.
|
||||
parts = []
|
||||
for part in _parse_version_parts(version.lower()):
|
||||
if part.startswith("*"):
|
||||
# remove "-" before a prerelease tag
|
||||
if part < "*final":
|
||||
while parts and parts[-1] == "*final-":
|
||||
parts.pop()
|
||||
|
||||
# remove trailing zeros from each series of numeric parts
|
||||
while parts and parts[-1] == "00000000":
|
||||
parts.pop()
|
||||
|
||||
parts.append(part)
|
||||
parts = tuple(parts)
|
||||
|
||||
return epoch, parts
|
||||
|
||||
|
||||
# Deliberately not anchored to the start and end of the string, to make it
|
||||
# easier for 3rd party code to reuse
|
||||
VERSION_PATTERN = r"""
|
||||
v?
|
||||
(?:
|
||||
(?:(?P<epoch>[0-9]+)!)? # epoch
|
||||
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
|
||||
(?P<pre> # pre-release
|
||||
[-_\.]?
|
||||
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
|
||||
[-_\.]?
|
||||
(?P<pre_n>[0-9]+)?
|
||||
)?
|
||||
(?P<post> # post release
|
||||
(?:-(?P<post_n1>[0-9]+))
|
||||
|
|
||||
(?:
|
||||
[-_\.]?
|
||||
(?P<post_l>post|rev|r)
|
||||
[-_\.]?
|
||||
(?P<post_n2>[0-9]+)?
|
||||
)
|
||||
)?
|
||||
(?P<dev> # dev release
|
||||
[-_\.]?
|
||||
(?P<dev_l>dev)
|
||||
[-_\.]?
|
||||
(?P<dev_n>[0-9]+)?
|
||||
)?
|
||||
)
|
||||
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
|
||||
"""
|
||||
|
||||
|
||||
class Version(_BaseVersion):
|
||||
|
||||
_regex = re.compile(
|
||||
r"^\s*" + VERSION_PATTERN + r"\s*$",
|
||||
re.VERBOSE | re.IGNORECASE,
|
||||
)
|
||||
|
||||
def __init__(self, version):
|
||||
# Validate the version and parse it into pieces
|
||||
match = self._regex.search(version)
|
||||
if not match:
|
||||
raise InvalidVersion("Invalid version: '{0}'".format(version))
|
||||
|
||||
# Store the parsed out pieces of the version
|
||||
self._version = _Version(
|
||||
epoch=int(match.group("epoch")) if match.group("epoch") else 0,
|
||||
release=tuple(int(i) for i in match.group("release").split(".")),
|
||||
pre=_parse_letter_version(
|
||||
match.group("pre_l"),
|
||||
match.group("pre_n"),
|
||||
),
|
||||
post=_parse_letter_version(
|
||||
match.group("post_l"),
|
||||
match.group("post_n1") or match.group("post_n2"),
|
||||
),
|
||||
dev=_parse_letter_version(
|
||||
match.group("dev_l"),
|
||||
match.group("dev_n"),
|
||||
),
|
||||
local=_parse_local_version(match.group("local")),
|
||||
)
|
||||
|
||||
# Generate a key which will be used for sorting
|
||||
self._key = _cmpkey(
|
||||
self._version.epoch,
|
||||
self._version.release,
|
||||
self._version.pre,
|
||||
self._version.post,
|
||||
self._version.dev,
|
||||
self._version.local,
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return "<Version({0})>".format(repr(str(self)))
|
||||
|
||||
def __str__(self):
|
||||
parts = []
|
||||
|
||||
# Epoch
|
||||
if self._version.epoch != 0:
|
||||
parts.append("{0}!".format(self._version.epoch))
|
||||
|
||||
# Release segment
|
||||
parts.append(".".join(str(x) for x in self._version.release))
|
||||
|
||||
# Pre-release
|
||||
if self._version.pre is not None:
|
||||
parts.append("-" + "".join(str(x) for x in self._version.pre))
|
||||
|
||||
# Post-release
|
||||
if self._version.post is not None:
|
||||
parts.append(".post{0}".format(self._version.post[1]))
|
||||
|
||||
# Development release
|
||||
if self._version.dev is not None:
|
||||
parts.append(".dev{0}".format(self._version.dev[1]))
|
||||
|
||||
# Local version segment
|
||||
if self._version.local is not None:
|
||||
parts.append(
|
||||
"+{0}".format(".".join(str(x) for x in self._version.local))
|
||||
)
|
||||
|
||||
return "".join(parts)
|
||||
|
||||
@property
|
||||
def public(self):
|
||||
return str(self).split("+", 1)[0]
|
||||
|
||||
@property
|
||||
def base_version(self):
|
||||
parts = []
|
||||
|
||||
# Epoch
|
||||
if self._version.epoch != 0:
|
||||
parts.append("{0}!".format(self._version.epoch))
|
||||
|
||||
# Release segment
|
||||
parts.append(".".join(str(x) for x in self._version.release))
|
||||
|
||||
return "".join(parts)
|
||||
|
||||
@property
|
||||
def local(self):
|
||||
version_string = str(self)
|
||||
if "+" in version_string:
|
||||
return version_string.split("+", 1)[1]
|
||||
|
||||
@property
|
||||
def is_prerelease(self):
|
||||
return bool(self._version.dev or self._version.pre)
|
||||
|
||||
@property
|
||||
def is_postrelease(self):
|
||||
return bool(self._version.post)
|
||||
|
||||
|
||||
def _parse_letter_version(letter, number):
|
||||
if letter:
|
||||
# We consider there to be an implicit 0 in a pre-release if there is
|
||||
# not a numeral associated with it.
|
||||
if number is None:
|
||||
number = 0
|
||||
|
||||
# We normalize any letters to their lower case form
|
||||
letter = letter.lower()
|
||||
|
||||
# We consider some words to be alternate spellings of other words and
|
||||
# in those cases we want to normalize the spellings to our preferred
|
||||
# spelling.
|
||||
if letter == "alpha":
|
||||
letter = "a"
|
||||
elif letter == "beta":
|
||||
letter = "b"
|
||||
elif letter in ["c", "pre", "preview"]:
|
||||
letter = "rc"
|
||||
|
||||
return letter, int(number)
|
||||
if not letter and number:
|
||||
# We assume if we are given a number, but we are not given a letter
|
||||
# then this is using the implicit post release syntax (e.g. 1.0-1)
|
||||
letter = "post"
|
||||
|
||||
return letter, int(number)
|
||||
|
||||
|
||||
_local_version_separators = re.compile(r"[\._-]")
|
||||
|
||||
|
||||
def _parse_local_version(local):
|
||||
"""
|
||||
Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
|
||||
"""
|
||||
if local is not None:
|
||||
return tuple(
|
||||
part.lower() if not part.isdigit() else int(part)
|
||||
for part in _local_version_separators.split(local)
|
||||
)
|
||||
|
||||
|
||||
def _cmpkey(epoch, release, pre, post, dev, local):
|
||||
# When we compare a release version, we want to compare it with all of the
|
||||
# trailing zeros removed. So we'll use a reverse the list, drop all the now
|
||||
# leading zeros until we come to something non zero, then take the rest
|
||||
# re-reverse it back into the correct order and make it a tuple and use
|
||||
# that for our sorting key.
|
||||
release = tuple(
|
||||
reversed(list(
|
||||
itertools.dropwhile(
|
||||
lambda x: x == 0,
|
||||
reversed(release),
|
||||
)
|
||||
))
|
||||
)
|
||||
|
||||
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
|
||||
# We'll do this by abusing the pre segment, but we _only_ want to do this
|
||||
# if there is not a pre or a post segment. If we have one of those then
|
||||
# the normal sorting rules will handle this case correctly.
|
||||
if pre is None and post is None and dev is not None:
|
||||
pre = -Infinity
|
||||
# Versions without a pre-release (except as noted above) should sort after
|
||||
# those with one.
|
||||
elif pre is None:
|
||||
pre = Infinity
|
||||
|
||||
# Versions without a post segment should sort before those with one.
|
||||
if post is None:
|
||||
post = -Infinity
|
||||
|
||||
# Versions without a development segment should sort after those with one.
|
||||
if dev is None:
|
||||
dev = Infinity
|
||||
|
||||
if local is None:
|
||||
# Versions without a local segment should sort before those with one.
|
||||
local = -Infinity
|
||||
else:
|
||||
# Versions with a local segment need that segment parsed to implement
|
||||
# the sorting rules in PEP440.
|
||||
# - Alpha numeric segments sort before numeric segments
|
||||
# - Alpha numeric segments sort lexicographically
|
||||
# - Numeric segments sort numerically
|
||||
# - Shorter versions sort before longer versions when the prefixes
|
||||
# match exactly
|
||||
local = tuple(
|
||||
(i, "") if isinstance(i, int) else (-Infinity, i)
|
||||
for i in local
|
||||
)
|
||||
|
||||
return epoch, release, pre, post, dev, local
|
0
buildozer/scripts/__init__.py
Normal file
0
buildozer/scripts/__init__.py
Normal file
24
buildozer/scripts/client.py
Normal file
24
buildozer/scripts/client.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
'''
|
||||
Main Buildozer client
|
||||
=====================
|
||||
|
||||
'''
|
||||
|
||||
import sys
|
||||
from buildozer import Buildozer, BuildozerCommandException, BuildozerException
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
Buildozer().run_command(sys.argv[1:])
|
||||
except BuildozerCommandException:
|
||||
# don't show the exception in the command line. The log already show
|
||||
# the command failed.
|
||||
sys.exit(1)
|
||||
except BuildozerException as error:
|
||||
Buildozer().error('%s' % error)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
278
buildozer/scripts/remote.py
Normal file
278
buildozer/scripts/remote.py
Normal file
|
@ -0,0 +1,278 @@
|
|||
'''
|
||||
Buildozer remote
|
||||
================
|
||||
|
||||
.. warning::
|
||||
|
||||
This is an experimental tool and not widely used. It might not fit for you.
|
||||
|
||||
Pack and send the source code to a remote SSH server, bundle buildozer with it,
|
||||
and start the build on the remote.
|
||||
You need paramiko to make it work.
|
||||
'''
|
||||
|
||||
__all__ = ["BuildozerRemote"]
|
||||
|
||||
import socket
|
||||
import sys
|
||||
from buildozer import (
|
||||
Buildozer, BuildozerCommandException, BuildozerException, __version__)
|
||||
from sys import stdout, stdin, exit
|
||||
from select import select
|
||||
from os.path import join, expanduser, realpath, exists, splitext
|
||||
from os import makedirs, walk, getcwd
|
||||
from configparser import ConfigParser
|
||||
try:
|
||||
import termios
|
||||
has_termios = True
|
||||
except ImportError:
|
||||
has_termios = False
|
||||
try:
|
||||
import paramiko
|
||||
except ImportError:
|
||||
print('Paramiko missing: pip install paramiko')
|
||||
|
||||
|
||||
class BuildozerRemote(Buildozer):
|
||||
def run_command(self, args):
|
||||
while args:
|
||||
if not args[0].startswith('-'):
|
||||
break
|
||||
arg = args.pop(0)
|
||||
|
||||
if arg in ('-v', '--verbose'):
|
||||
self.log_level = 2
|
||||
|
||||
elif arg in ('-p', '--profile'):
|
||||
self.config_profile = args.pop(0)
|
||||
|
||||
elif arg in ('-h', '--help'):
|
||||
self.usage()
|
||||
exit(0)
|
||||
|
||||
elif arg == '--version':
|
||||
print('Buildozer (remote) {0}'.format(__version__))
|
||||
exit(0)
|
||||
|
||||
self._merge_config_profile()
|
||||
|
||||
if len(args) < 2:
|
||||
self.usage()
|
||||
return
|
||||
|
||||
remote_name = args[0]
|
||||
remote_section = 'remote:{}'.format(remote_name)
|
||||
if not self.config.has_section(remote_section):
|
||||
self.error('Unknown remote "{}", must be configured first.'.format(
|
||||
remote_name))
|
||||
return
|
||||
|
||||
self.remote_host = remote_host = self.config.get(
|
||||
remote_section, 'host', '')
|
||||
self.remote_port = self.config.get(
|
||||
remote_section, 'port', '22')
|
||||
self.remote_user = remote_user = self.config.get(
|
||||
remote_section, 'user', '')
|
||||
self.remote_build_dir = remote_build_dir = self.config.get(
|
||||
remote_section, 'build_directory', '')
|
||||
self.remote_identity = self.config.get(
|
||||
remote_section, 'identity', '')
|
||||
if not remote_host:
|
||||
self.error('Missing "host = " for {}'.format(remote_section))
|
||||
return
|
||||
if not remote_user:
|
||||
self.error('Missing "user = " for {}'.format(remote_section))
|
||||
return
|
||||
if not remote_build_dir:
|
||||
self.error('Missing "build_directory = " for {}'.format(remote_section))
|
||||
return
|
||||
|
||||
# fake the target
|
||||
self.targetname = 'remote'
|
||||
self.check_build_layout()
|
||||
|
||||
# prepare our source code
|
||||
self.info('Prepare source code to sync')
|
||||
self._copy_application_sources()
|
||||
self._ssh_connect()
|
||||
try:
|
||||
self._ensure_buildozer()
|
||||
self._sync_application_sources()
|
||||
self._do_remote_commands(args[1:])
|
||||
self._ssh_sync(getcwd(), mode='get')
|
||||
finally:
|
||||
self._ssh_close()
|
||||
|
||||
def _ssh_connect(self):
|
||||
self.info('Connecting to {}'.format(self.remote_host))
|
||||
self._ssh_client = client = paramiko.SSHClient()
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
client.load_system_host_keys()
|
||||
kwargs = {}
|
||||
if self.remote_identity:
|
||||
kwargs['key_filename'] = expanduser(self.remote_identity)
|
||||
client.connect(self.remote_host, username=self.remote_user,
|
||||
port=int(self.remote_port), **kwargs)
|
||||
self._sftp_client = client.open_sftp()
|
||||
|
||||
def _ssh_close(self):
|
||||
self.debug('Closing remote connection')
|
||||
self._sftp_client.close()
|
||||
self._ssh_client.close()
|
||||
|
||||
def _ensure_buildozer(self):
|
||||
s = self._sftp_client
|
||||
root_dir = s.normalize('.')
|
||||
self.remote_build_dir = join(root_dir, self.remote_build_dir,
|
||||
self.package_full_name)
|
||||
self.debug('Remote build directory: {}'.format(self.remote_build_dir))
|
||||
self._ssh_mkdir(self.remote_build_dir)
|
||||
self._ssh_sync(__path__[0]) # noqa: F821 undefined name
|
||||
|
||||
def _sync_application_sources(self):
|
||||
self.info('Synchronize application sources')
|
||||
self._ssh_sync(self.app_dir)
|
||||
|
||||
# create custom buildozer.spec
|
||||
self.info('Create custom buildozer.spec')
|
||||
config = ConfigParser()
|
||||
config.read('buildozer.spec')
|
||||
config.set('app', 'source.dir', 'app')
|
||||
|
||||
fn = join(self.remote_build_dir, 'buildozer.spec')
|
||||
fd = self._sftp_client.open(fn, 'wb')
|
||||
config.write(fd)
|
||||
fd.close()
|
||||
|
||||
def _do_remote_commands(self, args):
|
||||
self.info('Execute remote buildozer')
|
||||
cmd = (
|
||||
'source ~/.profile;'
|
||||
'cd {0};'
|
||||
'env PYTHONPATH={0}:$PYTHONPATH '
|
||||
'python -c "import buildozer, sys;'
|
||||
'buildozer.Buildozer().run_command(sys.argv[1:])" {1} {2} 2>&1').format(
|
||||
self.remote_build_dir,
|
||||
'--verbose' if self.log_level == 2 else '',
|
||||
' '.join(args),
|
||||
)
|
||||
self._ssh_command(cmd)
|
||||
|
||||
def _ssh_mkdir(self, *args):
|
||||
directory = join(*args)
|
||||
self.debug('Create remote directory {}'.format(directory))
|
||||
try:
|
||||
self._sftp_client.mkdir(directory)
|
||||
except IOError:
|
||||
# already created?
|
||||
try:
|
||||
self._sftp_client.stat(directory)
|
||||
except IOError:
|
||||
self.error('Unable to create remote directory {}'.format(directory))
|
||||
raise
|
||||
|
||||
def _ssh_sync(self, directory, mode='put'):
|
||||
self.debug('Syncing {} directory'.format(directory))
|
||||
directory = realpath(expanduser(directory))
|
||||
base_strip = directory.rfind('/')
|
||||
if mode == 'get':
|
||||
local_dir = join(directory, 'bin')
|
||||
remote_dir = join(self.remote_build_dir, 'bin')
|
||||
if not exists(local_dir):
|
||||
makedirs(local_dir)
|
||||
for _file in self._sftp_client.listdir(path=remote_dir):
|
||||
self._sftp_client.get(join(remote_dir, _file),
|
||||
join(local_dir, _file))
|
||||
return
|
||||
for root, dirs, files in walk(directory):
|
||||
self._ssh_mkdir(self.remote_build_dir, root[base_strip + 1:])
|
||||
for fn in files:
|
||||
if splitext(fn)[1] in ('.pyo', '.pyc', '.swp'):
|
||||
continue
|
||||
local_file = join(root, fn)
|
||||
remote_file = join(self.remote_build_dir, root[base_strip + 1:], fn)
|
||||
self.debug('Sync {} -> {}'.format(local_file, remote_file))
|
||||
self._sftp_client.put(local_file, remote_file)
|
||||
|
||||
def _ssh_command(self, command):
|
||||
self.debug('Execute remote command {}'.format(command))
|
||||
transport = self._ssh_client.get_transport()
|
||||
channel = transport.open_session()
|
||||
try:
|
||||
channel.exec_command(command)
|
||||
self._interactive_shell(channel)
|
||||
finally:
|
||||
channel.close()
|
||||
|
||||
def _interactive_shell(self, chan):
|
||||
if has_termios:
|
||||
self._posix_shell(chan)
|
||||
else:
|
||||
self._windows_shell(chan)
|
||||
|
||||
def _posix_shell(self, chan):
|
||||
oldtty = termios.tcgetattr(stdin)
|
||||
try:
|
||||
chan.settimeout(0.0)
|
||||
|
||||
while True:
|
||||
r, w, e = select([chan, stdin], [], [])
|
||||
if chan in r:
|
||||
try:
|
||||
x = chan.recv(128)
|
||||
if len(x) == 0:
|
||||
print('\r\n*** EOF\r\n',)
|
||||
break
|
||||
stdout.write(x)
|
||||
stdout.flush()
|
||||
except socket.timeout:
|
||||
pass
|
||||
if stdin in r:
|
||||
x = stdin.read(1)
|
||||
if len(x) == 0:
|
||||
break
|
||||
chan.sendall(x)
|
||||
finally:
|
||||
termios.tcsetattr(stdin, termios.TCSADRAIN, oldtty)
|
||||
|
||||
# thanks to Mike Looijmans for this code
|
||||
def _windows_shell(self, chan):
|
||||
import threading
|
||||
|
||||
stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
|
||||
|
||||
def writeall(sock):
|
||||
while True:
|
||||
data = sock.recv(256)
|
||||
if not data:
|
||||
stdout.write('\r\n*** EOF ***\r\n\r\n')
|
||||
stdout.flush()
|
||||
break
|
||||
stdout.write(data)
|
||||
stdout.flush()
|
||||
|
||||
writer = threading.Thread(target=writeall, args=(chan,))
|
||||
writer.start()
|
||||
|
||||
try:
|
||||
while True:
|
||||
d = stdin.read(1)
|
||||
if not d:
|
||||
break
|
||||
chan.send(d)
|
||||
except EOFError:
|
||||
# user hit ^Z or F6
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
BuildozerRemote().run_command(sys.argv[1:])
|
||||
except BuildozerCommandException:
|
||||
pass
|
||||
except BuildozerException as error:
|
||||
Buildozer().error('%s' % error)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,13 +1,15 @@
|
|||
from sys import exit
|
||||
import os
|
||||
from os.path import join
|
||||
|
||||
|
||||
def no_config(f):
|
||||
f.__no_config = True
|
||||
return f
|
||||
|
||||
class Target(object):
|
||||
|
||||
class Target:
|
||||
def __init__(self, buildozer):
|
||||
super(Target, self).__init__()
|
||||
self.buildozer = buildozer
|
||||
self.build_mode = 'debug'
|
||||
self.platform_update = False
|
||||
|
@ -22,7 +24,7 @@ class Target(object):
|
|||
'{0} error(s) found in the buildozer.spec'.format(
|
||||
len(errors)))
|
||||
for error in errors:
|
||||
print error
|
||||
print(error)
|
||||
exit(1)
|
||||
|
||||
def compile_platform(self):
|
||||
|
@ -52,8 +54,13 @@ class Target(object):
|
|||
|
||||
result = []
|
||||
last_command = []
|
||||
for arg in args:
|
||||
if not arg.startswith('--'):
|
||||
while args:
|
||||
arg = args.pop(0)
|
||||
if arg == '--':
|
||||
if last_command:
|
||||
last_command += args
|
||||
break
|
||||
elif not arg.startswith('--'):
|
||||
if last_command:
|
||||
result.append(last_command)
|
||||
last_command = []
|
||||
|
@ -97,7 +104,38 @@ class Target(object):
|
|||
self.buildozer.build()
|
||||
|
||||
def cmd_release(self, *args):
|
||||
error = self.buildozer.error
|
||||
self.buildozer.prepare_for_build()
|
||||
if self.buildozer.config.get("app", "package.domain") == "org.test":
|
||||
error("")
|
||||
error("ERROR: Trying to release a package that starts with org.test")
|
||||
error("")
|
||||
error("The package.domain org.test is, as the name intented, a test.")
|
||||
error("Once you published an application with org.test,")
|
||||
error("you cannot change it, it will be part of the identifier")
|
||||
error("for Google Play / App Store / etc.")
|
||||
error("")
|
||||
error("So change package.domain to anything else.")
|
||||
error("")
|
||||
error("If you messed up before, set the environment variable to force the build:")
|
||||
error("export BUILDOZER_ALLOW_ORG_TEST_DOMAIN=1")
|
||||
error("")
|
||||
if "BUILDOZER_ALLOW_ORG_TEST_DOMAIN" not in os.environ:
|
||||
exit(1)
|
||||
|
||||
if self.buildozer.config.get("app", "package.domain") == "org.kivy":
|
||||
error("")
|
||||
error("ERROR: Trying to release a package that starts with org.kivy")
|
||||
error("")
|
||||
error("The package.domain org.kivy is reserved for the Kivy official")
|
||||
error("applications. Please use your own domain.")
|
||||
error("")
|
||||
error("If you are a Kivy developer, add an export in your shell")
|
||||
error("export BUILDOZER_ALLOW_KIVY_ORG_DOMAIN=1")
|
||||
error("")
|
||||
if "BUILDOZER_ALLOW_KIVY_ORG_DOMAIN" not in os.environ:
|
||||
exit(1)
|
||||
|
||||
self.build_mode = 'release'
|
||||
self.buildozer.build()
|
||||
|
||||
|
@ -110,3 +148,116 @@ class Target(object):
|
|||
def cmd_serve(self, *args):
|
||||
self.buildozer.cmd_serve()
|
||||
|
||||
def path_or_git_url(self, repo, owner='kivy', branch='master',
|
||||
url_format='https://github.com/{owner}/{repo}.git',
|
||||
platform=None,
|
||||
squash_hyphen=True):
|
||||
"""Get source location for a git checkout
|
||||
|
||||
This method will check the `buildozer.spec` for the keys:
|
||||
{repo}_dir
|
||||
{repo}_url
|
||||
{repo}_branch
|
||||
|
||||
and use them to determine the source location for a git checkout.
|
||||
|
||||
If a `platform` is specified, {platform}.{repo} will be used
|
||||
as the base for the buildozer key
|
||||
|
||||
`{repo}_dir` specifies a custom checkout location
|
||||
(relative to `buildozer.root_dir`). If present, `path` will be
|
||||
set to this value and `url`, `branch` will be set to None,
|
||||
None. Otherwise, `{repo}_url` and `{repo}_branch` will be
|
||||
examined.
|
||||
|
||||
If no keys are present, the kwargs will be used to create
|
||||
a sensible default URL and branch.
|
||||
|
||||
:Parameters:
|
||||
`repo`: str (required)
|
||||
name of repository to fetch. Used both for buildozer
|
||||
keys ({platform}.{repo}_dir|_url|_branch) and in building
|
||||
default git URL
|
||||
`branch`: str (default 'master')
|
||||
Specific branch to retrieve if none specified in
|
||||
buildozer.spec.
|
||||
`owner`: str
|
||||
owner of repo.
|
||||
`platform`: str or None
|
||||
platform prefix to use when retrieving `buildozer.spec`
|
||||
keys. If specified, key names will be {platform}.{repo}
|
||||
instead of just {repo}
|
||||
`squash_hyphen`: boolean
|
||||
if True, change '-' to '_' when looking for
|
||||
keys in buildozer.spec. This lets us keep backwards
|
||||
compatibility with old buildozer.spec files
|
||||
`url_format`: format string
|
||||
Used to construct default git URL.
|
||||
can use {repo} {owner} and {branch} if needed.
|
||||
|
||||
:Returns:
|
||||
A Tuple (path, url, branch) where
|
||||
`path`
|
||||
Path to a custom git checkout. If specified,
|
||||
both `url` and `branch` will be None
|
||||
`url`
|
||||
URL of git repository from where code should be
|
||||
checked-out
|
||||
`branch`
|
||||
branch name (or tag) that should be used for the
|
||||
check-out.
|
||||
|
||||
"""
|
||||
if squash_hyphen:
|
||||
key = repo.replace('-', '_')
|
||||
else:
|
||||
key = repo
|
||||
if platform:
|
||||
key = "{}.{}".format(platform, key)
|
||||
config = self.buildozer.config
|
||||
path = config.getdefault('app', '{}_dir'.format(key), None)
|
||||
|
||||
if path is not None:
|
||||
path = join(self.buildozer.root_dir, path)
|
||||
url = None
|
||||
branch = None
|
||||
else:
|
||||
branch = config.getdefault('app', '{}_branch'.format(key), branch)
|
||||
default_url = url_format.format(owner=owner, repo=repo, branch=branch)
|
||||
url = config.getdefault('app', '{}_url'.format(key), default_url)
|
||||
if branch != 'master':
|
||||
url = "--branch {} {}".format(branch, url)
|
||||
return path, url, branch
|
||||
|
||||
def install_or_update_repo(self, repo, **kwargs):
|
||||
"""Install or update a git repository into the platform directory.
|
||||
|
||||
This will clone the contents of a git repository to
|
||||
`buildozer.platform_dir`. The location of this repo can be
|
||||
specified via URL and branch name, or via a custom (local)
|
||||
directory name.
|
||||
|
||||
:Parameters:
|
||||
**kwargs:
|
||||
Any valid arguments for :meth:`path_or_git_url`
|
||||
|
||||
:Returns:
|
||||
fully qualified path to updated git repo
|
||||
"""
|
||||
cmd = self.buildozer.cmd
|
||||
install_dir = join(self.buildozer.platform_dir, repo)
|
||||
custom_dir, clone_url, clone_branch = self.path_or_git_url(repo, **kwargs)
|
||||
if not self.buildozer.file_exists(install_dir):
|
||||
if custom_dir:
|
||||
cmd('mkdir -p "{}"'.format(install_dir))
|
||||
cmd('cp -a "{}"/* "{}"/'.format(custom_dir, install_dir))
|
||||
else:
|
||||
cmd('git clone {}'.format(clone_url),
|
||||
cwd=self.buildozer.platform_dir)
|
||||
elif self.platform_update:
|
||||
if custom_dir:
|
||||
cmd('cp -a "{}"/* "{}"/'.format(custom_dir, install_dir))
|
||||
else:
|
||||
cmd('git clean -dxf', cwd=install_dir)
|
||||
cmd('git pull origin {}'.format(clone_branch), cwd=install_dir)
|
||||
return install_dir
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,13 +1,15 @@
|
|||
'''
|
||||
iOS target, based on kivy-ios project. (not working yet.)
|
||||
iOS target, based on kivy-ios project
|
||||
'''
|
||||
|
||||
import sys
|
||||
import plistlib
|
||||
from buildozer import BuildozerCommandException
|
||||
from buildozer.target import Target, no_config
|
||||
from os.path import join, basename
|
||||
from os.path import join, basename, expanduser, realpath
|
||||
from getpass import getpass
|
||||
|
||||
|
||||
PHP_TEMPLATE = '''
|
||||
<?php
|
||||
// credits goes to http://jeffreysambells.com/2010/06/22/ios-wireless-app-distribution
|
||||
|
@ -54,17 +56,28 @@ li { padding: 1em; }
|
|||
</html>
|
||||
'''
|
||||
|
||||
|
||||
class TargetIos(Target):
|
||||
targetname = "ios"
|
||||
|
||||
def __init__(self, buildozer):
|
||||
super().__init__(buildozer)
|
||||
executable = sys.executable or 'python'
|
||||
self._toolchain_cmd = f"{executable} toolchain.py "
|
||||
self._xcodebuild_cmd = "xcodebuild "
|
||||
# set via install_platform()
|
||||
self.ios_dir = None
|
||||
self.ios_deploy_dir = None
|
||||
|
||||
def check_requirements(self):
|
||||
if sys.platform != "darwin":
|
||||
raise NotImplementedError("Only macOS is supported for iOS target")
|
||||
checkbin = self.buildozer.checkbin
|
||||
cmd = self.buildozer.cmd
|
||||
|
||||
checkbin('Xcode xcodebuild', 'xcodebuild')
|
||||
checkbin('Xcode xcode-select', 'xcode-select')
|
||||
checkbin('Git git', 'git')
|
||||
checkbin('Cython', 'cython')
|
||||
checkbin('Mercurial', 'hg')
|
||||
checkbin('Cython cython', 'cython')
|
||||
checkbin('pkg-config', 'pkg-config')
|
||||
checkbin('autoconf', 'autoconf')
|
||||
|
@ -88,30 +101,79 @@ class TargetIos(Target):
|
|||
self.buildozer.debug(' -> found {0}'.format(xcode))
|
||||
|
||||
def install_platform(self):
|
||||
cmd = self.buildozer.cmd
|
||||
self.ios_dir = ios_dir = join(self.buildozer.platform_dir, 'kivy-ios')
|
||||
if not self.buildozer.file_exists(ios_dir):
|
||||
cmd('git clone git://github.com/kivy/kivy-ios',
|
||||
cwd=self.buildozer.platform_dir)
|
||||
elif self.platform_update:
|
||||
cmd('git clean -dxf', cwd=ios_dir)
|
||||
cmd('git pull origin master', cwd=ios_dir)
|
||||
"""
|
||||
Clones `kivy/kivy-ios` and `phonegap/ios-deploy` then sets `ios_dir`
|
||||
and `ios_deploy_dir` accordingly.
|
||||
"""
|
||||
self.ios_dir = self.install_or_update_repo('kivy-ios', platform='ios')
|
||||
self.ios_deploy_dir = self.install_or_update_repo('ios-deploy',
|
||||
platform='ios',
|
||||
branch='1.7.0',
|
||||
owner='phonegap')
|
||||
|
||||
self.fruitstrap_dir = fruitstrap_dir = join(self.buildozer.platform_dir,
|
||||
'fruitstrap')
|
||||
if not self.buildozer.file_exists(fruitstrap_dir):
|
||||
cmd('git clone git://github.com/mpurland/fruitstrap.git',
|
||||
cwd=self.buildozer.platform_dir)
|
||||
def toolchain(self, cmd, **kwargs):
|
||||
kwargs.setdefault('cwd', self.ios_dir)
|
||||
return self.buildozer.cmd(self._toolchain_cmd + cmd, **kwargs)
|
||||
|
||||
def xcodebuild(self, *args, **kwargs):
|
||||
return self.buildozer.cmd(self._xcodebuild_cmd + ' '.join(arg for arg in args if arg is not None), **kwargs)
|
||||
|
||||
@property
|
||||
def code_signing_allowed(self):
|
||||
allowed = self.buildozer.config.getboolean("app", "ios.codesign.allowed")
|
||||
allowed = "YES" if allowed else "NO"
|
||||
return f"CODE_SIGNING_ALLOWED={allowed}"
|
||||
|
||||
@property
|
||||
def code_signing_development_team(self):
|
||||
team = self.buildozer.config.getdefault("app", f"ios.codesign.development_team.{self.build_mode}", None)
|
||||
return f"DEVELOPMENT_TEAM={team}" if team else None
|
||||
|
||||
def get_available_packages(self):
|
||||
available_modules = self.toolchain("recipes --compact", get_stdout=True)[0]
|
||||
return available_modules.splitlines()[0].split()
|
||||
|
||||
def compile_platform(self):
|
||||
state = self.buildozer.state
|
||||
is_compiled = state.get('ios.platform.compiled', '')
|
||||
if not is_compiled:
|
||||
self.buildozer.cmd('tools/build-all.sh', cwd=self.ios_dir)
|
||||
state['ios.platform.compiled'] = '1'
|
||||
# for ios, the compilation depends really on the app requirements.
|
||||
# compile the distribution only if the requirements changed.
|
||||
last_requirements = self.buildozer.state.get('ios.requirements', '')
|
||||
app_requirements = self.buildozer.config.getlist('app', 'requirements',
|
||||
'')
|
||||
|
||||
if not self.buildozer.file_exists(self.fruitstrap_dir, 'fruitstrap'):
|
||||
self.buildozer.cmd('make fruitstrap', cwd=self.fruitstrap_dir)
|
||||
# we need to extract the requirements that kivy-ios knows about
|
||||
available_modules = self.get_available_packages()
|
||||
onlyname = lambda x: x.split('==')[0] # noqa: E731 do not assign a lambda expression, use a def
|
||||
ios_requirements = [x for x in app_requirements if onlyname(x) in
|
||||
available_modules]
|
||||
|
||||
need_compile = 0
|
||||
if last_requirements != ios_requirements:
|
||||
need_compile = 1
|
||||
|
||||
# len('requirements.source.') == 20, so use name[20:]
|
||||
source_dirs = {'{}_DIR'.format(name[20:].upper()):
|
||||
realpath(expanduser(value))
|
||||
for name, value in self.buildozer.config.items('app')
|
||||
if name.startswith('requirements.source.')}
|
||||
if source_dirs:
|
||||
need_compile = 1
|
||||
self.buildozer.environ.update(source_dirs)
|
||||
self.buildozer.info('Using custom source dirs:\n {}'.format(
|
||||
'\n '.join(['{} = {}'.format(k, v)
|
||||
for k, v in source_dirs.items()])))
|
||||
|
||||
if not need_compile:
|
||||
self.buildozer.info('Distribution already compiled, pass.')
|
||||
return
|
||||
|
||||
modules_str = ' '.join(ios_requirements)
|
||||
self.toolchain(f"build {modules_str}")
|
||||
|
||||
if not self.buildozer.file_exists(self.ios_deploy_dir, 'ios-deploy'):
|
||||
self.xcodebuild(cwd=self.ios_deploy_dir)
|
||||
|
||||
self.buildozer.state['ios.requirements'] = ios_requirements
|
||||
self.buildozer.state.sync()
|
||||
|
||||
def _get_package(self):
|
||||
config = self.buildozer.config
|
||||
|
@ -128,41 +190,65 @@ class TargetIos(Target):
|
|||
app_name = self.buildozer.namify(self.buildozer.config.get('app',
|
||||
'package.name'))
|
||||
|
||||
self.app_project_dir = join(self.ios_dir, 'app-{0}'.format(app_name.lower()))
|
||||
ios_frameworks = self.buildozer.config.getlist('app', 'ios.frameworks', '')
|
||||
frameworks_cmd = ''
|
||||
for framework in ios_frameworks:
|
||||
frameworks_cmd += '--add-framework={} '.format(framework)
|
||||
|
||||
self.app_project_dir = join(self.ios_dir, '{0}-ios'.format(app_name.lower()))
|
||||
if not self.buildozer.file_exists(self.app_project_dir):
|
||||
self.buildozer.cmd('tools/create-xcode-project.sh {0} {1}'.format(
|
||||
app_name, self.buildozer.app_dir),
|
||||
cwd=self.ios_dir)
|
||||
cmd = f"create {frameworks_cmd}{app_name} {self.buildozer.app_dir}"
|
||||
else:
|
||||
self.buildozer.cmd('tools/populate-project.sh {0} {1}'.format(
|
||||
app_name, self.buildozer.app_dir),
|
||||
cwd=self.ios_dir)
|
||||
cmd = f"update {frameworks_cmd}{app_name}-ios"
|
||||
self.toolchain(cmd)
|
||||
|
||||
# fix the plist
|
||||
plist_fn = '{}-Info.plist'.format(app_name.lower())
|
||||
plist_rfn = join(self.app_project_dir, plist_fn)
|
||||
version = self.buildozer.get_version()
|
||||
self.buildozer.info('Update Plist {}'.format(plist_fn))
|
||||
plist = plistlib.readPlist(plist_rfn)
|
||||
with open(plist_rfn, 'rb') as f:
|
||||
plist = plistlib.load(f)
|
||||
plist['CFBundleIdentifier'] = self._get_package()
|
||||
plist['CFBundleShortVersionString'] = version
|
||||
plist['CFBundleVersion'] = '{}.{}'.format(version,
|
||||
self.buildozer.build_id)
|
||||
|
||||
# add icon
|
||||
icon = self._get_icon()
|
||||
if icon:
|
||||
plist['CFBundleIconFiles'] = [icon]
|
||||
plist['CFBundleIcons'] = {'CFBundlePrimaryIcon': {
|
||||
'UIPrerenderedIcon': False, 'CFBundleIconFiles': [icon]}}
|
||||
# add icons
|
||||
self._create_icons()
|
||||
|
||||
# Generate OTA distribution manifest if `app_url`, `display_image_url` and `full_size_image_url` are defined.
|
||||
app_url = self.buildozer.config.getdefault("app", "ios.manifest.app_url", None)
|
||||
display_image_url = self.buildozer.config.getdefault("app", "ios.manifest.display_image_url", None)
|
||||
full_size_image_url = self.buildozer.config.getdefault("app", "ios.manifest.full_size_image_url", None)
|
||||
|
||||
if any((app_url, display_image_url, full_size_image_url)):
|
||||
|
||||
if not all((app_url, display_image_url, full_size_image_url)):
|
||||
self.buildozer.error("Options ios.manifest.app_url, ios.manifest.display_image_url"
|
||||
" and ios.manifest.full_size_image_url should be defined all together")
|
||||
return
|
||||
|
||||
plist['manifest'] = {
|
||||
'appURL': app_url,
|
||||
'displayImageURL': display_image_url,
|
||||
'fullSizeImageURL': full_size_image_url,
|
||||
}
|
||||
|
||||
# ok, write the modified plist.
|
||||
plistlib.writePlist(plist, plist_rfn)
|
||||
with open(plist_rfn, 'wb') as f:
|
||||
plistlib.dump(plist, f)
|
||||
|
||||
mode = 'Debug' if self.build_mode == 'debug' else 'Release'
|
||||
self.buildozer.cmd('xcodebuild -configuration {} clean build'.format(mode),
|
||||
mode = self.build_mode.capitalize()
|
||||
self.xcodebuild(
|
||||
f'-configuration {mode}',
|
||||
'-allowProvisioningUpdates',
|
||||
'ENABLE_BITCODE=NO',
|
||||
self.code_signing_allowed,
|
||||
self.code_signing_development_team,
|
||||
'clean build',
|
||||
cwd=self.app_project_dir)
|
||||
ios_app_dir = 'app-{app_lower}/build/{mode}-iphoneos/{app_lower}.app'.format(
|
||||
ios_app_dir = '{app_lower}-ios/build/{mode}-iphoneos/{app_lower}.app'.format(
|
||||
app_lower=app_name.lower(), mode=mode)
|
||||
self.buildozer.state['ios:latestappdir'] = ios_app_dir
|
||||
|
||||
|
@ -175,16 +261,39 @@ class TargetIos(Target):
|
|||
elif ioscodesign[0] not in ('"', "'"):
|
||||
ioscodesign = '"{}"'.format(ioscodesign)
|
||||
|
||||
ipa = join(self.buildozer.bin_dir, '{}-{}.ipa'.format(
|
||||
intermediate_dir = join(self.ios_dir, '{}-{}.intermediates'.format(app_name, version))
|
||||
xcarchive = join(intermediate_dir, '{}-{}.xcarchive'.format(
|
||||
app_name, version))
|
||||
self.buildozer.cmd((
|
||||
'/usr/bin/xcrun '
|
||||
'-sdk iphoneos PackageApplication {ios_app_dir} '
|
||||
'-o {ipa} --sign {ioscodesign} --embed '
|
||||
'{ios_app_dir}/embedded.mobileprovision').format(
|
||||
ioscodesign=ioscodesign, ios_app_dir=ios_app_dir,
|
||||
mode=mode, ipa=ipa),
|
||||
cwd=self.ios_dir)
|
||||
ipa_name = '{}-{}.ipa'.format(app_name, version)
|
||||
ipa_tmp = join(intermediate_dir, ipa_name)
|
||||
ipa = join(self.buildozer.bin_dir, ipa_name)
|
||||
build_dir = join(self.ios_dir, '{}-ios'.format(app_name.lower()))
|
||||
|
||||
self.buildozer.rmdir(intermediate_dir)
|
||||
|
||||
self.buildozer.info('Creating archive...')
|
||||
self.xcodebuild(
|
||||
'-alltargets',
|
||||
f'-configuration {mode}',
|
||||
f'-scheme {app_name.lower()}',
|
||||
f'-archivePath "{xcarchive}"',
|
||||
'archive',
|
||||
'ENABLE_BITCODE=NO',
|
||||
self.code_signing_development_team,
|
||||
cwd=build_dir)
|
||||
|
||||
self.buildozer.info('Creating IPA...')
|
||||
self.xcodebuild(
|
||||
'-exportArchive',
|
||||
f'-archivePath "{xcarchive}"',
|
||||
f'-exportOptionsPlist "{plist_rfn}"',
|
||||
f'-exportPath "{ipa_tmp}"',
|
||||
f'CODE_SIGN_IDENTITY={ioscodesign}',
|
||||
'ENABLE_BITCODE=NO',
|
||||
cwd=build_dir)
|
||||
|
||||
self.buildozer.info('Moving IPA to bin...')
|
||||
self.buildozer.file_rename(ipa_tmp, ipa)
|
||||
|
||||
self.buildozer.info('iOS packaging done!')
|
||||
self.buildozer.info('IPA {0} available in the bin directory'.format(
|
||||
|
@ -192,15 +301,13 @@ class TargetIos(Target):
|
|||
self.buildozer.state['ios:latestipa'] = ipa
|
||||
self.buildozer.state['ios:latestmode'] = self.build_mode
|
||||
|
||||
self._create_index()
|
||||
|
||||
def cmd_deploy(self, *args):
|
||||
super(TargetIos, self).cmd_deploy(*args)
|
||||
self._run_fruitstrap(gdb=False)
|
||||
super().cmd_deploy(*args)
|
||||
self._run_ios_deploy(lldb=False)
|
||||
|
||||
def cmd_run(self, *args):
|
||||
super(TargetIos, self).cmd_run(*args)
|
||||
self._run_fruitstrap(gdb=True)
|
||||
super().cmd_run(*args)
|
||||
self._run_ios_deploy(lldb=True)
|
||||
|
||||
def cmd_xcode(self, *args):
|
||||
'''Open the xcode project.
|
||||
|
@ -211,9 +318,9 @@ class TargetIos(Target):
|
|||
|
||||
ios_dir = ios_dir = join(self.buildozer.platform_dir, 'kivy-ios')
|
||||
self.buildozer.cmd('open {}.xcodeproj'.format(
|
||||
app_name), cwd=join(ios_dir, 'app-{}'.format(app_name)))
|
||||
app_name), cwd=join(ios_dir, '{}-ios'.format(app_name)))
|
||||
|
||||
def _run_fruitstrap(self, gdb=False):
|
||||
def _run_ios_deploy(self, lldb=False):
|
||||
state = self.buildozer.state
|
||||
if 'ios:latestappdir' not in state:
|
||||
self.buildozer.error(
|
||||
|
@ -221,20 +328,19 @@ class TargetIos(Target):
|
|||
return
|
||||
ios_app_dir = state.get('ios:latestappdir')
|
||||
|
||||
if gdb:
|
||||
gdb_mode = '-d'
|
||||
if lldb:
|
||||
debug_mode = '-d'
|
||||
self.buildozer.info('Deploy and start the application')
|
||||
else:
|
||||
gdb_mode = ''
|
||||
debug_mode = ''
|
||||
self.buildozer.info('Deploy the application')
|
||||
|
||||
self.buildozer.cmd('{fruitstrap} {gdb} -b {app_dir}'.format(
|
||||
fruitstrap=join(self.fruitstrap_dir, 'fruitstrap'),
|
||||
gdb=gdb_mode, app_dir=ios_app_dir),
|
||||
self.buildozer.cmd('{iosdeploy} {debug_mode} -b {app_dir}'.format(
|
||||
iosdeploy=join(self.ios_deploy_dir, 'ios-deploy'),
|
||||
debug_mode=debug_mode, app_dir=ios_app_dir),
|
||||
cwd=self.ios_dir, show_output=True)
|
||||
|
||||
def _get_icon(self):
|
||||
# check the icon size, must be 72x72 or 144x144
|
||||
def _create_icons(self):
|
||||
icon = self.buildozer.config.getdefault('app', 'icon.filename', '')
|
||||
if not icon:
|
||||
return
|
||||
|
@ -242,48 +348,14 @@ class TargetIos(Target):
|
|||
if not self.buildozer.file_exists(icon_fn):
|
||||
self.buildozer.error('Icon {} does not exists'.format(icon_fn))
|
||||
return
|
||||
output = self.buildozer.cmd('file {}'.format(icon),
|
||||
cwd=self.buildozer.app_dir, get_stdout=True)[0]
|
||||
if not output:
|
||||
self.buildozer.error('Unable to read icon {}'.format(icon_fn))
|
||||
return
|
||||
# output is something like:
|
||||
# "data/cancel.png: PNG image data, 50 x 50, 8-bit/color RGBA,
|
||||
# non-interlaced"
|
||||
info = output.splitlines()[0].split(',')
|
||||
fmt = info[0].split(':')[-1].strip()
|
||||
if fmt != 'PNG image data':
|
||||
self.buildozer.error('Only PNG icon are accepted, {} invalid'.format(icon_fn))
|
||||
return
|
||||
size = [int(x.strip()) for x in info[1].split('x')]
|
||||
if size != [72, 72] and size != [144, 144]:
|
||||
# icon cannot be used like that, it need a resize.
|
||||
self.buildozer.error('Invalid PNG size, must be 72x72 or 144x144. Resampling.')
|
||||
nearest_size = 144
|
||||
if size[0] < 144:
|
||||
nearest_size = 72
|
||||
|
||||
icon_basename = 'icon-{}.png'.format(nearest_size)
|
||||
self.buildozer.file_copy(icon_fn, join(self.app_project_dir,
|
||||
icon_basename))
|
||||
self.buildozer.cmd('sips -z {0} {0} {1}'.format(nearest_size,
|
||||
icon_basename), cwd=self.app_project_dir)
|
||||
else:
|
||||
# icon ok, use it as it.
|
||||
icon_basename = 'icon-{}.png'.format(size[0])
|
||||
self.buildozer.file_copy(icon_fn, join(self.app_project_dir,
|
||||
icon_basename))
|
||||
|
||||
icon_fn = join(self.app_project_dir, icon_basename)
|
||||
return icon_fn
|
||||
|
||||
def _create_index(self):
|
||||
# TODO
|
||||
pass
|
||||
self.toolchain(f"icon {self.app_project_dir} {icon_fn}")
|
||||
|
||||
def check_configuration_tokens(self):
|
||||
errors = []
|
||||
config = self.buildozer.config
|
||||
if not config.getboolean('app', 'ios.codesign.allowed'):
|
||||
return
|
||||
identity_debug = config.getdefault('app', 'ios.codesign.debug', '')
|
||||
identity_release = config.getdefault('app', 'ios.codesign.release',
|
||||
identity_debug)
|
||||
|
@ -302,8 +374,7 @@ class TargetIos(Target):
|
|||
elif identity_release not in available_identities:
|
||||
errors.append('[app] identity "{}" not found. '
|
||||
'Check with list_identities'.format(identity_release))
|
||||
|
||||
super(TargetIos, self).check_configuration_tokens(errors)
|
||||
super().check_configuration_tokens(errors)
|
||||
|
||||
@no_config
|
||||
def cmd_list_identities(self, *args):
|
||||
|
@ -319,7 +390,7 @@ class TargetIos(Target):
|
|||
get_stdout=True)[0]
|
||||
|
||||
lines = output.splitlines()[:-1]
|
||||
lines = ['"{}"'.format(x.split('"')[1]) for x in lines]
|
||||
lines = [u'"{}"'.format(x.split('"')[1]) for x in lines]
|
||||
return lines
|
||||
|
||||
def _unlock_keychain(self):
|
||||
|
@ -353,10 +424,10 @@ class TargetIos(Target):
|
|||
if not error:
|
||||
correct = True
|
||||
break
|
||||
self.error('Invalid keychain password')
|
||||
self.buildozer.error('Invalid keychain password')
|
||||
|
||||
if not correct:
|
||||
self.error('Unable to unlock the keychain, exiting.')
|
||||
self.buildozer.error('Unable to unlock the keychain, exiting.')
|
||||
raise BuildozerCommandException()
|
||||
|
||||
# maybe user want to save it for further reuse?
|
||||
|
@ -367,7 +438,7 @@ class TargetIos(Target):
|
|||
|
||||
save = None
|
||||
while save is None:
|
||||
q = raw_input('Do you want to save the password (Y/n): ')
|
||||
q = input('Do you want to save the password (Y/n): ')
|
||||
if q in ('', 'Y'):
|
||||
save = True
|
||||
elif q == 'n':
|
||||
|
@ -377,7 +448,8 @@ class TargetIos(Target):
|
|||
|
||||
if save:
|
||||
with open(password_file, 'wb') as fd:
|
||||
fd.write(password)
|
||||
fd.write(password.encode())
|
||||
|
||||
|
||||
def get_target(buildozer):
|
||||
return TargetIos(buildozer)
|
||||
|
|
246
buildozer/targets/osx.py
Normal file
246
buildozer/targets/osx.py
Normal file
|
@ -0,0 +1,246 @@
|
|||
'''
|
||||
OSX target, based on kivy-sdk-packager
|
||||
'''
|
||||
|
||||
import sys
|
||||
if sys.platform != 'darwin':
|
||||
raise NotImplementedError('This will only work on osx')
|
||||
|
||||
from buildozer.target import Target
|
||||
from os.path import exists, join, abspath, dirname
|
||||
from subprocess import check_call, check_output
|
||||
|
||||
|
||||
class TargetOSX(Target):
|
||||
targetname = "osx"
|
||||
|
||||
def ensure_sdk(self):
|
||||
self.buildozer.info('Check if kivy-sdk-packager exists')
|
||||
if exists(
|
||||
join(self.buildozer.platform_dir, 'kivy-sdk-packager-master')):
|
||||
self.buildozer.info(
|
||||
'kivy-sdk-packager found at '
|
||||
'{}'.format(self.buildozer.platform_dir))
|
||||
return
|
||||
|
||||
self.buildozer.info('kivy-sdk-packager does not exist, clone it')
|
||||
platdir = self.buildozer.platform_dir
|
||||
check_call(
|
||||
('curl', '-O', '-L',
|
||||
'https://github.com/kivy/kivy-sdk-packager/archive/master.zip'),
|
||||
cwd=platdir)
|
||||
check_call(('unzip', 'master.zip'), cwd=platdir)
|
||||
check_call(('rm', 'master.zip'), cwd=platdir)
|
||||
|
||||
def download_kivy(self, cwd, py_branch=2):
|
||||
current_kivy_vers = self.buildozer.config.get('app', 'osx.kivy_version')
|
||||
|
||||
if exists('/Applications/Kivy{}.app'.format(py_branch)):
|
||||
self.buildozer.info('Kivy found in Applications dir...')
|
||||
check_call(
|
||||
('cp', '-a', '/Applications/Kivy{}.app'.format(py_branch),
|
||||
'Kivy.app'), cwd=cwd)
|
||||
|
||||
else:
|
||||
if not exists(join(cwd, 'Kivy{}.dmg'.format(py_branch))):
|
||||
self.buildozer.info('Downloading kivy...')
|
||||
status_code = check_output(
|
||||
('curl', '-L', '--write-out', '%{http_code}', '-o', 'Kivy{}.dmg'.format(py_branch),
|
||||
'https://kivy.org/downloads/{}/Kivy-{}-osx-python{}.dmg'
|
||||
.format(current_kivy_vers, current_kivy_vers, py_branch)),
|
||||
cwd=cwd)
|
||||
|
||||
if status_code == "404":
|
||||
self.buildozer.error(
|
||||
"Unable to download the Kivy App. Check osx.kivy_version in your buildozer.spec, and verify "
|
||||
"Kivy servers are accessible. https://kivy.org/downloads/")
|
||||
check_call(("rm", "Kivy{}.dmg".format(py_branch)), cwd=cwd)
|
||||
sys.exit(1)
|
||||
|
||||
self.buildozer.info('Extracting and installing Kivy...')
|
||||
check_call(('hdiutil', 'attach', cwd + '/Kivy{}.dmg'.format(py_branch)))
|
||||
check_call(('cp', '-a', '/Volumes/Kivy/Kivy.app', './Kivy.app'), cwd=cwd)
|
||||
|
||||
def ensure_kivyapp(self):
|
||||
self.buildozer.info('check if Kivy.app exists in local dir')
|
||||
kivy_app_dir = join(self.buildozer.platform_dir, 'kivy-sdk-packager-master', 'osx')
|
||||
|
||||
py_branch = self.buildozer.config.get('app', 'osx.python_version')
|
||||
|
||||
if not int(py_branch) in (2, 3):
|
||||
self.buildozer.error('incompatible python version... aborting')
|
||||
sys.exit(1)
|
||||
|
||||
if exists(join(kivy_app_dir, 'Kivy.app')):
|
||||
self.buildozer.info('Kivy.app found at ' + kivy_app_dir)
|
||||
else:
|
||||
self.download_kivy(kivy_app_dir, py_branch)
|
||||
|
||||
def check_requirements(self):
|
||||
self.ensure_sdk()
|
||||
self.ensure_kivyapp()
|
||||
|
||||
def check_configuration_tokens(self, errors=None):
|
||||
if errors:
|
||||
self.buildozer.info('Check target configuration tokens')
|
||||
self.buildozer.error(
|
||||
'{0} error(s) found in the buildozer.spec'.format(
|
||||
len(errors)))
|
||||
for error in errors:
|
||||
print(error)
|
||||
sys.exit(1)
|
||||
# check
|
||||
|
||||
def build_package(self):
|
||||
self.buildozer.info('Building package')
|
||||
|
||||
bc = self.buildozer.config
|
||||
bcg = bc.get
|
||||
package_name = bcg('app', 'package.name')
|
||||
domain = bcg('app', 'package.domain')
|
||||
title = bcg('app', 'title')
|
||||
app_deps = open('requirements.txt').read()
|
||||
icon = bc.getdefault('app', 'icon.filename', '')
|
||||
version = self.buildozer.get_version()
|
||||
author = bc.getdefault('app', 'author', '')
|
||||
|
||||
self.buildozer.info('Create {}.app'.format(package_name))
|
||||
cwd = join(self.buildozer.platform_dir, 'kivy-sdk-packager-master', 'osx')
|
||||
# remove kivy from app_deps
|
||||
app_deps = [a for a in app_deps.split('\n') if not a.startswith('#') and a not in ['kivy', '']]
|
||||
|
||||
cmd = [
|
||||
'Kivy.app/Contents/Resources/script',
|
||||
'-m', 'pip', 'install',
|
||||
]
|
||||
cmd.extend(app_deps)
|
||||
check_output(cmd, cwd=cwd)
|
||||
|
||||
cmd = [
|
||||
'python', 'package_app.py', self.buildozer.app_dir,
|
||||
'--appname={}'.format(package_name),
|
||||
'--bundlename={}'.format(title),
|
||||
'--bundleid={}'.format(domain),
|
||||
'--bundleversion={}'.format(version),
|
||||
'--displayname={}'.format(title)
|
||||
]
|
||||
if icon:
|
||||
cmd.append('--icon={}'.format(icon))
|
||||
if author:
|
||||
cmd.append('--author={}'.format(author))
|
||||
|
||||
check_output(cmd, cwd=cwd)
|
||||
|
||||
self.buildozer.info('{}.app created.'.format(package_name))
|
||||
self.buildozer.info('Creating {}.dmg'.format(package_name))
|
||||
check_output(
|
||||
('sh', '-x', 'create-osx-dmg.sh', package_name + '.app'),
|
||||
cwd=cwd)
|
||||
self.buildozer.info('{}.dmg created'.format(package_name))
|
||||
self.buildozer.info('moving {}.dmg to bin.'.format(package_name))
|
||||
binpath = join(
|
||||
self.buildozer.user_build_dir or
|
||||
dirname(abspath(self.buildozer.specfilename)), 'bin')
|
||||
check_output(
|
||||
('cp', '-a', package_name + '.dmg', binpath),
|
||||
cwd=cwd)
|
||||
self.buildozer.info('All Done!')
|
||||
|
||||
def compile_platform(self):
|
||||
pass
|
||||
|
||||
def install_platform(self):
|
||||
# ultimate configuration check.
|
||||
# some of our configuration cannot be check without platform.
|
||||
self.check_configuration_tokens()
|
||||
#
|
||||
self.buildozer.environ.update({
|
||||
'PACKAGES_PATH': self.buildozer.global_packages_dir,
|
||||
})
|
||||
|
||||
def get_custom_commands(self):
|
||||
result = []
|
||||
for x in dir(self):
|
||||
if not x.startswith('cmd_'):
|
||||
continue
|
||||
if x[4:] in self.buildozer.standard_cmds:
|
||||
continue
|
||||
result.append((x[4:], getattr(self, x).__doc__))
|
||||
return result
|
||||
|
||||
def get_available_packages(self):
|
||||
return ['kivy']
|
||||
|
||||
def run_commands(self, args):
|
||||
if not args:
|
||||
self.buildozer.error('Missing target command')
|
||||
self.buildozer.usage()
|
||||
sys.exit(1)
|
||||
|
||||
result = []
|
||||
last_command = []
|
||||
for arg in args:
|
||||
if not arg.startswith('--'):
|
||||
if last_command:
|
||||
result.append(last_command)
|
||||
last_command = []
|
||||
last_command.append(arg)
|
||||
else:
|
||||
if not last_command:
|
||||
self.buildozer.error('Argument passed without a command')
|
||||
self.buildozer.usage()
|
||||
sys.exit(1)
|
||||
last_command.append(arg)
|
||||
if last_command:
|
||||
result.append(last_command)
|
||||
|
||||
config_check = False
|
||||
|
||||
for item in result:
|
||||
command, args = item[0], item[1:]
|
||||
if not hasattr(self, 'cmd_{0}'.format(command)):
|
||||
self.buildozer.error('Unknown command {0}'.format(command))
|
||||
sys.exit(1)
|
||||
|
||||
func = getattr(self, 'cmd_{0}'.format(command))
|
||||
|
||||
need_config_check = not hasattr(func, '__no_config')
|
||||
if need_config_check and not config_check:
|
||||
config_check = True
|
||||
self.check_configuration_tokens()
|
||||
|
||||
func(args)
|
||||
|
||||
def check_build_prepared(self):
|
||||
self._build_prepared = False
|
||||
|
||||
def cmd_clean(self, *args):
|
||||
self.buildozer.clean_platform()
|
||||
|
||||
def cmd_update(self, *args):
|
||||
self.platform_update = True
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_debug(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
self.build_mode = 'debug'
|
||||
self.check_build_prepared()
|
||||
self.buildozer.build()
|
||||
|
||||
def cmd_release(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
self.build_mode = 'release'
|
||||
self.buildozer.build()
|
||||
|
||||
def cmd_deploy(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_run(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_serve(self, *args):
|
||||
self.buildozer.cmd_serve()
|
||||
|
||||
|
||||
def get_target(buildozer):
|
||||
return TargetOSX(buildozer)
|
2
buildozer/tools/packer/.gitignore
vendored
Normal file
2
buildozer/tools/packer/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
packer_cache
|
||||
output-kivy-buildozer-vm
|
7
buildozer/tools/packer/CHANGELOG
Normal file
7
buildozer/tools/packer/CHANGELOG
Normal file
|
@ -0,0 +1,7 @@
|
|||
## Release 2.0 - 13 May 2017
|
||||
|
||||
- Brand new VM image using latest zesty (x)ubuntu (64 bits)
|
||||
- Image created for Virtualbox 5.1.22, with guest-tools
|
||||
- Increase disk space to 20GB
|
||||
- /build can store buildozer builds (specify with build_dir=/build/myapp)
|
||||
- Rewrite welcome document
|
34
buildozer/tools/packer/Makefile
Normal file
34
buildozer/tools/packer/Makefile
Normal file
|
@ -0,0 +1,34 @@
|
|||
.PHONY: all build
|
||||
VERSION := 2.0
|
||||
ANN1 = udp://public.popcorn-tracker.org:6969/announce
|
||||
ANN2 = udp://ipv4.tracker.harry.lu/announce
|
||||
ANN3 = udp://tracker.opentrackr.org:1337/announce
|
||||
ANN4 = udp://9.rarbg.com:2710/announce
|
||||
ANN5 = udp://explodie.org:6969
|
||||
ANN6 = udp://tracker.coppersurfer.tk:6969
|
||||
ANN7 = udp://tracker.leechers-paradise.org:6969
|
||||
ANN8 = udp://zer0day.ch:1337
|
||||
TORRENT_ANNOUNCE := ${ANN1},${ANN2},${ANN3},${ANN4},${ANN5},${ANN6},${ANN7},${ANN8}
|
||||
PACKAGE_FILENAME = kivy-buildozer-vm-${VERSION}.zip
|
||||
|
||||
all: packer repackage torrent upload
|
||||
|
||||
build:
|
||||
packer-io build template.json
|
||||
|
||||
repackage:
|
||||
cd output-kivy-buildozer-vm && mv Kivy kivy-buildozer-vm-${VERSION}
|
||||
cd output-kivy-buildozer-vm && zip -0 -r ${PACKAGE_FILENAME} kivy-buildozer-vm-${VERSION}
|
||||
|
||||
torrent:
|
||||
rm -f output-kivy-buildozer-vm/kivy-buildozer-vm.torrent
|
||||
mktorrent \
|
||||
-a ${TORRENT_ANNOUNCE} \
|
||||
-o output-kivy-buildozer-vm/kivy-buildozer-vm.torrent \
|
||||
-w https://txzone.net/files/torrents/${PACKAGE_FILENAME} \
|
||||
-v output-kivy-buildozer-vm/${PACKAGE_FILENAME}
|
||||
|
||||
upload:
|
||||
# txzone only for now, don't have access to kivy server
|
||||
rsync -avz --info=progress2 output-kivy-buildozer-vm/${PACKAGE_FILENAME} txzone.net:/var/www/websites/txzone.net/files/torrents/
|
||||
rsync -avz --info=progress2 output-kivy-buildozer-vm/kivy-buildozer-vm.torrent txzone.net:/var/www/websites/txzone.net/files/torrents/
|
37
buildozer/tools/packer/README.md
Normal file
37
buildozer/tools/packer/README.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Introduction
|
||||
|
||||
This is the packer template for building the official Kivy/Buildozer VM.
|
||||
It is based on xubuntu.
|
||||
|
||||
# Configure
|
||||
|
||||
You want to edit `http/preseed.cfg` and `template.json` before building an image.
|
||||
|
||||
# Build
|
||||
|
||||
```
|
||||
make packer
|
||||
```
|
||||
|
||||
# Release
|
||||
|
||||
1. Update Makefile to increase the version number
|
||||
2. Update the CHANGELOG
|
||||
3. Commit
|
||||
|
||||
Then:
|
||||
|
||||
```
|
||||
make all
|
||||
# make packer < build the image
|
||||
# make repackage < just zip it (no compression)
|
||||
# make torrent < create the torrent
|
||||
# make upload < upload on txzone.net (tito only)
|
||||
```
|
||||
|
||||
|
||||
# Notes
|
||||
|
||||
- trigger a build on travis, torrent creation and gdrive upload when buildozer is
|
||||
released
|
||||
- https://www.packer.io/docs/builders/virtualbox-ovf.html
|
7
buildozer/tools/packer/http/buildozer.desktop
Normal file
7
buildozer/tools/packer/http/buildozer.desktop
Normal file
|
@ -0,0 +1,7 @@
|
|||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name=Buildozer
|
||||
Exec=firefox -url "file:///usr/share/applications/buildozer-welcome/index.html" -width 600 -height 800
|
||||
Icon=/usr/share/applications/buildozer-welcome/icon.png
|
||||
Categories=Application;Development;favourite;
|
BIN
buildozer/tools/packer/http/kivy-icon-96.png
Normal file
BIN
buildozer/tools/packer/http/kivy-icon-96.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
100
buildozer/tools/packer/http/preseed.cfg
Normal file
100
buildozer/tools/packer/http/preseed.cfg
Normal file
|
@ -0,0 +1,100 @@
|
|||
### Options to set on the command line
|
||||
d-i debian-installer/locale string en_US.UTF-8
|
||||
d-i console-setup/ask_detect boolean false
|
||||
d-i keyboard-configuration/layoutcode string us
|
||||
d-i keyboard-configuration/variant string us
|
||||
|
||||
### Network
|
||||
d-i netcfg/choose_interface select auto
|
||||
d-i netcfg/get_hostname string kivy-buildozer-vm
|
||||
d-i netcfg/get_domain string local
|
||||
d-i netcfg/wireless_wep string
|
||||
|
||||
### Mirror
|
||||
d-i mirror/country string manual
|
||||
d-i mirror/http/hostname string fr.archive.ubuntu.com
|
||||
d-i mirror/http/directory string /ubuntu
|
||||
# d-i mirror/http/hostname string 192.168.1.16:3142
|
||||
# d-i mirror/http/directory string /fr.archive.ubuntu.com/ubuntu
|
||||
d-i mirror/http/proxy string
|
||||
|
||||
### Time
|
||||
d-i time/zone string UTC
|
||||
d-i clock-setup/utc boolean true
|
||||
|
||||
### Partitioning
|
||||
d-i partman-auto/method string lvm
|
||||
d-i partman-lvm/device_remove_lvm boolean true
|
||||
d-i partman-md/device_remove_md boolean true
|
||||
|
||||
# Write the changes to disks and configure LVM?
|
||||
d-i partman-lvm/confirm boolean true
|
||||
d-i partman-lvm/confirm_nooverwrite boolean true
|
||||
|
||||
d-i partman-auto-lvm/guided_size string max
|
||||
d-i partman-auto/choose_recipe select atomic
|
||||
d-i partman/default_filesystem string ext4
|
||||
|
||||
# This makes partman automatically partition without confirmation, provided
|
||||
# that you told it what to do using one of the methods above.
|
||||
#d-i partman-partitioning/confirm_write_new_label boolean true
|
||||
d-i partman/confirm_write_new_label boolean true
|
||||
d-i partman/choose_partition select finish
|
||||
d-i partman/confirm boolean true
|
||||
d-i partman/confirm_nooverwrite boolean true
|
||||
|
||||
### User Account
|
||||
|
||||
# root account
|
||||
#d-i passwd/root-login boolean true
|
||||
#d-i passwd/make-user boolean false
|
||||
#d-i passwd/root-password password abcdabcd
|
||||
#d-i passwd/root-password-again password abcdabcd
|
||||
|
||||
# a user account
|
||||
d-i passwd/user-fullname string kivy
|
||||
d-i passwd/username string kivy
|
||||
d-i passwd/user-password password kivy
|
||||
d-i passwd/user-password-again password kivy
|
||||
|
||||
# you might want to configure auto login.
|
||||
#d-i passwd/auto-login boolean true
|
||||
|
||||
d-i user-setup/allow-password-weak boolean true
|
||||
d-i user-setup/encrypt-home boolean false
|
||||
|
||||
# You can choose to install restricted and universe software, or to install
|
||||
# software from the backports repository.
|
||||
d-i apt-setup/restricted boolean true
|
||||
d-i apt-setup/universe boolean true
|
||||
# d-i apt-setup/backports boolean true
|
||||
|
||||
# Uncomment this if you don't want to use a network mirror.
|
||||
# d-i apt-setup/use_mirror boolean false
|
||||
|
||||
# Select which update services to use; define the mirrors to be used.
|
||||
# Values shown below are the normal defaults.
|
||||
d-i apt-setup/services-select multiselect security
|
||||
d-i apt-setup/security_host string security.ubuntu.com
|
||||
d-i apt-setup/security_path string /ubuntu
|
||||
|
||||
### Packages
|
||||
tasksel tasksel/first multiselect xubuntu-desktop
|
||||
|
||||
d-i pkgsel/include string openssh-server build-essential ibus-hangul
|
||||
d-i pkgsel/upgrade select none
|
||||
d-i pkgsel/update-policy select none
|
||||
d-i pkgsel/language-packs multiselect en, ko
|
||||
# required by ubuntu server iso, but not required by netboot iso
|
||||
d-i pkgsel/install-language-support boolean true
|
||||
|
||||
popularity-contest popularity-contest/participate boolean false
|
||||
|
||||
d-i lilo-installer/skip boolean true
|
||||
|
||||
### Bootloader
|
||||
d-i grub-installer/only_debian boolean true
|
||||
d-i grub-installer/with_other_os boolean true
|
||||
|
||||
### Finishing
|
||||
d-i finish-install/reboot_in_progress note
|
BIN
buildozer/tools/packer/http/wallpaper.png
Normal file
BIN
buildozer/tools/packer/http/wallpaper.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
15
buildozer/tools/packer/http/welcome/buildozer.css
Normal file
15
buildozer/tools/packer/http/welcome/buildozer.css
Normal file
|
@ -0,0 +1,15 @@
|
|||
body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: #fff5f6;
|
||||
border-left: 2px solid #c0392b;
|
||||
padding: 20px;
|
||||
margin-bottom: 2.5rem;
|
||||
padding-bottom: 1px;
|
||||
}
|
102
buildozer/tools/packer/http/welcome/index.html
Normal file
102
buildozer/tools/packer/http/welcome/index.html
Normal file
|
@ -0,0 +1,102 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Kivy/Buildozer VM</title>
|
||||
<link rel="stylesheet" href="milligram.min.css">
|
||||
<link rel="stylesheet" href="buildozer.css"
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Welcome to the Kivy/Buildozer VM</h1>
|
||||
<p id="menu">
|
||||
<a href="https://github.com/kivy/buildozer">Github</a> -
|
||||
<a href="https://buildozer.readthedocs.io/en/latest/">Documentation</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Thanks for using Kivy/Buildozer VM. It has been installed only for
|
||||
packaging Kivy application for Android.<br/>
|
||||
<b>Credentials</b>: username: <code>kivy</code> / password: <code>kivy</code>
|
||||
</p>
|
||||
|
||||
<h2>How to use the VM</h2>
|
||||
<p>
|
||||
Buildozer is ready to be used. You'll need internet connection for
|
||||
download the Android SDK/NDK (automatically done), and during the first
|
||||
compilation.
|
||||
<br/>
|
||||
It is preferable to add a <a href="#sharefolder"> share a folder
|
||||
</a> between your host and the VM, then build from there.<br/>
|
||||
|
||||
By the time we shipped the VM and you using it, you may need to
|
||||
<a href="#update-buildozer">update buildozer</a>.
|
||||
</p>
|
||||
<p>
|
||||
<b>Don't try to use latest Android SDK or NDK</b>. The defaults from buildozer
|
||||
works: Android SDK 20, Android NDK 9c. Recent Android SDK doesn't work
|
||||
the same as before (no more android command), and python-for-android
|
||||
project have issues with it. As for NDK, you can use 13b, it works too.
|
||||
</p>
|
||||
<ol>
|
||||
<li>First time only, in your project directory: <code>buildozer init</code></li>
|
||||
<li>Adjust the <code>buildozer.spec</code>:
|
||||
<pre>[buildozer]
|
||||
# change the name of your app
|
||||
package.name = myapp
|
||||
|
||||
# change the domain of your package
|
||||
package.domain = com.mydomain
|
||||
|
||||
# specify hostpython2 manually. If you want to use python 3, check buildozer
|
||||
# README about it, the VM is not preinstalled for that.
|
||||
requirements = hostpython2,kivy
|
||||
|
||||
[buildozer]
|
||||
# update the build directory (issue with virtualbox shared folder and symlink)
|
||||
build_dir = /build/myapp
|
||||
</pre></li>
|
||||
<li>Build your application: <code>buildozer android debug</code></li>
|
||||
<li>Build and deploy, run and get the logs: <code>buildozer android debug deploy run logcat</code></li>
|
||||
</ol>
|
||||
|
||||
<h2 id="sharefolder">Share a folder</h2>
|
||||
<p>
|
||||
Virtualbox allows you to share a folder between your computer and the
|
||||
VM. To do, just:
|
||||
<ol>
|
||||
<li>Go into Devices > Shared Folders > Shared Folders Settings</li>
|
||||
<li>Add a new folder, select the automount option</li>
|
||||
<li>Reboot the VM (that's easier)</li>
|
||||
<li>You'll find your new directory at <code>/media/sf_directoryname</code></li>
|
||||
</ol>
|
||||
</p>
|
||||
|
||||
<div class="warning">
|
||||
Virtualbox doesn't support symlink in Shared Folder anymore. So buildozer
|
||||
will fail during the build.<br/>
|
||||
We already created a <code>/build</code> directory where you can put your
|
||||
build in it. Edit your <code>buildozer.ini</code>:
|
||||
<pre>[buildozer]
|
||||
build_dir = /build/buildozer-myapp</pre>
|
||||
</div>
|
||||
|
||||
<h2 id="update-buildozer">Update buildozer</h2>
|
||||
<p>
|
||||
The buildozer version you have may be outdated, as well as the dependencies.
|
||||
The best is to regularly update buildozer:
|
||||
<pre>sudo pip install -U buildozer</pre>
|
||||
</p>
|
||||
|
||||
<h2>Cleaning cache</h2>
|
||||
|
||||
<p>
|
||||
The simplest way to update kivy and other modules is to clean all the
|
||||
buildozer cache, and rebuild everything.
|
||||
|
||||
<pre>rm -rf ~/.buildozer/android/packages</pre>
|
||||
<p>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
11
buildozer/tools/packer/http/welcome/milligram.min.css
vendored
Normal file
11
buildozer/tools/packer/http/welcome/milligram.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
3
buildozer/tools/packer/launch
Normal file
3
buildozer/tools/packer/launch
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
/usr/bin/qemu-system-x86_64 -redir tcp:3213::22 -vga qxl -display sdl -netdev user,id=user.0 -device virtio-net,netdev=user.0 -drive file=output-from-netboot-iso/ubuntu.qcow2,if=virtio -boot once=d -name sanitytest -machine type=pc-1.0,accel=kvm -m 512M -vnc 0.0.0.0:47
|
13
buildozer/tools/packer/scripts/additional-packages.sh
Normal file
13
buildozer/tools/packer/scripts/additional-packages.sh
Normal file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash -eux
|
||||
# Don't use openjdk-9, the conf directory is missing, and we get
|
||||
# an error when using the android sdk:
|
||||
# "Can't read cryptographic policy directory: unlimited"
|
||||
|
||||
wget https://bootstrap.pypa.io/get-pip.py
|
||||
python get-pip.py
|
||||
rm get-pip.py
|
||||
|
||||
apt-get -y install lib32stdc++6 lib32z1 lib32ncurses5
|
||||
apt-get -y install build-essential
|
||||
apt-get -y install git openjdk-8-jdk --no-install-recommends zlib1g-dev
|
||||
pip install cython buildozer python-for-android
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Mount the disk image
|
||||
cd /tmp
|
||||
mkdir /tmp/isomount
|
||||
mount -t iso9660 /dev/sr1 /tmp/isomount
|
||||
|
||||
# Install the drivers
|
||||
/tmp/isomount/VBoxLinuxAdditions.run
|
||||
|
||||
# Cleanup
|
||||
umount isomount
|
40
buildozer/tools/packer/scripts/minimize.sh
Normal file
40
buildozer/tools/packer/scripts/minimize.sh
Normal file
|
@ -0,0 +1,40 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Remove unwanted applications
|
||||
apt-get -y remove --purge libreoffice*
|
||||
apt-get -y remove --purge pidgin*
|
||||
apt-get -y remove --purge thunderbird*
|
||||
apt-get -y remove --purge fonts-noto-cjk
|
||||
|
||||
# Remove APT cache
|
||||
apt-get -y --purge autoremove
|
||||
apt-get -y clean
|
||||
|
||||
# Cleanup log files
|
||||
find /var/log -type f | while read f; do echo -ne '' > $f; done;
|
||||
|
||||
# Whiteout root
|
||||
count=`df --sync -kP / | tail -n1 | awk -F ' ' '{print $4}'`;
|
||||
count=$(expr $count - 1)
|
||||
dd if=/dev/zero of=/tmp/whitespace bs=1024 count=$count;
|
||||
rm /tmp/whitespace;
|
||||
|
||||
# Whiteout /boot
|
||||
count=`df --sync -kP /boot | tail -n1 | awk -F ' ' '{print $4}'`;
|
||||
count=$(expr $count - 1)
|
||||
dd if=/dev/zero of=/boot/whitespace bs=1024 count=$count;
|
||||
rm /boot/whitespace;
|
||||
|
||||
swappart=`cat /proc/swaps | tail -n1 | awk -F ' ' '{print $1}'`
|
||||
swapoff $swappart;
|
||||
dd if=/dev/zero of=$swappart;
|
||||
mkswap $swappart;
|
||||
swapon $swappart;
|
||||
|
||||
# Zero free space to aid VM compression
|
||||
dd if=/dev/zero of=/EMPTY bs=1M
|
||||
rm -f /EMPTY
|
||||
|
||||
# Remove bash history
|
||||
unset HISTFILE
|
||||
rm -f /root/.bash_history
|
61
buildozer/tools/packer/scripts/setup.sh
Normal file
61
buildozer/tools/packer/scripts/setup.sh
Normal file
|
@ -0,0 +1,61 @@
|
|||
#!/bin/bash
|
||||
# xfconf doesn't work with sudo, even with XAUTHORITY + DISPLAY
|
||||
# seems that the user need to log to be able to use them.
|
||||
|
||||
# keep them for reference for now.
|
||||
# change theme (works better for this wallpaper)
|
||||
# xfconf-query -c xfce4-desktop \
|
||||
# --property /backdrop/screen0/monitor0/workspace0/last-image \
|
||||
# --set /usr/share/backgrounds/kivy-wallpaper.png
|
||||
# xfconf-query -c xsettings \
|
||||
# --property /Net/ThemeName \
|
||||
# --set Adwaita
|
||||
# xfconf-query -c xsettings \
|
||||
# --property /Net/IconThemeName \
|
||||
# --set elementary-xfce-darker
|
||||
|
||||
|
||||
|
||||
set -x
|
||||
|
||||
# ensure the kivy user can mount shared folders
|
||||
adduser kivy vboxsf
|
||||
|
||||
# create a space specifically for builds
|
||||
mkdir /build
|
||||
chown kivy /build
|
||||
|
||||
# add a little face
|
||||
wget $PACKER_HTTP_ADDR/kivy-icon-96.png
|
||||
mv kivy-icon-96.png /home/kivy/.face
|
||||
chown kivy.kivy /home/kivy/.face
|
||||
|
||||
# set wallpaper
|
||||
wget $PACKER_HTTP_ADDR/wallpaper.png
|
||||
mv wallpaper.png /usr/share/backgrounds/kivy-wallpaper.png
|
||||
sed -i "s:/usr/share/xfce4/backdrops/xubuntu-wallpaper.png:/usr/share/backgrounds/kivy-wallpaper.png:g" /etc/xdg/xdg-xubuntu/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml
|
||||
sed -i "s:Greybird:Adwaita:g" /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml
|
||||
sed -i "s:Greybird:Adwaita:g" /etc/xdg/xdg-xubuntu/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml
|
||||
sed -i "s:Greybird:Adwaita:g" /etc/xdg/xdg-xubuntu/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml
|
||||
sed -i "s:Greybird:Adwaita:g" /etc/xdg/xdg-xubuntu/xfce4/xfconf/xfce-perchannel-xml/xfce4-notifyd.xml
|
||||
sed -i "s:elementary-xfce-darker:elementary-xfce-darkest:g" /etc/xdg/xdg-xubuntu/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml
|
||||
sed -i "s:elementary-xfce-dark:elementary-xfce-darkest:g" /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml
|
||||
|
||||
# add desktop icon
|
||||
wget $PACKER_HTTP_ADDR/buildozer.desktop
|
||||
mkdir -p /home/kivy/Desktop
|
||||
cp buildozer.desktop /home/kivy/Desktop/
|
||||
chown kivy.kivy -R /home/kivy/Desktop
|
||||
chmod +x /home/kivy/Desktop/buildozer.desktop
|
||||
mv buildozer.desktop /usr/share/applications/
|
||||
sed -i "s:^favorites=.*$:favorites=buildozer.desktop,exo-terminal-emulator.desktop,exo-web-browser.desktop,xfce-keyboard-settings.desktop,exo-file-manager.desktop,org.gnome.Software.desktop,xfhelp4.desktop:g" /etc/xdg/xdg-xubuntu/xfce4/whiskermenu/defaults.rc
|
||||
|
||||
# copy welcome directory
|
||||
mkdir -p /usr/share/applications/buildozer-welcome
|
||||
cd /usr/share/applications/buildozer-welcome
|
||||
wget $PACKER_HTTP_ADDR/welcome/milligram.min.css
|
||||
wget $PACKER_HTTP_ADDR/welcome/buildozer.css
|
||||
wget $PACKER_HTTP_ADDR/welcome/index.html
|
||||
wget $PACKER_HTTP_ADDR/kivy-icon-96.png
|
||||
mv kivy-icon-96.png icon.png
|
||||
cd -
|
50
buildozer/tools/packer/template.json
Normal file
50
buildozer/tools/packer/template.json
Normal file
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"variables": {
|
||||
"disk_size": "20480",
|
||||
"disk_format": "ovf",
|
||||
"ssh_username": "kivy",
|
||||
"ssh_password": "kivy",
|
||||
"hostname": "kivyvm"
|
||||
},
|
||||
"description": "Build a Xubuntu Virtual Machine",
|
||||
"builders": [{
|
||||
"type": "virtualbox-iso",
|
||||
"name": "kivy-buildozer-vm",
|
||||
"http_directory": "http",
|
||||
"iso_checksum": "6131e2cc90cf30407af18f3f1af16c54bf58ffc8",
|
||||
"iso_checksum_type": "sha1",
|
||||
"iso_url": "http://archive.ubuntu.com/ubuntu/dists/zesty/main/installer-amd64/current/images/netboot/mini.iso",
|
||||
"ssh_username": "{{user `ssh_username`}}",
|
||||
"ssh_password": "{{user `ssh_password`}}",
|
||||
"boot_wait": "3s",
|
||||
"boot_command": [
|
||||
"<esc><wait>",
|
||||
"/linux noapic preseed/url=http://{{.HTTPIP}}:{{.HTTPPort}}/preseed.cfg ",
|
||||
"hostname={{user `hostname`}} ",
|
||||
"debian-installer=en_US auto locale=en_US kbd-chooser/method=us ",
|
||||
"fb=false ",
|
||||
"keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ",
|
||||
"keyboard-configuration/variant=USA console-setup/ask_detect=false ",
|
||||
"initrd=/initrd.gz -- <enter>"
|
||||
],
|
||||
"disk_size": "{{user `disk_size`}}",
|
||||
"format": "{{user `disk_format`}}",
|
||||
"headless": false,
|
||||
"shutdown_command": "echo {{user `ssh_password`}} | sudo -S shutdown -P now",
|
||||
"vm_name": "Kivy/Buildozer VM",
|
||||
"guest_os_type": "Ubuntu_64",
|
||||
"guest_additions_mode": "attach",
|
||||
"ssh_wait_timeout": "120m"
|
||||
}],
|
||||
"provisioners": [{
|
||||
"type": "shell",
|
||||
"execute_command": "echo {{user `ssh_password`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
|
||||
"scripts": [
|
||||
"scripts/install-virtualbox-guest-additions.sh",
|
||||
"scripts/setup.sh",
|
||||
"scripts/additional-packages.sh",
|
||||
"scripts/minimize.sh"
|
||||
]
|
||||
}],
|
||||
"post-processors": []
|
||||
}
|
177
docs/Makefile
Normal file
177
docs/Makefile
Normal file
|
@ -0,0 +1,177 @@
|
|||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = build
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from https://www.sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Buildozer.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Buildozer.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/Buildozer"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Buildozer"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
latexpdfja:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
242
docs/make.bat
Normal file
242
docs/make.bat
Normal file
|
@ -0,0 +1,242 @@
|
|||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set BUILDDIR=build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% source
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. singlehtml to make a single large HTML file
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. devhelp to make HTML files and a Devhelp project
|
||||
echo. epub to make an epub
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. text to make text files
|
||||
echo. man to make manual pages
|
||||
echo. texinfo to make Texinfo files
|
||||
echo. gettext to make PO message catalogs
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. xml to make Docutils-native XML files
|
||||
echo. pseudoxml to make pseudoxml-XML files for display purposes
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
|
||||
%SPHINXBUILD% 2> nul
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "singlehtml" (
|
||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Buildozer.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Buildozer.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "devhelp" (
|
||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub" (
|
||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdf" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf
|
||||
cd %BUILDDIR%/..
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdfja" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf-ja
|
||||
cd %BUILDDIR%/..
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "text" (
|
||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "man" (
|
||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "texinfo" (
|
||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "gettext" (
|
||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "xml" (
|
||||
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The XML files are in %BUILDDIR%/xml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pseudoxml" (
|
||||
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
248
docs/source/conf.py
Normal file
248
docs/source/conf.py
Normal file
|
@ -0,0 +1,248 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Buildozer documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun Apr 20 16:56:31 2014.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = []
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Buildozer'
|
||||
copyright = u'2014, Kivy\'s Developers'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.11'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.11'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = []
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Buildozerdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'Buildozer.tex', u'Buildozer Documentation',
|
||||
u'Kivy\'s Developers', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'buildozer', u'Buildozer Documentation',
|
||||
[u'Kivy\'s Developers'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'Buildozer', u'Buildozer Documentation',
|
||||
u'Kivy\'s Developers', 'Buildozer', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
49
docs/source/contribute.rst
Normal file
49
docs/source/contribute.rst
Normal file
|
@ -0,0 +1,49 @@
|
|||
Contribute
|
||||
==========
|
||||
|
||||
|
||||
Write your own recipe
|
||||
---------------------
|
||||
|
||||
A recipe allows you to compile libraries / python extension for the mobile.
|
||||
Most of the time, the default compilation instructions doesn't work for the
|
||||
target, as ARM compiler / Android NDK introduce specificities that the library
|
||||
you want doesn't handle correctly, and you'll need to patch. Also, because the
|
||||
Android platform cannot load more than 64 inline dynamic libraries, we have a
|
||||
mechanism to bundle all of them in one to ensure you'll not hit this
|
||||
limitation.
|
||||
|
||||
To test your own recipe via Buildozer, you need to:
|
||||
|
||||
#. Fork `Python for Android <https://github.com/kivy/python-for-android>`_, and
|
||||
clone your own version (this will allow easy contribution later)::
|
||||
|
||||
git clone https://github.com/YOURNAME/python-for-android
|
||||
|
||||
#. Change your `buildozer.spec` to reference your version::
|
||||
|
||||
p4a.source_dir = /path/to/your/python-for-android
|
||||
|
||||
#. Copy your recipe into `python-for-android/recipes/YOURLIB/recipe.sh`
|
||||
|
||||
#. Rebuild.
|
||||
|
||||
When you correctly get the compilation and your recipe works, you can ask us to
|
||||
include it in the python-for-android project, by issuing a Pull Request:
|
||||
|
||||
#. Create a branch::
|
||||
|
||||
git checkout --track -b recipe-YOURLIB origin/master
|
||||
|
||||
#. Add and commit::
|
||||
|
||||
git add python-for-android/recipes/YOURLIB/*
|
||||
git commit -am 'Add support for YOURLIB`
|
||||
|
||||
#. Push to Github
|
||||
|
||||
git push origin master
|
||||
|
||||
#. Go to `https://github.com/YOURNAME/python-for-android`, and you should see
|
||||
your new branch and a button "Pull Request" on it. Use it, write a
|
||||
description about what you did, and Send!
|
47
docs/source/index.rst
Normal file
47
docs/source/index.rst
Normal file
|
@ -0,0 +1,47 @@
|
|||
.. Buildozer documentation master file, created by
|
||||
sphinx-quickstart on Sun Apr 20 16:56:31 2014.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to Buildozer's documentation!
|
||||
=====================================
|
||||
|
||||
Buildozer is a tool that aim to package mobiles application easily. It
|
||||
automates the entire build process, download the prerequisites like
|
||||
python-for-android, Android SDK, NDK, etc.
|
||||
|
||||
Buildozer manage a file named `buildozer.spec` in your application directory,
|
||||
describing your application requirements and settings such as title, icon,
|
||||
included modules etc. It will use the specification file to create a package
|
||||
for Android, iOS, and more.
|
||||
|
||||
Currently, Buildozer supports packaging for:
|
||||
|
||||
- Android: via `Python for Android
|
||||
<https://github.com/kivy/python-for-android>`_. You must have a Linux or OSX
|
||||
computer to be able to compile for Android.
|
||||
|
||||
- iOS: via `Kivy iOS <https://github.com/kivy/kivy-ios>`_. You must have an OSX
|
||||
computer to be able to compile for iOS.
|
||||
|
||||
- Supporting others platform is in the roadmap (such as .exe for Windows, .dmg
|
||||
for OSX, etc.)
|
||||
|
||||
If you have any questions about Buildozer, please refer to the `Kivy's user
|
||||
mailing list <https://groups.google.com/forum/#!forum/kivy-users>`_.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
installation
|
||||
quickstart
|
||||
specifications
|
||||
contribute
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
132
docs/source/installation.rst
Normal file
132
docs/source/installation.rst
Normal file
|
@ -0,0 +1,132 @@
|
|||
|
||||
Installation
|
||||
============
|
||||
|
||||
Buildozer itself doesn't depend on any library Python >= 3.3.
|
||||
Depending the platform you want to target, you might need more tools installed.
|
||||
Buildozer tries to give you hints or tries to install few things for
|
||||
you, but it doesn't cover every situation.
|
||||
|
||||
First, install the buildozer project with::
|
||||
|
||||
pip3 install --user --upgrade buildozer
|
||||
|
||||
Targeting Android
|
||||
-----------------
|
||||
|
||||
Android on Ubuntu 20.04 (64bit)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(expected to work as well in later version, but only regularly tested in the latest LTS)
|
||||
|
||||
::
|
||||
|
||||
sudo apt update
|
||||
sudo apt install -y git zip unzip openjdk-13-jdk python3-pip autoconf libtool pkg-config zlib1g-dev libncurses5-dev libncursesw5-dev libtinfo5 cmake libffi-dev libssl-dev
|
||||
pip3 install --user --upgrade Cython==0.29.19 virtualenv # the --user should be removed if you do this in a venv
|
||||
|
||||
# add the following line at the end of your ~/.bashrc file
|
||||
export PATH=$PATH:~/.local/bin/
|
||||
|
||||
Android on Windows 10
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To use buildozer in Windows 10 you need first to enable Windows Subsystem for Linux (WSL) and install a Linux distribution: https://docs.microsoft.com/en-us/windows/wsl/install-win10.
|
||||
|
||||
These instructions were tested with WSL 1 and Ubuntu 18.04 LTS.
|
||||
|
||||
After installing WSL and Ubuntu in your Windows 10 machine, open Ubuntu and do this:
|
||||
|
||||
1) Run the commands listed on the previous section (Android in Ubuntu 18.04 (64-bit).
|
||||
2) Run the following commands:
|
||||
|
||||
::
|
||||
|
||||
# Use here the python version you need
|
||||
sudo apt install -y python3.7-venv
|
||||
# Create a folder for buildozer. For example: C:\buildozer
|
||||
mkdir /mnt/c/buildozer
|
||||
cd /mnt/c/buildozer
|
||||
python3.7 -m venv venv-buildozer
|
||||
source venv/bin/activate
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade wheel
|
||||
python -m pip install --upgrade cython
|
||||
python -m pip install --upgrade virtualenv
|
||||
python -m pip install --upgrade buildozer
|
||||
# Restart your WSL terminal to enable the path change
|
||||
|
||||
Windows Subsystem for Linux does not have direct access to USB. Due to this, you need to install the Windows version of ADB (Android Debug Bridge):
|
||||
|
||||
- Go to https://developer.android.com/studio/releases/platform-tools and click on "Download SDK Platform-Tools for Windows".
|
||||
|
||||
- Unzip the downloaded file to a new folder. For example, "C:\\platform-tools".
|
||||
|
||||
Before Using Buildozer
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you wish, clone your code to a new folder, where the build process will run.
|
||||
|
||||
You don't need to create a virtualenv for your code requirements. But just add these requirements to a configuration file called buildozer.spec as you will see in the following sections.
|
||||
|
||||
Before running buildozer in your code folder, remember to go into the buildozer folder and activate the buildozer virtualenv.
|
||||
|
||||
Android on macOS
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
brew install openssl
|
||||
sudo ln -sfn /usr/local/opt/openssl /usr/local/ssl
|
||||
brew install pkg-config autoconf automake
|
||||
python3 -m pip install --user --upgrade Cython==0.29.19 virtualenv # the --user should be removed if you do this in a venv
|
||||
|
||||
# add the following line at the end of your `~/.bashrc` file
|
||||
export PATH=$PATH:~/Library/Python/3.7/bin
|
||||
|
||||
|
||||
TroubleShooting
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Buildozer stuck on "Installing/updating SDK platform tools if necessary"
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Press "y" then enter to continue, the license acceptance system is silently waiting for your input
|
||||
|
||||
|
||||
Aidl not found, please install it.
|
||||
""""""""""""""""""""""""""""""""""
|
||||
|
||||
Buildozer didn't install a necessary package
|
||||
|
||||
::
|
||||
|
||||
~/.buildozer/android/platform/android-sdk/tools/bin/sdkmanager "build-tools;29.0.0"
|
||||
|
||||
Then press "y" then enter to accept the license.
|
||||
|
||||
|
||||
python-for-android related errors
|
||||
"""""""""""""""""""""""""""""""""
|
||||
See the dedicated `p4a troubleshooting documentation
|
||||
<https://python-for-android.readthedocs.io/en/latest/troubleshooting/>`_.
|
||||
|
||||
|
||||
Targeting IOS
|
||||
-------------
|
||||
|
||||
Install XCode and command line tools (through the AppStore)
|
||||
|
||||
|
||||
Install homebrew (https://brew.sh)
|
||||
|
||||
::
|
||||
|
||||
brew install pkg-config sdl2 sdl2_image sdl2_ttf sdl2_mixer gstreamer autoconf automake
|
||||
|
||||
|
||||
Install pip and virtualenv
|
||||
|
||||
::
|
||||
|
||||
python3 -m pip install --user --upgrade pip virtualenv kivy-ios
|
106
docs/source/quickstart.rst
Normal file
106
docs/source/quickstart.rst
Normal file
|
@ -0,0 +1,106 @@
|
|||
Quickstart
|
||||
==========
|
||||
|
||||
Let's get started with Buildozer!
|
||||
|
||||
Init and build for Android
|
||||
--------------------------
|
||||
|
||||
#. Buildozer will try to guess the version of your application, by searching a
|
||||
line like `__version__ = "1.0.3"` in your `main.py`. Ensure you have one at
|
||||
the start of your application. It is not mandatory but heavily advised.
|
||||
|
||||
#. Create a `buildozer.spec` file, with::
|
||||
|
||||
buildozer init
|
||||
|
||||
#. Edit the `buildozer.spec` according to the :ref:`specifications`. You should
|
||||
at least change the `title`, `package.name` and `package.domain` in the
|
||||
`[app]` section.
|
||||
|
||||
#. Start a Android/debug build with::
|
||||
|
||||
buildozer -v android debug
|
||||
|
||||
#. Now it's time for a coffee / tea, or a dinner if you have a slow computer.
|
||||
The first build will be slow, as it will download the Android SDK, NDK, and
|
||||
others tools needed for the compilation.
|
||||
Don't worry, thoses files will be saved in a global directory and will be
|
||||
shared across the different project you'll manage with Buildozer.
|
||||
|
||||
#. At the end, you should have an APK file in the `bin/` directory.
|
||||
|
||||
|
||||
Run my application
|
||||
------------------
|
||||
|
||||
Buildozer is able to deploy the application on your mobile, run it, and even
|
||||
get back the log into the console. It will work only if you already compiled
|
||||
your application at least once::
|
||||
|
||||
buildozer android deploy run logcat
|
||||
|
||||
For iOS, it would look the same::
|
||||
|
||||
buildozer ios deploy run
|
||||
|
||||
You can combine the compilation with the deployment::
|
||||
|
||||
buildozer -v android debug deploy run logcat
|
||||
|
||||
You can also set this line at the default command to do if Buildozer is started
|
||||
without any arguments::
|
||||
|
||||
buildozer setdefault android debug deploy run logcat
|
||||
|
||||
# now just type buildozer, and it will do the default command
|
||||
buildozer
|
||||
|
||||
To save the logcat output into a file named `my_log.txt` (the file will appear in your current directory)::
|
||||
|
||||
buildozer -v android debug deploy run logcat > my_log.txt
|
||||
|
||||
To see your running application's print() messages and python's error messages, use:
|
||||
|
||||
::
|
||||
|
||||
buildozer -v android deploy run logcat | grep python
|
||||
|
||||
Run my application from Windows 10
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Plug your Android device on a USB port.
|
||||
|
||||
- Open Windows PowerShell, go into the folder where you installed the Windows version of ADB, and activate the ADB daemon. When the daemon is started you must see a number besides the word "device" meaning your device was correctly detected. In case of trouble, try another USB port or USB cable.
|
||||
|
||||
::
|
||||
|
||||
cd C:\platform-tools\
|
||||
.\adb.exe devices
|
||||
|
||||
- Open the Linux distribution you installed on Windows Subsystem for Linux (WSL) and proceed with the deploy commands:
|
||||
|
||||
::
|
||||
|
||||
buildozer -v android deploy run
|
||||
|
||||
It is important to notice that Windows ADB and Buildozer installed ADB must be the same version. To check the versions, open PowerShell and type:
|
||||
|
||||
::
|
||||
|
||||
cd C:\platform-tools\
|
||||
.\adb.exe version
|
||||
wsl
|
||||
cd ~/.buildozer/android/platform/android-sdk/platform-tools/
|
||||
./adb version
|
||||
|
||||
Install on non-connected devices
|
||||
--------------------------------
|
||||
|
||||
If you have compiled a package, and want to share it easily with others
|
||||
devices, you might be interested with the `serve` command. It will serve the
|
||||
`bin/` directory over HTTP. Then you just have to access to the URL showed in
|
||||
the console from your mobile::
|
||||
|
||||
buildozer serve
|
||||
|
128
docs/source/specifications.rst
Normal file
128
docs/source/specifications.rst
Normal file
|
@ -0,0 +1,128 @@
|
|||
Specifications
|
||||
==============
|
||||
|
||||
This document explains in detail all the configuration tokens you can use in
|
||||
`buildozer.spec`.
|
||||
|
||||
Section [app]
|
||||
-------------
|
||||
|
||||
- `title`: String, title of your application.
|
||||
|
||||
It might be possible that some characters are not working depending on the
|
||||
targeted platform. It's best to try and see if everything works as expected.
|
||||
Try to avoid too long titles, as they will also not fit in the title
|
||||
displayed under the icon.
|
||||
|
||||
- `package.name`: String, package name.
|
||||
|
||||
The Package name is one word with only ASCII characters and/or numbers. It
|
||||
should not contain any special characters. For example, if your application
|
||||
is named `Flat Jewels`, the package name can be `flatjewels`.
|
||||
|
||||
- `package.domain`: String, package domain.
|
||||
|
||||
Package domain is a string that references the company or individual that
|
||||
did the app. Both domain+name will become your application identifier for
|
||||
Android and iOS, choose it carefully. As an example, when the Kivy`s team
|
||||
is publishing an application, the domain starts with `org.kivy`.
|
||||
|
||||
- `source.dir`: String, location of your application sources.
|
||||
|
||||
The location must be a directory that contains a `main.py` file. It defaults
|
||||
to the directory where `buildozer.spec` is.
|
||||
|
||||
- `source.include_exts`: List, file extensions to include.
|
||||
|
||||
By default, not all files in your `source.dir` are included, but only some
|
||||
of them (`py,png,jpg,kv,atlas`), depending on the extension. Feel free to
|
||||
add your own extensions, or use an empty value if you want to include
|
||||
everything.
|
||||
|
||||
- `source.exclude_exts`: List, file extensions to exclude.
|
||||
|
||||
In contrary to `source.include_exts`, you could include all the files you
|
||||
want except the ones that end with an extension listed in this token. If
|
||||
empty, no files will be excluded based on their extensions.
|
||||
|
||||
- `source.exclude_dirs`: List, directories to exclude.
|
||||
|
||||
Same as `source.exclude_exts`, but for directories. You can exclude your
|
||||
`tests` and `bin` directory with::
|
||||
|
||||
source.exclude_dirs = tests, bin
|
||||
|
||||
- `source.exclude_patterns`: List, files to exclude if they match a pattern.
|
||||
|
||||
If you have a more complex application layout, you might need a pattern to
|
||||
exclude files. It also works if you don't have a pattern. For example::
|
||||
|
||||
source.exclude_patterns = license,images/originals/*
|
||||
|
||||
- `version.regex`: Regex, Regular expression to capture the version in
|
||||
`version.filename`.
|
||||
|
||||
The default capture method of your application version is by grepping a line
|
||||
like this::
|
||||
|
||||
__version__ = "1.0"
|
||||
|
||||
The `1.0` will be used as a version.
|
||||
|
||||
- `version.filename`: String, defaults to the main.py.
|
||||
|
||||
File to use for capturing the version with `version.regex`.
|
||||
|
||||
- `version`: String, manual application version.
|
||||
|
||||
If you don't want to capture the version, comment out both `version.regex`
|
||||
and `version.filename`, then put the version you want directly in the
|
||||
`version` token::
|
||||
|
||||
# version.regex =
|
||||
# version.filename =
|
||||
version = 1.0
|
||||
|
||||
- `requirements`: List, Python modules or extensions that your application
|
||||
requires.
|
||||
|
||||
The requirements can be either a name of a recipe in the Python-for-android
|
||||
project, or a pure-Python package. For example, if your application requires
|
||||
Kivy and requests, you need to write::
|
||||
|
||||
requirements = kivy,requests
|
||||
|
||||
If your application tries to install a Python extension (ie, a Python
|
||||
package that requires compilation), and the extension doesn't have a recipe
|
||||
associated to Python-for-android, it will not work. We explicitly disable
|
||||
the compilation here. If you want to make it work, contribute to the
|
||||
Python-for-android project by creating a recipe. See :doc:`contribute`.
|
||||
|
||||
- `presplash.filename`: String, loading screen of your application.
|
||||
|
||||
Presplash is the image shown on the device during application loading.
|
||||
It is called presplash on Android, and Loading image on iOS. The image might
|
||||
have different requirements depending the platform. Currently, Buildozer
|
||||
works well only with Android, iOS support is not great on this.
|
||||
|
||||
The image must be a JPG or PNG, preferable with Power-of-two size, e.g., a
|
||||
512x512 image is perfect to target all the devices. The image is not fitted,
|
||||
scaled, or anything on the device. If you provide a too-large image, it might
|
||||
not fit on small screens.
|
||||
|
||||
- `icon.filename`: String, icon of your application.
|
||||
|
||||
The icon of your application. It must be a PNG of 512x512 size to be able to
|
||||
cover all the various platform requirements.
|
||||
|
||||
- `orientation`: String, orientation of the application.
|
||||
|
||||
Indicate the orientation that your application supports. Defaults to
|
||||
`landscape`, but can be changed to `portrait` or `all`.
|
||||
|
||||
- `fullscreen`: Boolean, fullscreen mode.
|
||||
|
||||
Defaults to true, your application will run in fullscreen. Means the status
|
||||
bar will be hidden. If you want to let the user access the status bar,
|
||||
hour, notifications, use 0 as a value.
|
||||
|
43
files.txt
Normal file
43
files.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
/usr/local/bin/buildozer
|
||||
/usr/local/bin/buildozer-remote
|
||||
/usr/local/bin/virtualenv
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/PKG-INFO
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/SOURCES.txt
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/dependency_links.txt
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/entry_points.txt
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/not-zip-safe
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/requires.txt
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/top_level.txt
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/__init__.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/__init__.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/__main__.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/__main__.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/default.spec
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/jsonstore.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/jsonstore.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/__init__.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/__init__.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/_structures.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/_structures.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/version.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/version.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/__init__.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/__init__.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/client.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/client.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/remote.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/remote.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/sitecustomize.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/sitecustomize.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/target.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/target.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/__init__.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/__init__.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/android.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/android.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/android_new.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/android_new.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/ios.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/ios.pyc
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/osx.py
|
||||
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/osx.pyc
|
83
setup.py
83
setup.py
|
@ -1,19 +1,82 @@
|
|||
from distutils.core import setup
|
||||
'''
|
||||
Buildozer
|
||||
'''
|
||||
|
||||
import buildozer
|
||||
import sys
|
||||
from setuptools import setup
|
||||
from os.path import dirname, join
|
||||
import codecs
|
||||
import os
|
||||
import re
|
||||
import io
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
CURRENT_PYTHON = sys.version_info[:2]
|
||||
REQUIRED_PYTHON = (3, 6)
|
||||
|
||||
# This check and everything above must remain compatible with Python 2.7.
|
||||
if CURRENT_PYTHON < REQUIRED_PYTHON:
|
||||
sys.stderr.write("""
|
||||
==========================
|
||||
Unsupported Python version
|
||||
==========================
|
||||
This version of buildozer requires Python {}.{}, but you're trying to
|
||||
install it on Python {}.{}.
|
||||
""".format(*(REQUIRED_PYTHON + CURRENT_PYTHON)))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
def find_version(*file_paths):
|
||||
# Open in Latin-1 so that we avoid encoding errors.
|
||||
# Use codecs.open for Python 2 compatibility
|
||||
with codecs.open(os.path.join(here, *file_paths), 'r', 'utf-8') as f:
|
||||
version_file = f.read()
|
||||
|
||||
# The version line must have the form
|
||||
# __version__ = 'ver'
|
||||
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
|
||||
version_file, re.M)
|
||||
if version_match:
|
||||
return version_match.group(1)
|
||||
raise RuntimeError("Unable to find version string.")
|
||||
|
||||
|
||||
curdir = dirname(__file__)
|
||||
with io.open(join(curdir, "README.md"), encoding="utf-8") as fd:
|
||||
readme = fd.read()
|
||||
with io.open(join(curdir, "CHANGELOG.md"), encoding="utf-8") as fd:
|
||||
changelog = fd.read()
|
||||
|
||||
setup(
|
||||
name='buildozer',
|
||||
version=buildozer.__version__,
|
||||
version=find_version('buildozer', '__init__.py'),
|
||||
description='Generic Python packager for Android / iOS and Desktop',
|
||||
long_description=readme + "\n\n" + changelog,
|
||||
long_description_content_type='text/markdown',
|
||||
author='Mathieu Virbel',
|
||||
author_email='mat@kivy.org',
|
||||
url='http://github.com/kivy/buildozer',
|
||||
url='https://github.com/kivy/buildozer',
|
||||
license='MIT',
|
||||
packages=[
|
||||
'buildozer',
|
||||
'buildozer.targets',
|
||||
'buildozer.libs'],
|
||||
'buildozer', 'buildozer.targets', 'buildozer.libs', 'buildozer.scripts'
|
||||
],
|
||||
package_data={'buildozer': ['default.spec']},
|
||||
scripts=['tools/buildozer', 'tools/buildozer-remote'],
|
||||
description='Generic Python packager for Android / iOS and Desktop'
|
||||
)
|
||||
include_package_data=True,
|
||||
install_requires=['pexpect', 'virtualenv', 'sh'],
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Developers',
|
||||
'Topic :: Software Development :: Build Tools',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'buildozer=buildozer.scripts.client:main',
|
||||
'buildozer-remote=buildozer.scripts.remote:main'
|
||||
]
|
||||
})
|
||||
|
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
0
tests/scripts/__init__.py
Normal file
0
tests/scripts/__init__.py
Normal file
26
tests/scripts/test_client.py
Normal file
26
tests/scripts/test_client.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
import sys
|
||||
import unittest
|
||||
from buildozer import BuildozerCommandException
|
||||
from buildozer.scripts import client
|
||||
from unittest import mock
|
||||
|
||||
|
||||
class TestClient(unittest.TestCase):
|
||||
|
||||
def test_run_command_called(self):
|
||||
"""
|
||||
Checks Buildozer.run_command() is being called with arguments from command line.
|
||||
"""
|
||||
with mock.patch('buildozer.Buildozer.run_command') as m_run_command:
|
||||
client.main()
|
||||
assert m_run_command.call_args_list == [mock.call(sys.argv[1:])]
|
||||
|
||||
def test_exit_code(self):
|
||||
"""
|
||||
Makes sure the CLI exits with error code on BuildozerCommandException, refs #674.
|
||||
"""
|
||||
with mock.patch('buildozer.Buildozer.run_command') as m_run_command:
|
||||
m_run_command.side_effect = BuildozerCommandException()
|
||||
with self.assertRaises(SystemExit) as context:
|
||||
client.main()
|
||||
assert context.exception.code == 1
|
394
tests/targets/test_android.py
Normal file
394
tests/targets/test_android.py
Normal file
|
@ -0,0 +1,394 @@
|
|||
import os
|
||||
import tempfile
|
||||
from six import StringIO
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from buildozer.targets.android import TargetAndroid
|
||||
from tests.targets.utils import (
|
||||
init_buildozer,
|
||||
patch_buildozer,
|
||||
patch_buildozer_checkbin,
|
||||
patch_buildozer_cmd,
|
||||
patch_buildozer_file_exists,
|
||||
)
|
||||
|
||||
|
||||
def patch_buildozer_cmd_expect():
|
||||
return patch_buildozer("cmd_expect")
|
||||
|
||||
|
||||
def patch_buildozer_download():
|
||||
return patch_buildozer("download")
|
||||
|
||||
|
||||
def patch_buildozer_file_extract():
|
||||
return patch_buildozer("file_extract")
|
||||
|
||||
|
||||
def patch_os_isfile():
|
||||
return mock.patch("os.path.isfile")
|
||||
|
||||
|
||||
def patch_target_android(method):
|
||||
return mock.patch(
|
||||
"buildozer.targets.android.TargetAndroid.{method}".format(method=method)
|
||||
)
|
||||
|
||||
|
||||
def patch_platform(platform):
|
||||
return mock.patch("buildozer.targets.android.platform", platform)
|
||||
|
||||
|
||||
def init_target(temp_dir, options=None):
|
||||
buildozer = init_buildozer(temp_dir, "android", options)
|
||||
return TargetAndroid(buildozer)
|
||||
|
||||
|
||||
def call_build_package(target_android):
|
||||
"""
|
||||
Call the build_package() method of the tested TargetAndroid instance,
|
||||
patching the functions that would otherwise produce side-effects.
|
||||
|
||||
Return the mocked execute_build_package() method of the TargetAndroid
|
||||
instance so that tests can easily check which command-line arguments
|
||||
would be passed on to python-for-android's toolchain.
|
||||
"""
|
||||
buildozer = target_android.buildozer
|
||||
expected_dist_dir = (
|
||||
'{buildozer_dir}/android/platform/build-armeabi-v7a/dists/myapp__armeabi-v7a'.format(
|
||||
buildozer_dir=buildozer.buildozer_dir)
|
||||
)
|
||||
|
||||
with patch_target_android('_update_libraries_references') as m_update_libraries_references, \
|
||||
patch_target_android('_generate_whitelist') as m_generate_whitelist, \
|
||||
mock.patch('buildozer.targets.android.TargetAndroid.execute_build_package') as m_execute_build_package, \
|
||||
mock.patch('buildozer.targets.android.copyfile') as m_copyfile, \
|
||||
mock.patch('buildozer.targets.android.os.listdir') as m_listdir:
|
||||
m_listdir.return_value = ['30.0.0-rc2']
|
||||
target_android.build_package()
|
||||
|
||||
assert m_listdir.call_count == 1
|
||||
assert m_update_libraries_references.call_args_list == [
|
||||
mock.call(expected_dist_dir)
|
||||
]
|
||||
assert m_generate_whitelist.call_args_list == [mock.call(expected_dist_dir)]
|
||||
assert m_copyfile.call_args_list == [
|
||||
mock.call(
|
||||
'{expected_dist_dir}/bin/MyApplication-0.1-debug.apk'.format(
|
||||
expected_dist_dir=expected_dist_dir
|
||||
),
|
||||
'{bin_dir}/myapp-0.1-armeabi-v7a-debug.apk'.format(bin_dir=buildozer.bin_dir),
|
||||
)
|
||||
]
|
||||
return m_execute_build_package
|
||||
|
||||
|
||||
class TestTargetAndroid:
|
||||
|
||||
def setup_method(self):
|
||||
"""
|
||||
Create a temporary directory that will contain the spec file and will
|
||||
serve as the root_dir.
|
||||
"""
|
||||
self.temp_dir = tempfile.TemporaryDirectory()
|
||||
|
||||
def tear_method(self):
|
||||
"""
|
||||
Remove the temporary directory created in self.setup_method.
|
||||
"""
|
||||
self.temp_dir.cleanup()
|
||||
|
||||
def test_init(self):
|
||||
"""Tests init defaults."""
|
||||
target_android = init_target(self.temp_dir)
|
||||
buildozer = target_android.buildozer
|
||||
assert target_android._arch == "armeabi-v7a"
|
||||
assert target_android._build_dir.endswith(
|
||||
".buildozer/android/platform/build-armeabi-v7a"
|
||||
)
|
||||
assert target_android._p4a_bootstrap == "sdl2"
|
||||
assert target_android._p4a_cmd.endswith(
|
||||
"python -m pythonforandroid.toolchain "
|
||||
)
|
||||
assert target_android.build_mode == "debug"
|
||||
assert (
|
||||
target_android.extra_p4a_args == (
|
||||
' --color=always'
|
||||
' --storage-dir="{buildozer_dir}/android/platform/build-armeabi-v7a" --ndk-api=21 --ignore-setup-py'.format(
|
||||
buildozer_dir=buildozer.buildozer_dir)
|
||||
)
|
||||
)
|
||||
assert target_android.p4a_apk_cmd == "apk --debug --bootstrap=sdl2"
|
||||
assert target_android.platform_update is False
|
||||
|
||||
def test_init_positional_buildozer(self):
|
||||
"""Positional `buildozer` argument is required."""
|
||||
with pytest.raises(TypeError) as ex_info:
|
||||
TargetAndroid()
|
||||
assert ex_info.value.args == (
|
||||
"__init__() missing 1 required positional argument: 'buildozer'",
|
||||
)
|
||||
|
||||
def test_sdkmanager(self):
|
||||
"""Tests the _sdkmanager() method."""
|
||||
target_android = init_target(self.temp_dir)
|
||||
kwargs = {}
|
||||
with patch_buildozer_cmd() as m_cmd, patch_buildozer_cmd_expect() as m_cmd_expect, patch_os_isfile() as m_isfile:
|
||||
m_isfile.return_value = True
|
||||
assert m_cmd.return_value == target_android._sdkmanager(**kwargs)
|
||||
assert m_cmd.call_count == 1
|
||||
assert m_cmd_expect.call_count == 0
|
||||
assert m_isfile.call_count == 1
|
||||
kwargs = {"return_child": True}
|
||||
with patch_buildozer_cmd() as m_cmd, patch_buildozer_cmd_expect() as m_cmd_expect, patch_os_isfile() as m_isfile:
|
||||
m_isfile.return_value = True
|
||||
assert m_cmd_expect.return_value == target_android._sdkmanager(
|
||||
**kwargs
|
||||
)
|
||||
assert m_cmd.call_count == 0
|
||||
assert m_cmd_expect.call_count == 1
|
||||
assert m_isfile.call_count == 1
|
||||
|
||||
def test_check_requirements(self):
|
||||
"""Basic tests for the check_requirements() method."""
|
||||
target_android = init_target(self.temp_dir)
|
||||
buildozer = target_android.buildozer
|
||||
assert not hasattr(target_android, "adb_cmd")
|
||||
assert not hasattr(target_android, "javac_cmd")
|
||||
assert "PATH" not in buildozer.environ
|
||||
with patch_buildozer_checkbin() as m_checkbin:
|
||||
target_android.check_requirements()
|
||||
assert m_checkbin.call_args_list == [
|
||||
mock.call("Git (git)", "git"),
|
||||
mock.call("Cython (cython)", "cython"),
|
||||
mock.call("Java compiler (javac)", "javac"),
|
||||
mock.call("Java keytool (keytool)", "keytool"),
|
||||
]
|
||||
assert target_android.adb_cmd.endswith(
|
||||
".buildozer/android/platform/android-sdk/platform-tools/adb"
|
||||
)
|
||||
assert target_android.javac_cmd == "javac"
|
||||
assert target_android.keytool_cmd == "keytool"
|
||||
assert "PATH" in buildozer.environ
|
||||
|
||||
def test_check_configuration_tokens(self):
|
||||
"""Basic tests for the check_configuration_tokens() method."""
|
||||
target_android = init_target(self.temp_dir)
|
||||
with mock.patch(
|
||||
"buildozer.targets.android.Target.check_configuration_tokens"
|
||||
) as m_check_configuration_tokens:
|
||||
target_android.check_configuration_tokens()
|
||||
assert m_check_configuration_tokens.call_args_list == [mock.call([])]
|
||||
|
||||
@pytest.mark.parametrize("platform", ["linux", "darwin"])
|
||||
def test_install_android_sdk(self, platform):
|
||||
"""Basic tests for the _install_android_sdk() method."""
|
||||
target_android = init_target(self.temp_dir)
|
||||
with patch_buildozer_file_exists() as m_file_exists, patch_buildozer_download() as m_download:
|
||||
m_file_exists.return_value = True
|
||||
sdk_dir = target_android._install_android_sdk()
|
||||
assert m_file_exists.call_args_list == [
|
||||
mock.call(target_android.android_sdk_dir)
|
||||
]
|
||||
assert m_download.call_args_list == []
|
||||
assert sdk_dir.endswith(".buildozer/android/platform/android-sdk")
|
||||
with patch_buildozer_file_exists() as m_file_exists, \
|
||||
patch_buildozer_download() as m_download, \
|
||||
patch_buildozer_file_extract() as m_file_extract, \
|
||||
patch_platform(platform):
|
||||
m_file_exists.return_value = False
|
||||
sdk_dir = target_android._install_android_sdk()
|
||||
assert m_file_exists.call_args_list == [
|
||||
mock.call(target_android.android_sdk_dir)
|
||||
]
|
||||
platform_map = {"linux": "linux", "darwin": "mac"}
|
||||
platform = platform_map[platform]
|
||||
archive = "commandlinetools-{platform}-6514223_latest.zip".format(platform=platform)
|
||||
assert m_download.call_args_list == [
|
||||
mock.call(
|
||||
"https://dl.google.com/android/repository/",
|
||||
archive,
|
||||
cwd=mock.ANY,
|
||||
)
|
||||
]
|
||||
assert m_file_extract.call_args_list == [mock.call(archive, cwd=mock.ANY)]
|
||||
assert sdk_dir.endswith(".buildozer/android/platform/android-sdk")
|
||||
|
||||
def test_build_package(self):
|
||||
"""Basic tests for the build_package() method."""
|
||||
target_android = init_target(self.temp_dir)
|
||||
buildozer = target_android.buildozer
|
||||
m_execute_build_package = call_build_package(target_android)
|
||||
assert m_execute_build_package.call_args_list == [
|
||||
mock.call(
|
||||
[
|
||||
("--name", "'My Application'"),
|
||||
("--version", "0.1"),
|
||||
("--package", "org.test.myapp"),
|
||||
("--minsdk", "21"),
|
||||
("--ndk-api", "21"),
|
||||
("--private", "{buildozer_dir}/android/app".format(buildozer_dir=buildozer.buildozer_dir)),
|
||||
("--android-entrypoint", "org.kivy.android.PythonActivity"),
|
||||
("--android-apptheme", "@android:style/Theme.NoTitleBar"),
|
||||
("--orientation", "portrait"),
|
||||
("--window",),
|
||||
("debug",),
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
def test_numeric_version(self):
|
||||
"""The `android.numeric_version` config should be passed to `build_package()`."""
|
||||
target_android = init_target(self.temp_dir, {
|
||||
"android.numeric_version": "1234"
|
||||
})
|
||||
buildozer = target_android.buildozer
|
||||
m_execute_build_package = call_build_package(target_android)
|
||||
assert m_execute_build_package.call_args_list == [
|
||||
mock.call(
|
||||
[
|
||||
("--name", "'My Application'"),
|
||||
("--version", "0.1"),
|
||||
("--package", "org.test.myapp"),
|
||||
("--minsdk", "21"),
|
||||
("--ndk-api", "21"),
|
||||
("--private", "{buildozer_dir}/android/app".format(buildozer_dir=buildozer.buildozer_dir)),
|
||||
("--android-entrypoint", "org.kivy.android.PythonActivity"),
|
||||
("--android-apptheme", "@android:style/Theme.NoTitleBar"),
|
||||
("--orientation", "portrait"),
|
||||
("--window",),
|
||||
("--numeric-version", "1234"),
|
||||
("debug",),
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
def test_build_package_intent_filters(self):
|
||||
"""
|
||||
The build_package() method should honour the manifest.intent_filters
|
||||
config option.
|
||||
"""
|
||||
filters_path = os.path.join(self.temp_dir.name, 'filters.xml')
|
||||
|
||||
with open(filters_path, 'w') as f:
|
||||
f.write('<?xml version="1.0" encoding="utf-8"?>')
|
||||
|
||||
target_android = init_target(self.temp_dir, {
|
||||
'android.manifest.intent_filters': 'filters.xml'
|
||||
})
|
||||
buildozer = target_android.buildozer
|
||||
m_execute_build_package = call_build_package(target_android)
|
||||
|
||||
assert m_execute_build_package.call_args_list == [
|
||||
mock.call(
|
||||
[
|
||||
('--name', "'My Application'"),
|
||||
('--version', '0.1'),
|
||||
('--package', 'org.test.myapp'),
|
||||
('--minsdk', '21'),
|
||||
('--ndk-api', '21'),
|
||||
('--private', '{buildozer_dir}/android/app'.format(buildozer_dir=buildozer.buildozer_dir)),
|
||||
('--android-entrypoint', 'org.kivy.android.PythonActivity'),
|
||||
('--android-apptheme', '@android:style/Theme.NoTitleBar'),
|
||||
('--orientation', 'portrait'),
|
||||
('--window',),
|
||||
('--intent-filters', os.path.realpath(filters_path)),
|
||||
('debug',),
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
def test_allow_backup(self):
|
||||
"""The `android.allow_backup` config should be passed to `build_package()`."""
|
||||
target_android = init_target(self.temp_dir, {
|
||||
"android.allow_backup": "false"
|
||||
})
|
||||
buildozer = target_android.buildozer
|
||||
m_execute_build_package = call_build_package(target_android)
|
||||
assert m_execute_build_package.call_args_list == [
|
||||
mock.call(
|
||||
[
|
||||
("--name", "'My Application'"),
|
||||
("--version", "0.1"),
|
||||
("--package", "org.test.myapp"),
|
||||
("--minsdk", "21"),
|
||||
("--ndk-api", "21"),
|
||||
("--private", "{buildozer_dir}/android/app".format(buildozer_dir=buildozer.buildozer_dir)),
|
||||
("--android-entrypoint", "org.kivy.android.PythonActivity"),
|
||||
("--android-apptheme", "@android:style/Theme.NoTitleBar"),
|
||||
("--orientation", "portrait"),
|
||||
("--window",),
|
||||
("--allow-backup", "false"),
|
||||
("debug",),
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
def test_backup_rules(self):
|
||||
"""The `android.backup_rules` config should be passed to `build_package()`."""
|
||||
target_android = init_target(self.temp_dir, {
|
||||
"android.backup_rules": "backup_rules.xml"
|
||||
})
|
||||
buildozer = target_android.buildozer
|
||||
m_execute_build_package = call_build_package(target_android)
|
||||
assert m_execute_build_package.call_args_list == [
|
||||
mock.call(
|
||||
[
|
||||
("--name", "'My Application'"),
|
||||
("--version", "0.1"),
|
||||
("--package", "org.test.myapp"),
|
||||
("--minsdk", "21"),
|
||||
("--ndk-api", "21"),
|
||||
("--private", "{buildozer_dir}/android/app".format(buildozer_dir=buildozer.buildozer_dir)),
|
||||
("--android-entrypoint", "org.kivy.android.PythonActivity"),
|
||||
("--android-apptheme", "@android:style/Theme.NoTitleBar"),
|
||||
("--orientation", "portrait"),
|
||||
("--window",),
|
||||
("--backup-rules", "{root_dir}/backup_rules.xml".format(root_dir=buildozer.root_dir)),
|
||||
("debug",),
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
def test_install_platform_p4a_clone_url(self):
|
||||
"""The `p4a.url` config should be used for cloning p4a before the `p4a.fork` option."""
|
||||
target_android = init_target(self.temp_dir, {
|
||||
'p4a.url': 'https://custom-p4a-url/p4a.git',
|
||||
'p4a.fork': 'myfork',
|
||||
})
|
||||
|
||||
with patch_buildozer_cmd() as m_cmd, mock.patch('buildozer.targets.android.open') as m_open:
|
||||
m_open.return_value = StringIO('install_reqs = []') # to stub setup.py parsing
|
||||
target_android._install_p4a()
|
||||
|
||||
assert mock.call(
|
||||
'git clone -b master --single-branch https://custom-p4a-url/p4a.git python-for-android',
|
||||
cwd=mock.ANY) in m_cmd.call_args_list
|
||||
|
||||
def test_install_platform_p4a_clone_fork(self):
|
||||
"""The `p4a.fork` config should be used for cloning p4a."""
|
||||
target_android = init_target(self.temp_dir, {
|
||||
'p4a.fork': 'fork'
|
||||
})
|
||||
|
||||
with patch_buildozer_cmd() as m_cmd, mock.patch('buildozer.targets.android.open') as m_open:
|
||||
m_open.return_value = StringIO('install_reqs = []') # to stub setup.py parsing
|
||||
target_android._install_p4a()
|
||||
|
||||
assert mock.call(
|
||||
'git clone -b master --single-branch https://github.com/fork/python-for-android.git python-for-android',
|
||||
cwd=mock.ANY) in m_cmd.call_args_list
|
||||
|
||||
def test_install_platform_p4a_clone_default(self):
|
||||
"""The default URL should be used for cloning p4a if no config options `p4a.url` and `p4a.fork` are set."""
|
||||
target_android = init_target(self.temp_dir)
|
||||
|
||||
with patch_buildozer_cmd() as m_cmd, mock.patch('buildozer.targets.android.open') as m_open:
|
||||
m_open.return_value = StringIO('install_reqs = []') # to stub setup.py parsing
|
||||
target_android._install_p4a()
|
||||
|
||||
assert mock.call(
|
||||
'git clone -b master --single-branch https://github.com/kivy/python-for-android.git python-for-android',
|
||||
cwd=mock.ANY) in m_cmd.call_args_list
|
215
tests/targets/test_ios.py
Normal file
215
tests/targets/test_ios.py
Normal file
|
@ -0,0 +1,215 @@
|
|||
import sys
|
||||
import tempfile
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from buildozer import BuildozerCommandException
|
||||
from buildozer.targets.ios import TargetIos
|
||||
from tests.targets.utils import (
|
||||
init_buildozer,
|
||||
patch_buildozer_checkbin,
|
||||
patch_buildozer_cmd,
|
||||
patch_buildozer_error,
|
||||
patch_buildozer_file_exists,
|
||||
)
|
||||
|
||||
|
||||
def patch_target_ios(method):
|
||||
return mock.patch("buildozer.targets.ios.TargetIos.{method}".format(method=method))
|
||||
|
||||
|
||||
def init_target(temp_dir, options=None):
|
||||
buildozer = init_buildozer(temp_dir, "ios", options)
|
||||
return TargetIos(buildozer)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.platform != "darwin", reason="Only macOS is supported for target iOS"
|
||||
)
|
||||
class TestTargetIos:
|
||||
def setup_method(self):
|
||||
"""
|
||||
Create a temporary directory that will contain the spec file and will
|
||||
serve as the root_dir.
|
||||
"""
|
||||
self.temp_dir = tempfile.TemporaryDirectory()
|
||||
|
||||
def tear_method(self):
|
||||
"""
|
||||
Remove the temporary directory created in self.setup_method.
|
||||
"""
|
||||
self.temp_dir.cleanup()
|
||||
|
||||
def test_init(self):
|
||||
"""Tests init defaults."""
|
||||
target = init_target(self.temp_dir)
|
||||
assert target.targetname == "ios"
|
||||
assert target.code_signing_allowed == "CODE_SIGNING_ALLOWED=NO"
|
||||
assert target.build_mode == "debug"
|
||||
assert target.platform_update is False
|
||||
|
||||
def test_check_requirements(self):
|
||||
"""Basic tests for the check_requirements() method."""
|
||||
target = init_target(self.temp_dir)
|
||||
buildozer = target.buildozer
|
||||
assert not hasattr(target, "adb_cmd")
|
||||
assert not hasattr(target, "javac_cmd")
|
||||
assert "PATH" not in buildozer.environ
|
||||
with patch_buildozer_checkbin() as m_checkbin:
|
||||
target.check_requirements()
|
||||
assert m_checkbin.call_args_list == [
|
||||
mock.call("Xcode xcodebuild", "xcodebuild"),
|
||||
mock.call("Xcode xcode-select", "xcode-select"),
|
||||
mock.call("Git git", "git"),
|
||||
mock.call("Cython cython", "cython"),
|
||||
mock.call("pkg-config", "pkg-config"),
|
||||
mock.call("autoconf", "autoconf"),
|
||||
mock.call("automake", "automake"),
|
||||
mock.call("libtool", "libtool"),
|
||||
]
|
||||
assert target._toolchain_cmd.endswith("toolchain.py ")
|
||||
assert target._xcodebuild_cmd == "xcodebuild "
|
||||
|
||||
def test_check_configuration_tokens(self):
|
||||
"""Basic tests for the check_configuration_tokens() method."""
|
||||
target = init_target(self.temp_dir, {"ios.codesign.allowed": "yes"})
|
||||
with mock.patch(
|
||||
"buildozer.targets.android.Target.check_configuration_tokens"
|
||||
) as m_check_configuration_tokens, mock.patch(
|
||||
"buildozer.targets.ios.TargetIos._get_available_identities"
|
||||
) as m_get_available_identities:
|
||||
target.check_configuration_tokens()
|
||||
assert m_get_available_identities.call_args_list == [mock.call()]
|
||||
assert m_check_configuration_tokens.call_args_list == [
|
||||
mock.call(
|
||||
[
|
||||
'[app] "ios.codesign.debug" key missing, you must give a certificate name to use.',
|
||||
'[app] "ios.codesign.release" key missing, you must give a certificate name to use.',
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
def test_get_available_packages(self):
|
||||
"""Checks the toolchain `recipes --compact` output is parsed correctly to return recipe list."""
|
||||
target = init_target(self.temp_dir)
|
||||
with patch_target_ios("toolchain") as m_toolchain:
|
||||
m_toolchain.return_value = ("hostpython3 kivy pillow python3 sdl2", None, 0)
|
||||
available_packages = target.get_available_packages()
|
||||
assert m_toolchain.call_args_list == [
|
||||
mock.call("recipes --compact", get_stdout=True)
|
||||
]
|
||||
assert available_packages == [
|
||||
"hostpython3",
|
||||
"kivy",
|
||||
"pillow",
|
||||
"python3",
|
||||
"sdl2",
|
||||
]
|
||||
|
||||
def test_install_platform(self):
|
||||
"""Checks `install_platform()` calls clone commands and sets `ios_dir` and `ios_deploy_dir` attributes."""
|
||||
target = init_target(self.temp_dir)
|
||||
assert target.ios_dir is None
|
||||
assert target.ios_deploy_dir is None
|
||||
with patch_buildozer_cmd() as m_cmd:
|
||||
target.install_platform()
|
||||
assert m_cmd.call_args_list == [
|
||||
mock.call("git clone https://github.com/kivy/kivy-ios", cwd=mock.ANY),
|
||||
mock.call(
|
||||
"git clone --branch 1.10.0 https://github.com/phonegap/ios-deploy",
|
||||
cwd=mock.ANY,
|
||||
),
|
||||
]
|
||||
assert target.ios_dir.endswith(".buildozer/ios/platform/kivy-ios")
|
||||
assert target.ios_deploy_dir.endswith(".buildozer/ios/platform/ios-deploy")
|
||||
|
||||
def test_compile_platform(self):
|
||||
"""Checks the `toolchain build` command is called on the ios requirements."""
|
||||
target = init_target(self.temp_dir)
|
||||
target.ios_deploy_dir = "/ios/deploy/dir"
|
||||
# fmt: off
|
||||
with patch_target_ios("get_available_packages") as m_get_available_packages, \
|
||||
patch_target_ios("toolchain") as m_toolchain, \
|
||||
patch_buildozer_file_exists() as m_file_exists:
|
||||
m_get_available_packages.return_value = ["hostpython3", "python3"]
|
||||
m_file_exists.return_value = True
|
||||
target.compile_platform()
|
||||
# fmt: on
|
||||
assert m_get_available_packages.call_args_list == [mock.call()]
|
||||
assert m_toolchain.call_args_list == [mock.call("build python3")]
|
||||
assert m_file_exists.call_args_list == [
|
||||
mock.call(target.ios_deploy_dir, "ios-deploy")
|
||||
]
|
||||
|
||||
def test_get_package(self):
|
||||
"""Checks default package values and checks it can be overridden."""
|
||||
# default value
|
||||
target = init_target(self.temp_dir)
|
||||
package = target._get_package()
|
||||
assert package == "org.test.myapp"
|
||||
# override
|
||||
target = init_target(
|
||||
self.temp_dir,
|
||||
{"package.domain": "com.github.kivy", "package.name": "buildozer"},
|
||||
)
|
||||
package = target._get_package()
|
||||
assert package == "com.github.kivy.buildozer"
|
||||
|
||||
def test_unlock_keychain_wrong_password(self):
|
||||
"""A `BuildozerCommandException` should be raised on wrong password 3 times."""
|
||||
target = init_target(self.temp_dir)
|
||||
# fmt: off
|
||||
with mock.patch("buildozer.targets.ios.getpass") as m_getpass, \
|
||||
patch_buildozer_cmd() as m_cmd, \
|
||||
pytest.raises(BuildozerCommandException):
|
||||
m_getpass.return_value = "password"
|
||||
# the `security unlock-keychain` command returned an error
|
||||
# hence we'll get prompted to enter the password
|
||||
m_cmd.return_value = (None, None, 123)
|
||||
target._unlock_keychain()
|
||||
# fmt: on
|
||||
assert m_getpass.call_args_list == [
|
||||
mock.call("Password to unlock the default keychain:"),
|
||||
mock.call("Password to unlock the default keychain:"),
|
||||
mock.call("Password to unlock the default keychain:"),
|
||||
]
|
||||
|
||||
def test_build_package_no_signature(self):
|
||||
"""Code signing is currently required to go through final `xcodebuild` steps."""
|
||||
target = init_target(self.temp_dir)
|
||||
target.ios_dir = "/ios/dir"
|
||||
# fmt: off
|
||||
with patch_target_ios("_unlock_keychain") as m_unlock_keychain, \
|
||||
patch_buildozer_error() as m_error, \
|
||||
mock.patch("buildozer.targets.ios.plistlib.readPlist") as m_readplist, \
|
||||
mock.patch("buildozer.targets.ios.plistlib.writePlist") as m_writeplist, \
|
||||
patch_buildozer_cmd() as m_cmd:
|
||||
m_readplist.return_value = {}
|
||||
target.build_package()
|
||||
# fmt: on
|
||||
assert m_unlock_keychain.call_args_list == [mock.call()]
|
||||
assert m_error.call_args_list == [
|
||||
mock.call(
|
||||
"Cannot create the IPA package without signature. "
|
||||
'You must fill the "ios.codesign.debug" token.'
|
||||
)
|
||||
]
|
||||
assert m_readplist.call_args_list == [
|
||||
mock.call("/ios/dir/myapp-ios/myapp-Info.plist")
|
||||
]
|
||||
assert m_writeplist.call_args_list == [
|
||||
mock.call(
|
||||
{
|
||||
"CFBundleIdentifier": "org.test.myapp",
|
||||
"CFBundleShortVersionString": "0.1",
|
||||
"CFBundleVersion": "0.1.None",
|
||||
},
|
||||
"/ios/dir/myapp-ios/myapp-Info.plist",
|
||||
)
|
||||
]
|
||||
assert m_cmd.call_args_list == [mock.call(mock.ANY, cwd=target.ios_dir), mock.call(
|
||||
"xcodebuild -configuration Debug -allowProvisioningUpdates ENABLE_BITCODE=NO "
|
||||
"CODE_SIGNING_ALLOWED=NO clean build",
|
||||
cwd="/ios/dir/myapp-ios",
|
||||
)]
|
66
tests/targets/utils.py
Normal file
66
tests/targets/utils.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
import os
|
||||
import re
|
||||
from unittest import mock
|
||||
|
||||
import buildozer as buildozer_module
|
||||
from buildozer import Buildozer
|
||||
|
||||
|
||||
def patch_buildozer(method):
|
||||
return mock.patch("buildozer.Buildozer.{method}".format(method=method))
|
||||
|
||||
|
||||
def patch_buildozer_cmd():
|
||||
return patch_buildozer("cmd")
|
||||
|
||||
|
||||
def patch_buildozer_checkbin():
|
||||
return patch_buildozer("checkbin")
|
||||
|
||||
|
||||
def patch_buildozer_file_exists():
|
||||
return patch_buildozer("file_exists")
|
||||
|
||||
|
||||
def patch_buildozer_error():
|
||||
return patch_buildozer("error")
|
||||
|
||||
|
||||
def default_specfile_path():
|
||||
return os.path.join(os.path.dirname(buildozer_module.__file__), "default.spec")
|
||||
|
||||
|
||||
def init_buildozer(temp_dir, target, options=None):
|
||||
"""
|
||||
Create a buildozer.spec file in the temporary directory and init the
|
||||
Buildozer instance.
|
||||
|
||||
The optional argument can be used to overwrite the config options in
|
||||
the buildozer.spec file, e.g.:
|
||||
|
||||
init_buildozer({'title': 'Test App'})
|
||||
|
||||
will replace line 4 of the default spec file.
|
||||
"""
|
||||
if options is None:
|
||||
options = {}
|
||||
|
||||
spec_path = os.path.join(temp_dir.name, "buildozer.spec")
|
||||
|
||||
with open(default_specfile_path()) as f:
|
||||
default_spec = f.readlines()
|
||||
|
||||
spec = []
|
||||
for line in default_spec:
|
||||
if line.strip():
|
||||
match = re.search(r"[#\s]?([0-9a-z_.]+)", line)
|
||||
key = match and match.group(1)
|
||||
if key in options:
|
||||
line = "{} = {}\n".format(key, options[key])
|
||||
|
||||
spec.append(line)
|
||||
|
||||
with open(spec_path, "w") as f:
|
||||
f.writelines(spec)
|
||||
|
||||
return Buildozer(filename=spec_path, target=target)
|
243
tests/test_buildozer.py
Normal file
243
tests/test_buildozer.py
Normal file
|
@ -0,0 +1,243 @@
|
|||
import re
|
||||
import os
|
||||
import codecs
|
||||
import unittest
|
||||
import buildozer as buildozer_module
|
||||
from buildozer import Buildozer
|
||||
from six import StringIO
|
||||
import tempfile
|
||||
from unittest import mock
|
||||
|
||||
from buildozer.targets.android import (
|
||||
TargetAndroid, DEFAULT_ANDROID_NDK_VERSION, MSG_P4A_RECOMMENDED_NDK_ERROR
|
||||
)
|
||||
|
||||
|
||||
class TestBuildozer(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Creates a temporary spec file containing the content of the default.spec.
|
||||
"""
|
||||
self.specfile = tempfile.NamedTemporaryFile(suffix='.spec', delete=False)
|
||||
self.specfilename = self.specfile.name
|
||||
default_spec = codecs.open(self.default_specfile_path(), encoding='utf-8')
|
||||
self.specfile.write(default_spec.read().encode('utf-8'))
|
||||
self.specfile.close()
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Deletes the temporary spec file.
|
||||
"""
|
||||
os.unlink(self.specfile.name)
|
||||
|
||||
@staticmethod
|
||||
def default_specfile_path():
|
||||
return os.path.join(
|
||||
os.path.dirname(buildozer_module.__file__),
|
||||
'default.spec')
|
||||
|
||||
@staticmethod
|
||||
def file_re_sub(filepath, pattern, replace):
|
||||
"""
|
||||
Helper method for inplace file regex editing.
|
||||
"""
|
||||
with open(filepath) as f:
|
||||
file_content = f.read()
|
||||
file_content = re.sub(pattern, replace, file_content)
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(file_content)
|
||||
|
||||
@classmethod
|
||||
def set_specfile_log_level(cls, specfilename, log_level):
|
||||
"""
|
||||
Helper method for setting `log_level` in a given `specfilename`.
|
||||
"""
|
||||
pattern = 'log_level = [0-9]'
|
||||
replace = 'log_level = {}'.format(log_level)
|
||||
cls.file_re_sub(specfilename, pattern, replace)
|
||||
buildozer = Buildozer(specfilename)
|
||||
assert buildozer.log_level == log_level
|
||||
|
||||
def test_buildozer_base(self):
|
||||
"""
|
||||
Basic test making sure the Buildozer object can be instantiated.
|
||||
"""
|
||||
buildozer = Buildozer()
|
||||
assert buildozer.specfilename == 'buildozer.spec'
|
||||
# spec file doesn't have to exist
|
||||
assert os.path.exists(buildozer.specfilename) is False
|
||||
|
||||
def test_buildozer_read_spec(self):
|
||||
"""
|
||||
Initializes Buildozer object from existing spec file.
|
||||
"""
|
||||
buildozer = Buildozer(filename=self.default_specfile_path())
|
||||
assert os.path.exists(buildozer.specfilename) is True
|
||||
|
||||
def test_buildozer_help(self):
|
||||
"""
|
||||
Makes sure the help gets display with no error, refs:
|
||||
https://github.com/kivy/buildozer/issues/813
|
||||
"""
|
||||
buildozer = Buildozer()
|
||||
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
buildozer.usage()
|
||||
assert 'Usage:' in mock_stdout.getvalue()
|
||||
|
||||
def test_log_get_set(self):
|
||||
"""
|
||||
Tests reading and setting log level from spec file.
|
||||
"""
|
||||
# the default log level value is known
|
||||
buildozer = Buildozer('does_not_exist.spec')
|
||||
assert buildozer.log_level == 2
|
||||
# sets log level to 1 on the spec file
|
||||
self.set_specfile_log_level(self.specfile.name, 1)
|
||||
buildozer = Buildozer(self.specfile.name)
|
||||
assert buildozer.log_level == 1
|
||||
|
||||
def test_log_print(self):
|
||||
"""
|
||||
Checks logger prints different info depending on log level.
|
||||
"""
|
||||
# sets log level to 1 in the spec file
|
||||
self.set_specfile_log_level(self.specfile.name, 1)
|
||||
buildozer = Buildozer(self.specfile.name)
|
||||
assert buildozer.log_level == 1
|
||||
# at this level, debug messages shouldn't not be printed
|
||||
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
buildozer.debug('debug message')
|
||||
buildozer.info('info message')
|
||||
buildozer.error('error message')
|
||||
# using `in` keyword rather than `==` because of bash color prefix/suffix
|
||||
assert 'debug message' not in mock_stdout.getvalue()
|
||||
assert 'info message' in mock_stdout.getvalue()
|
||||
assert 'error message' in mock_stdout.getvalue()
|
||||
# sets log level to 2 in the spec file
|
||||
self.set_specfile_log_level(self.specfile.name, 2)
|
||||
buildozer = Buildozer(self.specfile.name)
|
||||
assert buildozer.log_level == 2
|
||||
# at this level all message types should be printed
|
||||
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
buildozer.debug('debug message')
|
||||
buildozer.info('info message')
|
||||
buildozer.error('error message')
|
||||
assert 'debug message' in mock_stdout.getvalue()
|
||||
assert 'info message' in mock_stdout.getvalue()
|
||||
assert 'error message' in mock_stdout.getvalue()
|
||||
|
||||
def test_run_command_unknown(self):
|
||||
"""
|
||||
Makes sure the unknown command/target is handled gracefully, refs:
|
||||
https://github.com/kivy/buildozer/issues/812
|
||||
"""
|
||||
buildozer = Buildozer()
|
||||
command = 'foobar'
|
||||
args = [command, 'debug']
|
||||
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with self.assertRaises(SystemExit):
|
||||
buildozer.run_command(args)
|
||||
assert mock_stdout.getvalue() == 'Unknown command/target {}\n'.format(command)
|
||||
|
||||
def test_android_ant_path(self):
|
||||
"""
|
||||
Verify that the selected ANT path is being used from the spec file
|
||||
"""
|
||||
my_ant_path = '/my/ant/path'
|
||||
|
||||
buildozer = Buildozer(filename=self.default_specfile_path(), target='android')
|
||||
buildozer.config.set('app', 'android.ant_path', my_ant_path) # Set ANT path
|
||||
target = TargetAndroid(buildozer=buildozer)
|
||||
|
||||
# Mock first run
|
||||
with mock.patch('buildozer.Buildozer.download') as download, \
|
||||
mock.patch('buildozer.Buildozer.file_extract') as m_file_extract, \
|
||||
mock.patch('os.makedirs'):
|
||||
ant_path = target._install_apache_ant()
|
||||
assert m_file_extract.call_args_list == [mock.call(mock.ANY, cwd='/my/ant/path')]
|
||||
assert ant_path == my_ant_path
|
||||
assert download.call_args_list == [
|
||||
mock.call("https://archive.apache.org/dist/ant/binaries/", mock.ANY, cwd=my_ant_path)]
|
||||
# Mock ant already installed
|
||||
with mock.patch.object(Buildozer, 'file_exists', return_value=True):
|
||||
ant_path = target._install_apache_ant()
|
||||
assert ant_path == my_ant_path
|
||||
|
||||
def test_cmd_unicode_decode(self):
|
||||
"""
|
||||
Verifies Buildozer.cmd() can properly handle non-unicode outputs.
|
||||
refs: https://github.com/kivy/buildozer/issues/857
|
||||
"""
|
||||
buildozer = Buildozer()
|
||||
command = 'uname'
|
||||
kwargs = {
|
||||
'show_output': True,
|
||||
'get_stdout': True,
|
||||
'get_stderr': True,
|
||||
}
|
||||
command_output = b'\x80 cannot decode \x80'
|
||||
# showing the point that we can't decode it
|
||||
with self.assertRaises(UnicodeDecodeError):
|
||||
command_output.decode('utf-8')
|
||||
with mock.patch('buildozer.Popen') as m_popen, \
|
||||
mock.patch('buildozer.select') as m_select, \
|
||||
mock.patch('buildozer.stdout') as m_stdout:
|
||||
m_select.select().__getitem__.return_value = [0]
|
||||
# makes sure fcntl.fcntl() gets what it expects so it doesn't crash
|
||||
m_popen().stdout.fileno.return_value = 0
|
||||
m_popen().stderr.fileno.return_value = 2
|
||||
# Buildozer.cmd() is iterating through command output "chunk" until
|
||||
# one chunk is None
|
||||
m_popen().stdout.read.side_effect = [command_output, None]
|
||||
m_popen().returncode = 0
|
||||
stdout, stderr, returncode = buildozer.cmd(command, **kwargs)
|
||||
# when get_stdout is True, the command output also gets returned
|
||||
assert stdout == command_output.decode('utf-8', 'ignore')
|
||||
assert stderr is None
|
||||
assert returncode == 0
|
||||
# Python2 and Python3 have different approaches for decoding the output
|
||||
assert m_stdout.write.call_args_list == [
|
||||
mock.call(command_output.decode('utf-8', 'replace'))
|
||||
]
|
||||
|
||||
def test_p4a_recommended_ndk_version_default_value(self):
|
||||
self.set_specfile_log_level(self.specfile.name, 1)
|
||||
buildozer = Buildozer(self.specfile.name, 'android')
|
||||
assert buildozer.target.p4a_recommended_ndk_version is None
|
||||
|
||||
def test_p4a_recommended_android_ndk_error(self):
|
||||
self.set_specfile_log_level(self.specfile.name, 1)
|
||||
buildozer = Buildozer(self.specfile.name, 'android')
|
||||
|
||||
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
ndk_version = buildozer.target.p4a_recommended_android_ndk
|
||||
assert MSG_P4A_RECOMMENDED_NDK_ERROR in mock_stdout.getvalue()
|
||||
# and we should get the default android's ndk version of buildozer
|
||||
assert ndk_version == DEFAULT_ANDROID_NDK_VERSION
|
||||
|
||||
@mock.patch('buildozer.targets.android.os.path.isfile')
|
||||
@mock.patch('buildozer.targets.android.os.path.exists')
|
||||
@mock.patch('buildozer.targets.android.open', create=True)
|
||||
def test_p4a_recommended_android_ndk_found(
|
||||
self, mock_open, mock_exists, mock_isfile
|
||||
):
|
||||
self.set_specfile_log_level(self.specfile.name, 1)
|
||||
buildozer = Buildozer(self.specfile.name, 'android')
|
||||
expected_ndk = '19b'
|
||||
recommended_line = 'RECOMMENDED_NDK_VERSION = {expected_ndk}\n'.format(
|
||||
expected_ndk=expected_ndk)
|
||||
mock_open.return_value = StringIO(recommended_line)
|
||||
ndk_version = buildozer.target.p4a_recommended_android_ndk
|
||||
p4a_dir = os.path.join(
|
||||
buildozer.platform_dir, buildozer.target.p4a_directory_name)
|
||||
mock_open.assert_called_once_with(
|
||||
os.path.join(p4a_dir, "pythonforandroid", "recommendations.py"), 'r'
|
||||
)
|
||||
assert ndk_version == expected_ndk
|
||||
|
||||
# now test that we only read one time p4a file, so we call again to
|
||||
# `p4a_recommended_android_ndk` and we should still have one call to `open`
|
||||
# file, the performed above
|
||||
ndk_version = buildozer.target.p4a_recommended_android_ndk
|
||||
mock_open.assert_called_once()
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/env python2.7
|
||||
|
||||
if __name__ == '__main__':
|
||||
from buildozer import run
|
||||
run()
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/env python2.7
|
||||
|
||||
if __name__ == '__main__':
|
||||
from buildozer import run_remote
|
||||
run_remote()
|
32
tox.ini
Normal file
32
tox.ini
Normal file
|
@ -0,0 +1,32 @@
|
|||
[tox]
|
||||
envlist = pep8,py3
|
||||
|
||||
[testenv]
|
||||
deps =
|
||||
pytest
|
||||
py3: coverage
|
||||
commands = pytest tests/
|
||||
|
||||
[testenv:py3]
|
||||
# for py3 env we will get code coverage
|
||||
commands =
|
||||
coverage run --branch --source=buildozer -m pytest {posargs:tests/}
|
||||
coverage report -m
|
||||
|
||||
[testenv:pep8]
|
||||
deps = flake8
|
||||
commands = flake8 buildozer/ tests/
|
||||
|
||||
[flake8]
|
||||
ignore =
|
||||
E121, # continuation line under-indented for hanging indent
|
||||
E122, # continuation line missing indentation or outdented
|
||||
E126, # continuation line over-indented for hanging indent
|
||||
E127, # continuation line over-indented for visual indent
|
||||
E128, # continuation line under-indented for visual indent
|
||||
E131, # continuation line unaligned for hanging indent
|
||||
E402, # module level import not at top of file
|
||||
E501, # line too long
|
||||
E722, # do not use bare 'except'
|
||||
W503, # line break before binary operator
|
||||
W504 # line break after binary operator
|
Loading…
Reference in a new issue