Compare commits
949 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a68fd4394 | ||
|
|
54996900b5 | ||
|
|
bb08abc0b9 | ||
|
|
1dfbebf98e | ||
|
|
2e0f40ff51 | ||
|
|
bdecdea568 | ||
|
|
a88b8de820 | ||
|
|
bb6f75c0a8 | ||
|
|
57e92e8a56 | ||
|
|
93b9b53acb | ||
|
|
edb35b5a6d | ||
|
|
bb7bc33a8a | ||
|
|
64c617d8ab | ||
|
|
bcccb0c620 | ||
|
|
e1de55cc82 | ||
|
|
4b501a5b63 | ||
|
|
dc494c85f2 | ||
|
|
624a8d370c | ||
|
|
5814d666ab | ||
|
|
53e3a12441 | ||
|
|
dd770ef303 | ||
|
|
8b3fa5c91e | ||
|
|
43bf47ea7b | ||
|
|
4be84fbf12 | ||
|
|
e9b46e5cf6 | ||
|
|
6a57a3c452 | ||
|
|
cdb49eaa1f | ||
|
|
cb11486f66 | ||
|
|
0e9b446a81 | ||
|
|
2cf79a1adb | ||
|
|
5550ec8f2c | ||
|
|
70f3785b47 | ||
|
|
8c4c22c72a | ||
|
|
cd4a316a91 | ||
|
|
654d489c01 | ||
|
|
f3acf9002e | ||
|
|
e03bd0a40d | ||
|
|
1167da2027 | ||
|
|
7cde444ffe | ||
|
|
67e97a89ce | ||
|
|
892ffc8ce4 | ||
|
|
c5e83b1079 | ||
|
|
fbf7f1c3f9 | ||
|
|
68bc57ae85 | ||
|
|
10d31ea0a3 | ||
|
|
df1536ea77 | ||
|
|
6aff54be76 | ||
|
|
e64ebdfaee | ||
|
|
7e15ff930d | ||
|
|
b83610a653 | ||
|
|
9cb14838e8 | ||
|
|
24a0e8956c | ||
|
|
6fe66ad79c | ||
|
|
9946d15f23 | ||
|
|
b032dcca16 | ||
|
|
01d6ae55a4 | ||
|
|
f1b377bf07 | ||
|
|
03c5208d47 | ||
|
|
3ace9348f6 | ||
|
|
e01678da93 | ||
|
|
3a14017729 | ||
|
|
98b971b4de | ||
|
|
2b6a683198 | ||
|
|
1f58d8ee27 | ||
|
|
4ec3d6d064 | ||
|
|
fb4527d91b | ||
|
|
8c9e416175 | ||
|
|
a83bbcaf1d | ||
|
|
431f3337d9 | ||
|
|
c9b164b983 | ||
|
|
54d32ad910 | ||
|
|
0efd9fcac0 | ||
|
|
c0a39570c9 | ||
|
|
9ac4b570e6 | ||
|
|
6689827278 | ||
|
|
86a24ebd0f | ||
|
|
d2a7d18067 | ||
|
|
b679672c0e | ||
|
|
90f83db9c9 | ||
|
|
32d74f8623 | ||
|
|
53cc381c76 | ||
|
|
add107583f | ||
|
|
e86d811fc0 | ||
|
|
5cff144a22 | ||
|
|
a021adb7fd | ||
|
|
e2a090bbba | ||
|
|
a70c8536f9 | ||
|
|
e52d4fc003 | ||
|
|
3753e3f353 | ||
|
|
979d8e66f2 | ||
|
|
c5b37cc7e7 | ||
|
|
e3989bcc2b | ||
|
|
2f9c512b59 | ||
|
|
43172cf530 | ||
|
|
e518eacbde | ||
|
|
c3b8b279b0 | ||
|
|
0dd4951be7 | ||
|
|
12d06bd727 | ||
|
|
bc52345f05 | ||
|
|
c28a313374 | ||
|
|
c509c8e7e5 | ||
|
|
fb89cef256 | ||
|
|
9ac9fd4fe9 | ||
|
|
dfb89df4f1 | ||
|
|
0e572aea36 | ||
|
|
420cee4ee6 | ||
|
|
403297d967 | ||
|
|
abba254a38 | ||
|
|
048107e378 | ||
|
|
78efe2a960 | ||
|
|
8077091b34 | ||
|
|
683e32cffb | ||
|
|
1c9d76e637 | ||
|
|
ee58107caa | ||
|
|
01946dd4d6 | ||
|
|
c9e16b2c39 | ||
|
|
77eada7dbd | ||
|
|
f38a2ae14a | ||
|
|
227733d195 | ||
|
|
13148728b3 | ||
|
|
8f91ebf194 | ||
|
|
230c635a54 | ||
|
|
e1f930282c | ||
|
|
cb07fe395c | ||
|
|
3917284f71 | ||
|
|
8bfd45c095 | ||
|
|
a001d8cfb7 | ||
|
|
867358ea81 | ||
|
|
62c3e46529 | ||
|
|
8a95ed8ee6 | ||
|
|
20caac1b6e | ||
|
|
48b8c69ba0 | ||
|
|
35d53a0684 | ||
|
|
dbeb252fee | ||
|
|
21614ea891 | ||
|
|
4b38ccef80 | ||
|
|
2d4d18fd75 | ||
|
|
27cd9dde38 | ||
|
|
373da39ac2 | ||
|
|
b7990b7df8 | ||
|
|
4b9047b7d8 | ||
|
|
d226818be3 | ||
|
|
1ee9da79f8 | ||
|
|
070eb6b947 | ||
|
|
cbb0bd5ee7 | ||
|
|
553a25cea7 | ||
|
|
53982272d6 | ||
|
|
a32cf2344f | ||
|
|
934cf32163 | ||
|
|
a17c7b9bbf | ||
|
|
a03df3fad0 | ||
|
|
86cd20dcc3 | ||
|
|
71402b658e | ||
|
|
5d8d8e77f8 | ||
|
|
4dee30ed84 | ||
|
|
025676d6e7 | ||
|
|
aad396ae38 | ||
|
|
c798d131bb | ||
|
|
bf3e024648 | ||
|
|
191f31baa7 | ||
|
|
d3b7903af8 | ||
|
|
99e7d1e161 | ||
|
|
b13166f5d9 | ||
|
|
80fe4458c6 | ||
|
|
791574c26e | ||
|
|
ac61ebf2d5 | ||
|
|
4599e9897d | ||
|
|
cb99ed0a01 | ||
|
|
4864d52966 | ||
|
|
b2d61679fb | ||
|
|
383b3dadd5 | ||
|
|
c65c259123 | ||
|
|
e7e2730929 | ||
|
|
bb9615eed0 | ||
|
|
18877bf80e | ||
|
|
778b784eb6 | ||
|
|
5ff900f7ec | ||
|
|
ba31424604 | ||
|
|
1782111d45 | ||
|
|
1fa63300aa | ||
|
|
b42c918973 | ||
|
|
f12262ea96 | ||
|
|
334cf45d6d | ||
|
|
b7bb72294a | ||
|
|
64ff204371 | ||
|
|
282367c6d5 | ||
|
|
36c33a5889 | ||
|
|
5ee7e81ff9 | ||
|
|
f4859444dd | ||
|
|
73c7994cd1 | ||
|
|
0c74090953 | ||
|
|
f60d54eae4 | ||
|
|
31bc015cdd | ||
|
|
b028ad3604 | ||
|
|
d2e4e35c37 | ||
|
|
1f37200bb6 | ||
|
|
77178daad3 | ||
|
|
1648f161d9 | ||
|
|
9fa6cea69b | ||
|
|
66b827e502 | ||
|
|
7755a902dd | ||
|
|
d25b73f47d | ||
|
|
ac2969c3f8 | ||
|
|
ee38b2ef03 | ||
|
|
0f70e04e6e | ||
|
|
9fc1e7272e | ||
|
|
0d4d0b8a37 | ||
|
|
fcd2c989a2 | ||
|
|
e0d0d6c455 | ||
|
|
ce1a961b99 | ||
|
|
c71a08a9d9 | ||
|
|
17bfcea65a | ||
|
|
5e8959bab1 | ||
|
|
9924dc0f92 | ||
|
|
7388c036d7 | ||
|
|
ad4512801f | ||
|
|
409b9af398 | ||
|
|
7cc8fd7e87 | ||
|
|
42c8105f13 | ||
|
|
9a71cc5b4e | ||
|
|
c543b7469d | ||
|
|
7caac3265a | ||
|
|
5d68d5a246 | ||
|
|
7187f87eae | ||
|
|
fb81f3e77e | ||
|
|
0ae49ed098 | ||
|
|
b8e5aaf754 | ||
|
|
aa4820c3b7 | ||
|
|
5d79d6e134 | ||
|
|
fb1455a17b | ||
|
|
c668eeba0f | ||
|
|
62421ee49d | ||
|
|
e791f29ce1 | ||
|
|
06947cc453 | ||
|
|
8c97474524 | ||
|
|
77a8568b28 | ||
|
|
e2dadbd7fe | ||
|
|
17b668a115 | ||
|
|
a30c2b6a75 | ||
|
|
2660eebec2 | ||
|
|
f415664b6d | ||
|
|
5092b29312 | ||
|
|
d5be901bc2 | ||
|
|
5462eddfdb | ||
|
|
fef51f12c6 | ||
|
|
fdb3679cf5 | ||
|
|
11beb37c50 | ||
|
|
5cd17730b1 | ||
|
|
cb192056f8 | ||
|
|
892f96e305 | ||
|
|
13ef58a5bb | ||
|
|
2bf6509e1d | ||
|
|
a45d5a98dd | ||
|
|
a31714f8a4 | ||
|
|
23d2a806f0 | ||
|
|
c20b2330ab | ||
|
|
8613551aec | ||
|
|
2ab01dadc0 | ||
|
|
790636c8cd | ||
|
|
23938830f7 | ||
|
|
674b87057a | ||
|
|
83d9248ec8 | ||
|
|
f9d27e4a67 | ||
|
|
2683803ef3 | ||
|
|
dd86d7a5ed | ||
|
|
1246a81d39 | ||
|
|
8ab7278db2 | ||
|
|
db099e7722 | ||
|
|
fcc01bc37e | ||
|
|
a18dacf5f2 | ||
|
|
77f9cae50b | ||
|
|
3610bbf21b | ||
|
|
d5e3be9a55 | ||
|
|
80b369d6d5 | ||
|
|
d29eb84010 | ||
|
|
381ce535bf | ||
|
|
2e20bb0639 | ||
|
|
56cd24797e | ||
|
|
431ca99c23 | ||
|
|
6ced2ff293 | ||
|
|
31055bb303 | ||
|
|
24a53e39dd | ||
|
|
2ab113b695 | ||
|
|
9a0481a750 | ||
|
|
09035eb4c4 | ||
|
|
1adf268e71 | ||
|
|
23f57ad5a7 | ||
|
|
d9b15cf69e | ||
|
|
dbfe12a993 | ||
|
|
2b32dfd99d | ||
|
|
679de40780 | ||
|
|
66f15fdd37 | ||
|
|
038f0e45b1 | ||
|
|
033bfcc804 | ||
|
|
fa87c08a29 | ||
|
|
dfb799739a | ||
|
|
1193f7ed22 | ||
|
|
7530c21a9f | ||
|
|
a120614617 | ||
|
|
0311f0db38 | ||
|
|
547b683e61 | ||
|
|
ff1d943a69 | ||
|
|
15a5c89e86 | ||
|
|
03b974ee3f | ||
|
|
f145605c63 | ||
|
|
29230d0316 | ||
|
|
57fc49ddc2 | ||
|
|
5ac6853fed | ||
|
|
b870214cca | ||
|
|
55074b925f | ||
|
|
958424ce59 | ||
|
|
d04fc289ac | ||
|
|
e14edf134d | ||
|
|
dbb127447f | ||
|
|
dc94fc39ec | ||
|
|
6db9a7cb12 | ||
|
|
1f39386616 | ||
|
|
25aef945d1 | ||
|
|
c9aa43afe0 | ||
|
|
913e177f6f | ||
|
|
ae431aec12 | ||
|
|
8ac15048cd | ||
|
|
a1cfe87f1e | ||
|
|
c130396d4e | ||
|
|
bc2e7cf317 | ||
|
|
7ace1d652d | ||
|
|
26effd1def | ||
|
|
5f6824e5dd | ||
|
|
4589bdd31f | ||
|
|
72e0b49e0b | ||
|
|
3caa45d860 | ||
|
|
7c069f14f8 | ||
|
|
552885dbd3 | ||
|
|
6efeb1471c | ||
|
|
01f062d2ba | ||
|
|
2a42c463d2 | ||
|
|
182843edf6 | ||
|
|
9a9d36e9d9 | ||
|
|
7d5249eea6 | ||
|
|
f7910c41c3 | ||
|
|
3973f4f952 | ||
|
|
8a19769a47 | ||
|
|
c0ee593c10 | ||
|
|
c806451b8a | ||
|
|
00e5ff1964 | ||
|
|
432aec62a9 | ||
|
|
c8ec7e5191 | ||
|
|
a0d2b96de6 | ||
|
|
2c202b82d7 | ||
|
|
a42dc08756 | ||
|
|
48f58110fe | ||
|
|
7b3724972b | ||
|
|
9ca2a16218 | ||
|
|
f1e8400abf | ||
|
|
11e0ffa90a | ||
|
|
2ee4326a4d | ||
|
|
226e72ac18 | ||
|
|
65c78b8f3f | ||
|
|
6137c7ca06 | ||
|
|
5bebf11b37 | ||
|
|
68161d2714 | ||
|
|
a6473cb826 | ||
|
|
0084c6f96a | ||
|
|
a87825dbee | ||
|
|
3566154cd0 | ||
|
|
92d69e320f | ||
|
|
08a190ef5b | ||
|
|
98339ee5d8 | ||
|
|
fa387fd758 | ||
|
|
54979f2fc4 | ||
|
|
538e90f23a | ||
|
|
d9107bcac6 | ||
|
|
3f3a0b9140 | ||
|
|
e1347e434e | ||
|
|
7657faa9c3 | ||
|
|
28ef765913 | ||
|
|
d2f59391a2 | ||
|
|
df90bdb350 | ||
|
|
c416c77d7a | ||
|
|
ce05a720d1 | ||
|
|
6c19a440f5 | ||
|
|
f4612fdb5d | ||
|
|
04b9a0b09e | ||
|
|
f93c438067 | ||
|
|
e1d608443a | ||
|
|
9233c3a898 | ||
|
|
dfa514334b | ||
|
|
5810a96e62 | ||
|
|
70473a80af | ||
|
|
525fd30cb2 | ||
|
|
5212cd4dcd | ||
|
|
e95bde62a2 | ||
|
|
4fe73cf6ad | ||
|
|
78b2835da4 | ||
|
|
f9a49efae9 | ||
|
|
b9ddc9e678 | ||
|
|
dc459c84a3 | ||
|
|
1d26239809 | ||
|
|
5ca233779d | ||
|
|
e51b4897a3 | ||
|
|
81f283e56f | ||
|
|
ccdd2fd2ca | ||
|
|
69f11a29e1 | ||
|
|
cf494f3238 | ||
|
|
d5895c635a | ||
|
|
2ac9873613 | ||
|
|
eb59e76cde | ||
|
|
d9db845b43 | ||
|
|
e55327b064 | ||
|
|
bdd5a4e053 | ||
|
|
ac2e2c9a42 | ||
|
|
76f9d49e24 | ||
|
|
6ec8ab95fc | ||
|
|
9c98625610 | ||
|
|
f270cde47d | ||
|
|
9de7efd072 | ||
|
|
7b81d317a0 | ||
|
|
876f975aa2 | ||
|
|
3c5815ac0f | ||
|
|
678ae2d684 | ||
|
|
e4f8f44fb0 | ||
|
|
49566d29f8 | ||
|
|
7f4ee7b20a | ||
|
|
32526a8c16 | ||
|
|
71a7f72ab9 | ||
|
|
4d0824f4a4 | ||
|
|
d56dd40d06 | ||
|
|
6aafd6dc3a | ||
|
|
011b512f28 | ||
|
|
aa2d17e489 | ||
|
|
0eee2293dc | ||
|
|
a2f35d2bda | ||
|
|
58f58d9ee8 | ||
|
|
412bb349ac | ||
|
|
652f15f893 | ||
|
|
8512ebb923 | ||
|
|
f0ac173ec8 | ||
|
|
bef0d47924 | ||
|
|
cba0d59021 | ||
|
|
7d3afcab94 | ||
|
|
5f1cda07e7 | ||
|
|
e11beade4b | ||
|
|
6a1e089b73 | ||
|
|
0aa98ac2da | ||
|
|
f9ef38cc7a | ||
|
|
a3a215a1ba | ||
|
|
d3ee322d7c | ||
|
|
7ec20e7752 | ||
|
|
08dfb13dbf | ||
|
|
6a5cddd907 | ||
|
|
dc5078306d | ||
|
|
1bc032853c | ||
|
|
e562e4e7b9 | ||
|
|
0ffffa9029 | ||
|
|
0f2303e8d5 | ||
|
|
31f7f8149e | ||
|
|
fe1f57c23f | ||
|
|
29a0b010da | ||
|
|
621e1163f8 | ||
|
|
17d64cfcbe | ||
|
|
7379d2135d | ||
|
|
c55fd06b99 | ||
|
|
d81727a08c | ||
|
|
b582e1592a | ||
|
|
dd8533a320 | ||
|
|
d72a8cbf89 | ||
|
|
fe0876ded6 | ||
|
|
fa15763c5d | ||
|
|
205215d409 | ||
|
|
076bfcde87 | ||
|
|
10510484b5 | ||
|
|
e1dea5b4d3 | ||
|
|
891f8d00cf | ||
|
|
0d409f0fe3 | ||
|
|
4e0c8982c9 | ||
|
|
a741c66c97 | ||
|
|
3e6a7cbdf5 | ||
|
|
5d34aa0afe | ||
|
|
979ae94698 | ||
|
|
8d7b85b26a | ||
|
|
686977a986 | ||
|
|
9c6c782146 | ||
|
|
ca9539b5b6 | ||
|
|
ff25be8839 | ||
|
|
d1ab1b59be | ||
|
|
05bc1865a6 | ||
|
|
6e6e0275ad | ||
|
|
ec3c5b2ca2 | ||
|
|
5289d569b0 | ||
|
|
6f873ff6b5 | ||
|
|
467cbe972c | ||
|
|
bfd1bfe9f0 | ||
|
|
3404a6c699 | ||
|
|
17a4b5155e | ||
|
|
d406e2ed22 | ||
|
|
0bfc9935b2 | ||
|
|
64c6cbe303 | ||
|
|
2245db3e80 | ||
|
|
6f19a50c98 | ||
|
|
c7ce9598a8 | ||
|
|
afcdccf783 | ||
|
|
1bf12842ca | ||
|
|
da8fbee256 | ||
|
|
4021f26e76 | ||
|
|
8eab8438cf | ||
|
|
1b4096b01d | ||
|
|
54caa6e438 | ||
|
|
486eb149f2 | ||
|
|
faa034a205 | ||
|
|
2cd3ebc7a8 | ||
|
|
7e3af6c235 | ||
|
|
dd4de16d1d | ||
|
|
ba8577fa5f | ||
|
|
6192319f8c | ||
|
|
fed368d553 | ||
|
|
20c885418e | ||
|
|
9318ee30bd | ||
|
|
8b6c9574df | ||
|
|
313148136a | ||
|
|
6e1fdc77ae | ||
|
|
2a9582ebb1 | ||
|
|
dd1cd46719 | ||
|
|
9961d9e54d | ||
|
|
7eb12110d1 | ||
|
|
3d62744601 | ||
|
|
17af417235 | ||
|
|
df9d314361 | ||
|
|
610e0c984a | ||
|
|
3688fca126 | ||
|
|
9bc89c784f | ||
|
|
79682f5d52 | ||
|
|
c206ac0335 | ||
|
|
34840175f3 | ||
|
|
6312457425 | ||
|
|
f71e664952 | ||
|
|
80d559f17e | ||
|
|
772aedc263 | ||
|
|
45d7c124c8 | ||
|
|
73abb20b3d | ||
|
|
0baf104a75 | ||
|
|
302d51cdfd | ||
|
|
d3cbfd5467 | ||
|
|
9e3e7e1820 | ||
|
|
18893bf6cd | ||
|
|
f53161d6f5 | ||
|
|
4c9a571106 | ||
|
|
365edcad16 | ||
|
|
ae9047a708 | ||
|
|
9c0e58df8d | ||
|
|
ee34f11c29 | ||
|
|
6ca6d88bff | ||
|
|
65a397fb63 | ||
|
|
0a669077fb | ||
|
|
451688a12e | ||
|
|
d181d89dd2 | ||
|
|
ac14b0d73b | ||
|
|
0f42c65792 | ||
|
|
37b3e980dc | ||
|
|
eb49e011e2 | ||
|
|
e0a73f72ee | ||
|
|
e217ab28c5 | ||
|
|
ca583865ea | ||
|
|
5e7efde311 | ||
|
|
2c7c13420b | ||
|
|
ac4fc3e54e | ||
|
|
46db36a05e | ||
|
|
3d073be990 | ||
|
|
1bc49fe450 | ||
|
|
1f7fe9abcc | ||
|
|
5217abf57a | ||
|
|
2ecbde891a | ||
|
|
bf7fc66646 | ||
|
|
5a94b38e2f | ||
|
|
1bc55f5937 | ||
|
|
04c9542f94 | ||
|
|
17e739f68a | ||
|
|
4f5515fde3 | ||
|
|
ae3ba129ea | ||
|
|
6b92a0fff7 | ||
|
|
d859bb8e67 | ||
|
|
f12bbf71ed | ||
|
|
b723beb545 | ||
|
|
47daaaf14f | ||
|
|
9ba5bae34d | ||
|
|
dbfa2d7994 | ||
|
|
8134f86d1f | ||
|
|
5c60b09bf4 | ||
|
|
20a19d67d0 | ||
|
|
311a2f6023 | ||
|
|
59a3cf93e6 | ||
|
|
a42f095cef | ||
|
|
a29340523f | ||
|
|
5ad7a7c014 | ||
|
|
c6fa7e4aad | ||
|
|
d4b248fbe3 | ||
|
|
48881d081a | ||
|
|
331024414e | ||
|
|
9d0c5349bb | ||
|
|
dc40d8afac | ||
|
|
005877b4b8 | ||
|
|
774d21747a | ||
|
|
12e5b39c05 | ||
|
|
4d5e452ece | ||
|
|
1ba3ecbef3 | ||
|
|
db6695cb02 | ||
|
|
b3f5e039f2 | ||
|
|
c3e17fb185 | ||
|
|
f7ae7fe43a | ||
|
|
e07822350e | ||
|
|
07439ff99c | ||
|
|
f111c245c1 | ||
|
|
c3502da4a0 | ||
|
|
4012108d48 | ||
|
|
4a0605e09b | ||
|
|
250380d73e | ||
|
|
b30f5d782d | ||
|
|
b00cd9b557 | ||
|
|
e11f8f646b | ||
|
|
92b1de8cf8 | ||
|
|
bbafe53a2b | ||
|
|
e239fd970f | ||
|
|
7fa4515c28 | ||
|
|
b40eb0a454 | ||
|
|
5e3e9ddb8e | ||
|
|
a9a5284a67 | ||
|
|
afe504dbbf | ||
|
|
0c484ddcf7 | ||
|
|
8d0e80620a | ||
|
|
1d28506b09 | ||
|
|
1b33dbe2ae | ||
|
|
80654c059d | ||
|
|
999c548e6e | ||
|
|
e42913ae8a | ||
|
|
ee07cbecba | ||
|
|
fffaa9bced | ||
|
|
6195b2c99d | ||
|
|
06aafc96c9 | ||
|
|
2dc0727e36 | ||
|
|
a219feaa60 | ||
|
|
f3a09da340 | ||
|
|
946e345a3f | ||
|
|
6cb8d11b22 | ||
|
|
fdcf9c5327 | ||
|
|
45c714cbb5 | ||
|
|
7352a309a0 | ||
|
|
b297fe6f59 | ||
|
|
e575212c49 | ||
|
|
c52dc10c9e | ||
|
|
d35c913249 | ||
|
|
9bac59b952 | ||
|
|
5016253922 | ||
|
|
03893071fc | ||
|
|
d3dc94c04b | ||
|
|
af0feabb6a | ||
|
|
81ab0a414f | ||
|
|
ecd6ca0172 | ||
|
|
db7ee192f7 | ||
|
|
2ec0b601fa | ||
|
|
79feb6d5d2 | ||
|
|
8013b760e3 | ||
|
|
a29b8e5b36 | ||
|
|
9ef487a7a5 | ||
|
|
563fa46ba4 | ||
|
|
7865c06863 | ||
|
|
3d53b9244d | ||
|
|
f2afa4dd50 | ||
|
|
893ecec55e | ||
|
|
401584dbd8 | ||
|
|
b234b0bded | ||
|
|
b9b2c6a013 | ||
|
|
1d2efa0d25 | ||
|
|
93ec092eaf | ||
|
|
29ae492983 | ||
|
|
b9f6a59a20 | ||
|
|
d74551216f | ||
|
|
d4302ae51b | ||
|
|
9d5fb0b201 | ||
|
|
e0a5fe4002 | ||
|
|
f9d9a0a4bd | ||
|
|
78f0c7b119 | ||
|
|
c6d8343de2 | ||
|
|
0ccd11e587 | ||
|
|
b486711d68 | ||
|
|
2eb4c5e960 | ||
|
|
85aa740c98 | ||
|
|
6415848383 | ||
|
|
beb9460538 | ||
|
|
c030770be7 | ||
|
|
0180342dff | ||
|
|
b97748d3dc | ||
|
|
9d4977db00 | ||
|
|
f095284faa | ||
|
|
401c2f42f9 | ||
|
|
eb0348d47c | ||
|
|
1f46240ba9 | ||
|
|
14870726e0 | ||
|
|
c7d6a2eecb | ||
|
|
ce61eb2174 | ||
|
|
f3df21ef0a | ||
|
|
5eb554e008 | ||
|
|
e5e7c3fad3 | ||
|
|
2a8b9ab75e | ||
|
|
c8f0ffb42f | ||
|
|
b3e68b96cf | ||
|
|
ae7a550a09 | ||
|
|
e069bbb800 | ||
|
|
17ff6be6a9 | ||
|
|
d42489c67a | ||
|
|
3ea72e5d21 | ||
|
|
762854ad7a | ||
|
|
10465066ee | ||
|
|
0cf9f51816 | ||
|
|
3d5e2340ca | ||
|
|
e2047afa42 | ||
|
|
231b39d2dc | ||
|
|
dddce30368 | ||
|
|
e0e4ba2bd7 | ||
|
|
e0eadb6b76 | ||
|
|
483e5dfbea | ||
|
|
8aa9d8213d | ||
|
|
a74f71c935 | ||
|
|
87b81e53f0 | ||
|
|
a2816e31c3 | ||
|
|
f78af9f27b | ||
|
|
98138a0a60 | ||
|
|
e639b6303e | ||
|
|
99fb3ebe00 | ||
|
|
5829840409 | ||
|
|
4699ab5500 | ||
|
|
69fc7f39b7 | ||
|
|
510a962a52 | ||
|
|
570fc3cfb2 | ||
|
|
5d211f2fa6 | ||
|
|
dcb127c14d | ||
|
|
fba87de064 | ||
|
|
576f8cba44 | ||
|
|
b9f9429542 | ||
|
|
bf0df9f3c3 | ||
|
|
1d458f2782 | ||
|
|
5ca4b4a884 | ||
|
|
5935052ead | ||
|
|
f3f2ad9144 | ||
|
|
9d1edc4554 | ||
|
|
5143b8a492 | ||
|
|
7c67f40fc4 | ||
|
|
167b600135 | ||
|
|
6c465e25d3 | ||
|
|
c183d06ed1 | ||
|
|
574731b853 | ||
|
|
94568a4ec8 | ||
|
|
b22c0e5b6d | ||
|
|
ab3347d25d | ||
|
|
66872de8e5 | ||
|
|
f6d4402fdc | ||
|
|
9f66ccb5f3 | ||
|
|
b339330592 | ||
|
|
56acd2953b | ||
|
|
6f8e13297e | ||
|
|
e9a9144098 | ||
|
|
d1905dbee8 | ||
|
|
adc88f01b7 | ||
|
|
ccf0c5db67 | ||
|
|
507554b8e8 | ||
|
|
4795133daf | ||
|
|
c1c9075962 | ||
|
|
a691e9f744 | ||
|
|
8969eed506 | ||
|
|
be83095edf | ||
|
|
5c7783305a | ||
|
|
f394f7457b | ||
|
|
d60806bfa6 | ||
|
|
32febcb892 | ||
|
|
6c594b6f5f | ||
|
|
67d46432ed | ||
|
|
adf4166caa | ||
|
|
40b9810a63 | ||
|
|
d9e7984279 | ||
|
|
e5b9900d3b | ||
|
|
fc3f1431b2 | ||
|
|
c8bf2f4cb1 | ||
|
|
d16555ec4b | ||
|
|
3c9415b1c2 | ||
|
|
aa45670d87 | ||
|
|
e6d801a594 | ||
|
|
0aec2be4dd | ||
|
|
c86b618aaa | ||
|
|
451afabfbb | ||
|
|
f60049f713 | ||
|
|
ee0cd679d3 | ||
|
|
07ed6daeda | ||
|
|
b5800ced61 | ||
|
|
6d879f19f8 | ||
|
|
dde79c14f5 | ||
|
|
b08f245504 | ||
|
|
cbd0b7a94b | ||
|
|
f060d09272 | ||
|
|
6edad7e7de | ||
|
|
f0f596c892 | ||
|
|
dbe65f1d35 | ||
|
|
cdaf620f92 | ||
|
|
09b753d09e | ||
|
|
838fa5635f | ||
|
|
0a4d218010 | ||
|
|
24944cff22 | ||
|
|
34820f4344 | ||
|
|
56047e5fc8 | ||
|
|
80ee6c1a91 | ||
|
|
5649fbac20 | ||
|
|
586d3ecd60 | ||
|
|
9ebdca66d9 | ||
|
|
41ddcf2218 | ||
|
|
cbe1216bc2 | ||
|
|
234ee63859 | ||
|
|
2402541974 | ||
|
|
8b1fb30f59 | ||
|
|
bf6864bce0 | ||
|
|
34ebdaddc1 | ||
|
|
9f42772b7e | ||
|
|
47211f6cb3 | ||
|
|
95b48705fe | ||
|
|
6c1a2e1230 | ||
|
|
55b1e40885 | ||
|
|
d87f404d6e | ||
|
|
48c6ec87cf | ||
|
|
71972dcaab | ||
|
|
3fd158ad6e | ||
|
|
447af8da6a | ||
|
|
e8b80e8752 | ||
|
|
30a1164f6a | ||
|
|
80a5ea137b | ||
|
|
db8a8f3556 | ||
|
|
81195db87d | ||
|
|
03aaab6f8b | ||
|
|
c8af154205 | ||
|
|
825b9eafc2 | ||
|
|
0ad9ff0d87 | ||
|
|
8451133d00 | ||
|
|
be165c677f | ||
|
|
55ee289ed6 | ||
|
|
ca979a99e8 | ||
|
|
4ecbaa79cf | ||
|
|
c12f01261a | ||
|
|
d6d2749411 | ||
|
|
509588b130 | ||
|
|
e7411e8260 | ||
|
|
59f9b6f359 | ||
|
|
43df9f6b9c | ||
|
|
fd12f57f10 | ||
|
|
5edb3acad5 | ||
|
|
e35a8de4bb | ||
|
|
8b93e87e3e | ||
|
|
cb61e90148 | ||
|
|
c37b2d236b | ||
|
|
0c9295f8bc | ||
|
|
3b27d89c4a | ||
|
|
8356ac67e8 | ||
|
|
dffd2deb53 | ||
|
|
8ff48b371e | ||
|
|
6de66b87cb | ||
|
|
c8a521c182 | ||
|
|
5c48ccd92a | ||
|
|
f74d8aaf2b | ||
|
|
ffa1eb1ee9 | ||
|
|
24dfbfd84f | ||
|
|
ad6d71fef3 | ||
|
|
c178031f06 | ||
|
|
20db698475 | ||
|
|
dd624ccd9c | ||
|
|
ac504768b2 | ||
|
|
2d7b7160c3 | ||
|
|
2fbb9c285d | ||
|
|
47d99e5193 | ||
|
|
0437d6cc1a | ||
|
|
c6851cf7c5 | ||
|
|
45680a562e | ||
|
|
3b9d46fadc | ||
|
|
f840f3aceb | ||
|
|
afa1ecf3c5 | ||
|
|
295b9f4f5b | ||
|
|
79048a5a84 | ||
|
|
d683bd3744 | ||
|
|
9f5f4973ae | ||
|
|
441785b51d | ||
|
|
0d32115c3f | ||
|
|
e660768e4b | ||
|
|
01abb32025 | ||
|
|
d44d9ddca6 | ||
|
|
13f92b2b76 | ||
|
|
e6aa64760e | ||
|
|
3829df665f | ||
|
|
c8fafa6bbd | ||
|
|
aede2235d0 | ||
|
|
c56c73f250 | ||
|
|
dd0b6b1e30 | ||
|
|
5b324c85b0 | ||
|
|
fc9cff7d26 | ||
|
|
f3e70c79eb | ||
|
|
a705b72740 | ||
|
|
de6652dd9d | ||
|
|
c0dcbecbea | ||
|
|
b323f329cc | ||
|
|
2142d00bb9 | ||
|
|
4ce585be02 | ||
|
|
8ab1733374 | ||
|
|
e28f09e95b | ||
|
|
27e511b785 | ||
|
|
9dfa503bad | ||
|
|
5abe8dd506 | ||
|
|
e4119f3fd2 | ||
|
|
480e5ca4d1 | ||
|
|
f4cf2cecb5 | ||
|
|
5ab5cf03b5 | ||
|
|
13ba1e4900 | ||
|
|
17c919edd9 | ||
|
|
99b3693f40 | ||
|
|
483bb53d9c | ||
|
|
80ec23887e | ||
|
|
ea81b97bfc | ||
|
|
be39bf8d91 | ||
|
|
ca66c4bf59 | ||
|
|
4192489836 | ||
|
|
2e4667da88 | ||
|
|
9718aa5d4a | ||
|
|
d5dd43289b | ||
|
|
1bd7a662df | ||
|
|
327589a1d7 | ||
|
|
531b8f641f | ||
|
|
8ac274cdca | ||
|
|
fea79bc971 | ||
|
|
f2526bbc78 | ||
|
|
1794f2e047 | ||
|
|
b99e9abb5f | ||
|
|
e77f9bb8fc | ||
|
|
628f88cf79 | ||
|
|
87238f26f6 | ||
|
|
95013e87dd | ||
|
|
d604e8b9b4 | ||
|
|
9a2eb04054 | ||
|
|
f34da8a96f | ||
|
|
527f17d19e | ||
|
|
2818e05e71 | ||
|
|
49b50ce66c | ||
|
|
b793fbfc28 | ||
|
|
59ff94fefb | ||
|
|
f3c29840a7 | ||
|
|
6dabe4c010 | ||
|
|
8ecfcb12c7 | ||
|
|
ae8bc77ee7 | ||
|
|
e25490751c |
29
.gitignore
vendored
@@ -2,19 +2,34 @@
|
||||
default.properties
|
||||
gen
|
||||
assets/www/cordova.js
|
||||
framework/assets/www/.tmp*
|
||||
local.properties
|
||||
framework/proguard.cfg
|
||||
framework/cordova.jar
|
||||
framework/cordova-*.jar
|
||||
framework/phonegap-*.jar
|
||||
framework/lib
|
||||
proguard.cfg
|
||||
proguard.cfg
|
||||
proguard-project.txt
|
||||
framework/bin
|
||||
framework/test/org/apache/cordova/*.class
|
||||
framework/assets/www/.DS_Store
|
||||
framework/assets/www/cordova-*.js
|
||||
framework/assets/www/phonegap-*.js
|
||||
framework/libs
|
||||
test/libs
|
||||
example
|
||||
./test
|
||||
tmp
|
||||
*.tmp
|
||||
test/libs/*.jar
|
||||
test/bin
|
||||
test/assets/www/.tmp*
|
||||
tmp/**
|
||||
bin/node_modules
|
||||
.metadata
|
||||
tmp/**/*
|
||||
Thumbs.db
|
||||
Desktop.ini
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*.class
|
||||
*.jar
|
||||
# IntelliJ IDEA files
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
8
.reviewboardrc
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Settings for post-review (used for uploading diffs to reviews.apache.org).
|
||||
#
|
||||
GUESS_FIELDS = True
|
||||
OPEN_BROWSER = True
|
||||
TARGET_GROUPS = 'cordova'
|
||||
REVIEWBOARD_URL = 'http://reviews.apache.org'
|
||||
|
||||
14
NOTICE
@@ -1,5 +1,17 @@
|
||||
Apache Cordova
|
||||
Copyright 2012 The Apache Software Foundation
|
||||
|
||||
This product includes software developed by
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org)
|
||||
|
||||
=========================================================================
|
||||
== NOTICE file corresponding to the section 4 d of ==
|
||||
== the Apache License, Version 2.0, ==
|
||||
== in this case for the Android-specific code. ==
|
||||
=========================================================================
|
||||
|
||||
Android Code
|
||||
Copyright 2005-2008 The Android Open Source Project
|
||||
|
||||
This product includes software developed as part of
|
||||
The Android Open Source Project (http://source.android.com).
|
||||
|
||||
82
README.md
@@ -1,38 +1,41 @@
|
||||
<!--
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
-->
|
||||
Cordova Android
|
||||
===
|
||||
|
||||
Cordova Android is an Android application library that allows for Cordova based projects to be built for the Android Platform. Cordova based applications are, at the core, an application written with web technology: HTML, CSS and JavaScript.
|
||||
Cordova Android is an Android application library that allows for Cordova-based
|
||||
projects to be built for the Android Platform. Cordova based applications are,
|
||||
at the core, applications written with web technology: HTML, CSS and JavaScript.
|
||||
|
||||
[Apache Cordova](http://cordova.io) is a project at The Apache Software Foundation (ASF).
|
||||
|
||||
Apache Cordova is an effort undergoing incubation at The Apache
|
||||
Software Foundation (ASF), sponsored by the Apache Incubator project.
|
||||
Incubation is required of all newly accepted projects until a further
|
||||
review indicates that the infrastructure, communications, and decision
|
||||
making process have stabilized in a manner consistent with other
|
||||
successful ASF projects. While incubation status is not necessarily
|
||||
a reflection of the completeness or stability of the code, it does
|
||||
indicate that the project has yet to be fully endorsed by the ASF.
|
||||
|
||||
Requires
|
||||
---
|
||||
|
||||
- Java JDK 1.5
|
||||
- Apache ANT
|
||||
- Java JDK 1.5 or greater
|
||||
- Apache ANT 1.8.0 or greater
|
||||
- Android SDK [http://developer.android.com](http://developer.android.com)
|
||||
- Apache Commons Codec [http://commons.apache.org/codec/](http://commons.apache.org/codec/)
|
||||
|
||||
Building
|
||||
---
|
||||
|
||||
To create your cordova.jar, copy the commons codec:
|
||||
|
||||
mv commons-codec-1.6.jar framework/libs
|
||||
|
||||
then run in the framework directory:
|
||||
|
||||
android update project -p . -t android-15
|
||||
ant jar
|
||||
|
||||
|
||||
|
||||
Cordova Android Developer Tools
|
||||
---
|
||||
|
||||
@@ -49,7 +52,6 @@ the dependencies:
|
||||
General Commands
|
||||
|
||||
./bin/create [path package activity] ... create the ./example app or a cordova android project
|
||||
./bin/bench ............................ generate a bench proj
|
||||
./bin/autotest ......................... test the cli tools
|
||||
./bin/test ............................. run mobile-spec
|
||||
|
||||
@@ -57,7 +59,7 @@ Project Commands
|
||||
|
||||
These commands live in a generated Cordova Android project.
|
||||
|
||||
./cordovap/debug [path] ..................... install to first device
|
||||
./cordova/debug [path] ..................... install to first device
|
||||
./cordova/emulate .......................... start avd (emulator) named default
|
||||
./cordova/log .............................. starts logcat
|
||||
|
||||
@@ -78,15 +80,10 @@ Start adb logcat (console.log calls output here):
|
||||
|
||||
./cordova/log
|
||||
|
||||
Running the [callback/callback-test](http://github.com/callback/callback-test) tests:
|
||||
---
|
||||
|
||||
./bin/test
|
||||
|
||||
Creating a new Cordova Android Project
|
||||
---
|
||||
|
||||
./bin/create ~/Desktop/myapp com.phonegap.special MyApp
|
||||
./bin/create ~/Desktop/myapp com.myapp.special MyApp
|
||||
|
||||
Importing a Cordova Android Project into Eclipse
|
||||
----
|
||||
@@ -98,10 +95,25 @@ Importing a Cordova Android Project into Eclipse
|
||||
5. Right click on the project root: Run as > Run Configurations
|
||||
6. Click on the Target tab and select Manual (this way you can choose the emulator or device to build to)
|
||||
|
||||
Building without the Tooling
|
||||
---
|
||||
Note: The Developer Tools handle this. This is only to be done if the tooling fails, or if
|
||||
you are developing directly against the framework.
|
||||
|
||||
|
||||
To create your `cordova.jar` file, run in the framework directory:
|
||||
|
||||
android update project -p . -t android-17
|
||||
ant jar
|
||||
|
||||
|
||||
Running Tests
|
||||
----
|
||||
Please see details under test/README.md.
|
||||
|
||||
Further Reading
|
||||
---
|
||||
|
||||
- [http://developer.android.com](http://developer.android.com)
|
||||
- [http://docs.phonegap.com](http://docs.phonegap.com)
|
||||
- [http://wiki.phonegap.com](http://wiki.phonegap.com)
|
||||
- [http://cordova.apache.org/](http://cordova.apache.org)
|
||||
- [http://wiki.apache.org/cordova/](http://wiki.apache.org/cordova/)
|
||||
|
||||
21
bin/BOOM
@@ -1,21 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
#
|
||||
./bin/create
|
||||
cd ./example && ./cordova/debug && ./cordova/log
|
||||
@@ -1,2 +0,0 @@
|
||||
#! /usr/bin/env node
|
||||
require('nodeunit').reporters.default.run(['bin/tests'])
|
||||
47
bin/bench
@@ -1,47 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
#
|
||||
#
|
||||
# Creates an app in `./bench` that posts results to http://cordova-bench.heroku.com with current cordova/Android sha.
|
||||
#
|
||||
# USAGE
|
||||
# ./bin/bench
|
||||
#
|
||||
|
||||
# clobber any existing bench
|
||||
if [ -e ./bench ]
|
||||
then
|
||||
rm -rf ./bench
|
||||
fi
|
||||
|
||||
# create a benching app
|
||||
./bin/create ./bench org.apache.cordova.bench cordovaBench
|
||||
|
||||
# grab the latest bench www code
|
||||
git clone git@github.com:brianleroux/cordova-bench.git
|
||||
|
||||
# copy it into the app
|
||||
cat ./cordova-bench/www/index.html > ./bench/assets/www/index.html
|
||||
#cat ~/Desktop/cordova-bench/www/index.html > ./bench/assets/www/index.html
|
||||
|
||||
# clean up
|
||||
rm -rf ./cordova-bench
|
||||
|
||||
# launch to the first device found
|
||||
./bin/debug ./bench
|
||||
@@ -1,4 +1,4 @@
|
||||
#! /bin/sh
|
||||
#! /bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
@@ -16,29 +16,19 @@
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
#
|
||||
set -e
|
||||
|
||||
VERSION=$(cat ./VERSION)
|
||||
|
||||
# get the latest mobile-spec
|
||||
git clone git@github.com:callback/callback-test.git
|
||||
|
||||
# clobber test if it exists
|
||||
if [ -e ./test ]
|
||||
then
|
||||
rm -rf ./test
|
||||
ROOT="$( cd "$( dirname "$0" )/.." && pwd )"
|
||||
cmd=`android list target`
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "The command \"android\" failed. Make sure you have the latest Android SDK installed, and the \"android\" command (inside the tools/ folder) added to your path."
|
||||
exit 2
|
||||
elif [[ ! $cmd =~ "android-18" ]]; then
|
||||
echo "Please install Android target 18 (the Android 4.3 SDK). Make sure you have the latest Android tools installed as well. Run \"android\" from your command-line to install/update any missing SDKs or tools."
|
||||
exit 2
|
||||
else
|
||||
cmd="android update project -p $ROOT -t android-18 1> /dev/null 2>&1"
|
||||
eval $cmd
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Error updating the Cordova library to work with your Android environment."
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
# generate a working proj
|
||||
./bin/create ./test org.apache.cordova.test CordovaTest
|
||||
|
||||
# kill the default app and replace it w/ mobile-spec
|
||||
rm -rf ./test/assets/www
|
||||
mv ./callback-test ./test/assets/www
|
||||
|
||||
# copy in cordova.js since www dir was replaced above
|
||||
cp ./framework/assets/www/cordova-$VERSION.js ./test/assets/www/cordova-$VERSION.js
|
||||
|
||||
# build it, launch it and start logging on stdout
|
||||
cd ./test && ./cordova/debug && ./cordova/log
|
||||
26
bin/check_reqs.bat
Normal file
@@ -0,0 +1,26 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
|
||||
@ECHO OFF
|
||||
SET full_path=%~dp0
|
||||
IF EXIST %full_path%check_reqs.js (
|
||||
cscript "%full_path%check_reqs.js" //nologo
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'check_reqs.js' in 'bin' folder, aborting...>&2
|
||||
EXIT /B 1
|
||||
)
|
||||
102
bin/check_reqs.js
Normal file
@@ -0,0 +1,102 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
var ROOT = WScript.ScriptFullName.split('\\bin\\check_reqs.js').join(''),
|
||||
shell = WScript.CreateObject("WScript.Shell"),
|
||||
fso = WScript.CreateObject('Scripting.FileSystemObject');
|
||||
|
||||
|
||||
// executes a command in the shell, returns stdout or stderr if error
|
||||
function exec_out(command) {
|
||||
var oExec=shell.Exec(command);
|
||||
var output = new String();
|
||||
while (oExec.Status == 0) {
|
||||
if (!oExec.StdOut.AtEndOfStream) {
|
||||
var line = oExec.StdOut.ReadAll();
|
||||
// XXX: Change to verbose mode
|
||||
// WScript.StdOut.WriteLine(line);
|
||||
output += line;
|
||||
}
|
||||
WScript.sleep(100);
|
||||
}
|
||||
//Check to make sure our scripts did not encounter an error
|
||||
if (!oExec.StdErr.AtEndOfStream) {
|
||||
var line = oExec.StdErr.ReadAll();
|
||||
return {'error' : true, 'output' : line};
|
||||
} else if (!oExec.StdOut.AtEndOfStream) {
|
||||
var line = oExec.StdOut.ReadAll();
|
||||
// XXX: Change to verbose mode
|
||||
// WScript.StdOut.WriteLine(line);
|
||||
output += line;
|
||||
}
|
||||
return {'error' : false, 'output' : output};
|
||||
}
|
||||
|
||||
// log to stdout or stderr
|
||||
function Log(msg, error) {
|
||||
if (error) {
|
||||
WScript.StdErr.WriteLine(msg);
|
||||
}
|
||||
else {
|
||||
WScript.StdOut.WriteLine(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// checks that android requirements are met
|
||||
function check_requirements() {
|
||||
var target = get_target();
|
||||
if(target==null) {
|
||||
Log('Unable to find android target in project.properties');
|
||||
WScript.Quit(2);
|
||||
}
|
||||
var result = exec_out('%comspec% /c android list target');
|
||||
if(result.error) {
|
||||
Log('The command `android` failed. Make sure you have the latest Android SDK installed, and the `android` command (inside the tools/ folder) added to your path. Output: ' + result.output, true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
else if(result.output.indexOf(target) == -1) {
|
||||
Log(result.output.indexOf(target));
|
||||
Log('Please install the latest Android target (' + target + '). Make sure you have the latest Android tools installed as well. Run `android` from your command-line to install/update any missing SDKs or tools.', true);
|
||||
Log(result.output);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
else {
|
||||
var cmd = '%comspec% /c android update project -p ' + ROOT + '\\framework -t ' + target;
|
||||
result = exec_out(cmd);
|
||||
if(result.error) {
|
||||
Log('Error updating the Cordova library to work with your Android environment. Command run: "' + cmd + '", output: ' + result.output, true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function get_target() {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(ROOT + '\\framework\\project.properties', 1);
|
||||
var s=f.ReadAll();
|
||||
var lines = s.split('\n');
|
||||
for (var line in lines) {
|
||||
if(lines[line].match(/target=/))
|
||||
{
|
||||
return lines[line].split('=')[1].replace(' ', '').replace('\r', '');
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
check_requirements();
|
||||
|
||||
154
bin/create
@@ -1,4 +1,4 @@
|
||||
#! /bin/sh
|
||||
#! /bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
@@ -23,52 +23,136 @@
|
||||
#
|
||||
set -e
|
||||
|
||||
PROJECT_PATH=${1:-"./example"}
|
||||
if [ -z "$1" ] || [ "$1" == "-h" ]
|
||||
then
|
||||
echo "Usage: $0 <path_to_new_project> <package_name> <project_name>"
|
||||
echo "Make sure the Android SDK tools folder is in your PATH!"
|
||||
echo " <path_to_new_project>: Path to your new Cordova iOS project"
|
||||
echo " <package_name>: Package name, following reverse-domain style convention"
|
||||
echo " <project_name>: Project name"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
BUILD_PATH="$( cd "$( dirname "$0" )/.." && pwd )"
|
||||
VERSION=$(cat "$BUILD_PATH"/VERSION)
|
||||
|
||||
PROJECT_PATH="${1:-'./example'}"
|
||||
PACKAGE=${2:-"org.apache.cordova.example"}
|
||||
ACTIVITY=${3:-"cordovaExample"}
|
||||
TARGET=$(android list targets | grep 'id: ' | sed 's/id: \([0-9]*\).*/\1/g' | tail -1)
|
||||
VERSION=$(cat ./VERSION)
|
||||
ACTIVITY=$(echo ${3:-"cordovaExample"} | tr -d '[:blank:][:punct:]')
|
||||
APP_LABEL=${3:-"Cordova Example"};
|
||||
|
||||
# clobber any existing example
|
||||
if [ $# -eq 0 ]
|
||||
if [ -d "$PROJECT_PATH" ]
|
||||
then
|
||||
rm -rf $PROJECT_PATH
|
||||
echo "Project already exists! Delete and recreate"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# update the cordova-android framework for the desired target
|
||||
android update project --target $TARGET --path ./framework
|
||||
function createAppInfoJar {
|
||||
pushd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo > /dev/null
|
||||
javac ApplicationInfo.java
|
||||
jar -cfe ../appinfo.jar ApplicationInfo ApplicationInfo.class
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
if [ ! -e ./framework/libs/commons-codec-1.6.jar ]; then
|
||||
# Use curl to get the jar (TODO: Support Apache Mirrors)
|
||||
curl -OL http://mirror.symnds.com/software/Apache//commons/codec/binaries/commons-codec-1.6-bin.zip
|
||||
unzip commons-codec-1.6-bin.zip
|
||||
mkdir -p ./framework/libs
|
||||
cp commons-codec-1.6/commons-codec-1.6.jar ./framework/libs/
|
||||
function on_error {
|
||||
echo "An unexpected error occurred: $previous_command exited with $?"
|
||||
echo "Deleting project..."
|
||||
[ -d "$PROJECT_PATH" ] && rm -rf "$PROJECT_PATH"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function replace {
|
||||
local pattern=$1
|
||||
local filename=$2
|
||||
# Mac OS X requires -i argument
|
||||
if [[ "$OSTYPE" =~ "darwin" ]]
|
||||
then
|
||||
/usr/bin/sed -i '' -e "$pattern" "$filename"
|
||||
elif [[ "$OSTYPE" =~ "linux" ]]
|
||||
then
|
||||
/bin/sed -i -e $pattern "$filename"
|
||||
fi
|
||||
}
|
||||
|
||||
# we do not want the script to silently fail
|
||||
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
|
||||
trap on_error ERR
|
||||
|
||||
ANDROID_BIN="${ANDROID_BIN:=$( which android )}"
|
||||
PACKAGE_AS_PATH=$(echo $PACKAGE | sed 's/\./\//g')
|
||||
ACTIVITY_PATH="$PROJECT_PATH"/src/$PACKAGE_AS_PATH/$ACTIVITY.java
|
||||
MANIFEST_PATH="$PROJECT_PATH"/AndroidManifest.xml
|
||||
STRINGS_PATH="$PROJECT_PATH"/res/values/strings.xml
|
||||
|
||||
TARGET=$("$ANDROID_BIN" list targets | grep id: | tail -1 | cut -f 2 -d ' ' )
|
||||
API_LEVEL=$("$ANDROID_BIN" list target | grep "API level:" | tail -n 1 | cut -f 2 -d ':' | tr -d ' ')
|
||||
|
||||
# check that build targets exist
|
||||
if [ -z "$TARGET" ] || [ -z "$API_LEVEL" ]
|
||||
then
|
||||
echo "No Android Targets are installed. Please install at least one via the android SDK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# compile cordova.js and cordova.jar
|
||||
cd ./framework && ant jar && cd ../
|
||||
# if this a distribution release no need to build a jar
|
||||
if [ ! -e "$BUILD_PATH"/cordova-$VERSION.jar ] && [ -d "$BUILD_PATH"/framework ]
|
||||
then
|
||||
# update the cordova-android framework for the desired target
|
||||
"$ANDROID_BIN" update project --target $TARGET --path "$BUILD_PATH"/framework &> /dev/null
|
||||
|
||||
# copy all the bin scripts etc in there
|
||||
cp -R ./bin/templates/project/ $PROJECT_PATH
|
||||
# compile cordova.js and cordova.jar
|
||||
pushd "$BUILD_PATH"/framework > /dev/null
|
||||
ant jar > /dev/null
|
||||
popd > /dev/null
|
||||
fi
|
||||
|
||||
# copy in cordova.js
|
||||
cp ./framework/assets/www/cordova-$VERSION.js $PROJECT_PATH/.cordova/android/cordova-$VERSION.js
|
||||
# create new android project
|
||||
"$ANDROID_BIN" create project --target $TARGET --path "$PROJECT_PATH" --package $PACKAGE --activity $ACTIVITY &> /dev/null
|
||||
|
||||
# copy in cordova.jar
|
||||
cp ./framework/cordova-$VERSION.jar $PROJECT_PATH/.cordova/android/cordova-$VERSION.jar
|
||||
# copy project template
|
||||
cp -r "$BUILD_PATH"/bin/templates/project/assets "$PROJECT_PATH"
|
||||
cp -r "$BUILD_PATH"/bin/templates/project/res "$PROJECT_PATH"
|
||||
|
||||
# copy in res/xml
|
||||
cp ./framework/res/xml/cordova.xml $PROJECT_PATH/.cordova/android/cordova.xml
|
||||
cp ./framework/res/xml/plugins.xml $PROJECT_PATH/.cordova/android/plugins.xml
|
||||
# copy cordova.js, cordova.jar and res/xml
|
||||
if [ -d "$BUILD_PATH"/framework ]
|
||||
then
|
||||
cp -r "$BUILD_PATH"/framework/res/xml "$PROJECT_PATH"/res
|
||||
cp "$BUILD_PATH"/framework/assets/www/cordova.js "$PROJECT_PATH"/assets/www/cordova.js
|
||||
cp "$BUILD_PATH"/framework/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
|
||||
else
|
||||
cp -r "$BUILD_PATH"/xml "$PROJECT_PATH"/res/xml
|
||||
cp "$BUILD_PATH"/cordova.js "$PROJECT_PATH"/assets/www/cordova.js
|
||||
cp "$BUILD_PATH"/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
|
||||
fi
|
||||
|
||||
# app properties
|
||||
cat > $PROJECT_PATH/.cordova/config <<eom
|
||||
VERSION=$VERSION
|
||||
PROJECT_PATH=$PROJECT_PATH
|
||||
PACKAGE=$PACKAGE
|
||||
ACTIVITY=$ACTIVITY
|
||||
TARGET=$TARGET
|
||||
eom
|
||||
# interpolate the activity name and package
|
||||
cp "$BUILD_PATH"/bin/templates/project/Activity.java "$ACTIVITY_PATH"
|
||||
replace "s/__ACTIVITY__/${ACTIVITY}/g" "$ACTIVITY_PATH"
|
||||
replace "s/__ID__/${PACKAGE}/g" "$ACTIVITY_PATH"
|
||||
|
||||
# interpolate the app name into strings.xml
|
||||
replace "s/>${ACTIVITY}</>${APP_LABEL}</g" "$STRINGS_PATH"
|
||||
|
||||
cp "$BUILD_PATH"/bin/templates/project/AndroidManifest.xml "$MANIFEST_PATH"
|
||||
replace "s/__ACTIVITY__/${ACTIVITY}/g" "$MANIFEST_PATH"
|
||||
replace "s/__PACKAGE__/${PACKAGE}/g" "$MANIFEST_PATH"
|
||||
replace "s/__APILEVEL__/${API_LEVEL}/g" "$MANIFEST_PATH"
|
||||
|
||||
# creating cordova folder and copying run/build/log/launch scripts
|
||||
mkdir "$PROJECT_PATH"/cordova
|
||||
mkdir "$PROJECT_PATH"/cordova/lib
|
||||
createAppInfoJar
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/appinfo.jar "$PROJECT_PATH"/cordova/appinfo.jar
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/build "$PROJECT_PATH"/cordova/build
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/clean "$PROJECT_PATH"/cordova/clean
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/log "$PROJECT_PATH"/cordova/log
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/run "$PROJECT_PATH"/cordova/run
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/version "$PROJECT_PATH"/cordova/version
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/install-device "$PROJECT_PATH"/cordova/lib/install-device
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/install-emulator "$PROJECT_PATH"/cordova/lib/install-emulator
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/list-devices "$PROJECT_PATH"/cordova/lib/list-devices
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/list-emulator-images "$PROJECT_PATH"/cordova/lib/list-emulator-images
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/list-started-emulators "$PROJECT_PATH"/cordova/lib/list-started-emulators
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/start-emulator "$PROJECT_PATH"/cordova/lib/start-emulator
|
||||
|
||||
(cd $PROJECT_PATH && ./cordova/create)
|
||||
|
||||
@@ -1 +1,54 @@
|
||||
cscript bin\create.js %*
|
||||
@ECHO OFF
|
||||
GOTO BEGIN
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
|
||||
:BEGIN
|
||||
IF NOT DEFINED JAVA_HOME GOTO MISSING_JAVA_HOME
|
||||
|
||||
FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
|
||||
IF [%%~$PATH:X]==[] (
|
||||
ECHO Cannot locate %%X using the PATH environment variable.
|
||||
ECHO Retry after adding directory containing %%X to the PATH variable.
|
||||
ECHO Remember to open a new command window after updating the PATH variable.
|
||||
IF "%%X"=="java.exe" GOTO GET_JAVA
|
||||
IF "%%X"=="javac.exe" GOTO GET_JAVA
|
||||
IF "%%X"=="ant.bat" GOTO GET_ANT
|
||||
IF "%%X"=="android.bat" GOTO GET_ANDROID
|
||||
GOTO ERROR
|
||||
)
|
||||
)
|
||||
cscript "%~dp0\create.js" %* //nologo
|
||||
GOTO END
|
||||
:MISSING_JAVA_HOME
|
||||
ECHO The JAVA_HOME environment variable is not set.
|
||||
ECHO Set JAVA_HOME to an existing JRE directory.
|
||||
ECHO Remember to also add JAVA_HOME to the PATH variable.
|
||||
ECHO After updating system variables, open a new command window and retry.
|
||||
GOTO ERROR
|
||||
:GET_JAVA
|
||||
ECHO Visit http://java.oracle.com if you need to install Java (JDK).
|
||||
GOTO ERROR
|
||||
:GET_ANT
|
||||
ECHO Visit http://ant.apache.org if you need to install Apache Ant.
|
||||
GOTO ERROR
|
||||
:GET_ANDROID
|
||||
ECHO Visit http://developer.android.com if you need to install the Android SDK.
|
||||
GOTO ERROR
|
||||
:ERROR
|
||||
EXIT /B 1
|
||||
:END
|
||||
|
||||
388
bin/create.js
@@ -1,174 +1,214 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* create a cordova/android project
|
||||
*
|
||||
* USAGE
|
||||
* ./create [path package activity]
|
||||
*/
|
||||
|
||||
function read(filename) {
|
||||
WScript.Echo('Reading in ' + filename);
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 1);
|
||||
var s=f.ReadAll();
|
||||
f.Close();
|
||||
return s;
|
||||
}
|
||||
function write(filename, contents) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 2, true);
|
||||
f.Write(contents);
|
||||
f.Close();
|
||||
}
|
||||
function replaceInFile(filename, regexp, replacement) {
|
||||
write(filename, read(filename).replace(regexp, replacement));
|
||||
}
|
||||
function exec(s, output) {
|
||||
WScript.Echo('Executing ' + s);
|
||||
var o=shell.Exec(s);
|
||||
while (o.Status == 0) {
|
||||
WScript.Sleep(100);
|
||||
}
|
||||
WScript.Echo("Command exited with code " + o.Status);
|
||||
}
|
||||
|
||||
function fork(s) {
|
||||
WScript.Echo('Executing ' + s);
|
||||
var o=shell.Exec(s);
|
||||
while (o.Status != 1) {
|
||||
WScript.Sleep(100);
|
||||
}
|
||||
WScript.Echo(o.StdOut.ReadAll());
|
||||
WScript.Echo(o.StdErr.ReadAll());
|
||||
WScript.Echo("Command exited with code " + o.Status);
|
||||
}
|
||||
|
||||
var args = WScript.Arguments, PROJECT_PATH="example",
|
||||
PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
|
||||
shell=WScript.CreateObject("WScript.Shell");
|
||||
|
||||
// working dir
|
||||
var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
|
||||
|
||||
if (args.Count() == 3) {
|
||||
WScript.Echo('Found expected arguments');
|
||||
PROJECT_PATH=args(0);
|
||||
PACKAGE=args(1);
|
||||
ACTIVITY=args(2);
|
||||
}
|
||||
|
||||
var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
|
||||
var ACTIVITY_PATH=PROJECT_PATH+'\\src\\'+PACKAGE_AS_PATH+'\\'+ACTIVITY+'.java';
|
||||
var MANIFEST_PATH=PROJECT_PATH+'\\AndroidManifest.xml';
|
||||
var TARGET=shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s([0-9]).*/)[1];
|
||||
var VERSION=read('VERSION').replace(/\r\n/,'').replace(/\n/,'');
|
||||
|
||||
WScript.Echo("Project path: " + PROJECT_PATH);
|
||||
WScript.Echo("Package: " + PACKAGE);
|
||||
WScript.Echo("Activity: " + ACTIVITY);
|
||||
WScript.Echo("Package as path: " + PACKAGE_AS_PATH);
|
||||
WScript.Echo("Activity path: " + ACTIVITY_PATH);
|
||||
WScript.Echo("Manifest path: " + MANIFEST_PATH);
|
||||
WScript.Echo("Cordova version: " + VERSION);
|
||||
|
||||
// TODO: clobber any existing example
|
||||
|
||||
/*
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
rm -rf $PROJECT_PATH
|
||||
fi
|
||||
*/
|
||||
|
||||
// create the project
|
||||
exec('android.bat create project --target '+TARGET+' --path '+PROJECT_PATH+' --package '+PACKAGE+' --activity '+ACTIVITY);
|
||||
|
||||
// update the cordova framework project to a target that exists on this machine
|
||||
exec('android.bat update project --target '+TARGET+' --path framework');
|
||||
|
||||
// pull down commons codec if necessary
|
||||
var fso = WScript.CreateObject('Scripting.FileSystemObject');
|
||||
if (!fso.FileExists(ROOT + '\\framework\\libs\\commons-codec-1.6.jar')) {
|
||||
// We need the .jar
|
||||
var url = 'http://mirror.symnds.com/software/Apache//commons/codec/binaries/commons-codec-1.6-bin.zip';
|
||||
var savePath = ROOT + '\\framework\\libs\\commons-codec-1.6-bin.zip';
|
||||
if (!fso.FileExists(savePath)) {
|
||||
// We need the zip to get the jar
|
||||
var xhr = WScript.CreateObject('MSXML2.XMLHTTP');
|
||||
xhr.open('GET', url, false);
|
||||
xhr.send();
|
||||
if (xhr.status == 200) {
|
||||
var stream = WScript.CreateObject('ADODB.Stream');
|
||||
stream.Open();
|
||||
stream.Type = 1;
|
||||
stream.Write(xhr.ResponseBody);
|
||||
stream.Position = 0;
|
||||
stream.SaveToFile(savePath);
|
||||
stream.Close();
|
||||
} else {
|
||||
WScript.Echo('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
|
||||
}
|
||||
}
|
||||
var app = WScript.CreateObject('Shell.Application');
|
||||
var source = app.NameSpace(savePath).Items();
|
||||
var target = app.NameSpace(ROOT + '\\framework\\libs');
|
||||
target.CopyHere(source, 256);
|
||||
|
||||
// Move the jar into libs
|
||||
fso.MoveFile(ROOT + '\\framework\\libs\\commons-codec-1.6\\commons-codec-1.6.jar', ROOT + '\\framework\\libs\\commons-codec-1.6.jar');
|
||||
|
||||
// Clean up
|
||||
fso.DeleteFile(ROOT + '\\framework\\libs\\commons-codec-1.6-bin.zip');
|
||||
fso.DeleteFolder(ROOT + '\\framework\\libs\\commons-codec-1.6', true);
|
||||
}
|
||||
|
||||
|
||||
// compile cordova.js and cordova.jar
|
||||
// if you see an error about "Unable to resolve target" then you may need to
|
||||
// update your android tools or install an additional Android platform version
|
||||
exec('ant.bat -f framework\\build.xml jar');
|
||||
|
||||
// copy in the project template
|
||||
exec('cmd /c xcopy bin\\templates\\project\\* '+PROJECT_PATH+' /S /Y');
|
||||
|
||||
// copy example www assets
|
||||
exec('cmd /c xcopy ' + PROJECT_PATH + '\\cordova\\assets ' + PROJECT_PATH + ' /S /Y');
|
||||
|
||||
// copy in cordova.js
|
||||
exec('cmd /c copy framework\\assets\\js\\cordova.android.js '+PROJECT_PATH+'\\.cordova\\android\\cordova-'+VERSION+'.js /Y');
|
||||
|
||||
// copy in cordova.jar
|
||||
exec('cmd /c copy framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\.cordova\\android\\cordova-'+VERSION+'.jar /Y');
|
||||
|
||||
// copy in xml
|
||||
exec('cmd /c copy framework\\res\\xml\\cordova.xml ' + PROJECT_PATH + '\\.cordova\\android\\cordova.xml /Y');
|
||||
exec('cmd /c copy framework\\res\\xml\\plugins.xml ' + PROJECT_PATH + '\\.cordova\\android\\plugins.xml /Y');
|
||||
|
||||
// write out config file
|
||||
write(PROJECT_PATH + '\\.cordova\\config',
|
||||
'VERSION=' + VERSION + '\r\n' +
|
||||
'PROJECT_PATH=' + PROJECT_PATH + '\r\n' +
|
||||
'PACKAGE=' + PACKAGE + '\r\n' +
|
||||
'ACTIVITY=' + ACTIVITY + '\r\n' +
|
||||
'TARGET=' + TARGET);
|
||||
|
||||
// run project-specific create process
|
||||
fork('cscript.exe ' + PROJECT_PATH + '\\cordova\\create.js');
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* create a cordova/android project
|
||||
*
|
||||
* USAGE
|
||||
* ./create [path package activity]
|
||||
*/
|
||||
|
||||
var args = WScript.Arguments, PROJECT_PATH="example",
|
||||
PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
|
||||
shell=WScript.CreateObject("WScript.Shell"),
|
||||
fso = WScript.CreateObject('Scripting.FileSystemObject');
|
||||
|
||||
function Usage() {
|
||||
Log("Usage: create PathTONewProject [ PackageName AppName ]");
|
||||
Log(" PathTONewProject : The path to where you wish to create the project");
|
||||
Log(" PackageName : The package for the project (default is org.apache.cordova.example)")
|
||||
Log(" AppName : The name of the application/activity (default is cordovaExample)");
|
||||
Log("examples:");
|
||||
Log(" create C:\\Users\\anonymous\\Desktop\\MyProject");
|
||||
Log(" create C:\\Users\\anonymous\\Desktop\\MyProject io.Cordova.Example AnApp");
|
||||
}
|
||||
|
||||
// logs messaged to stdout and stderr
|
||||
function Log(msg, error) {
|
||||
if (error) {
|
||||
WScript.StdErr.WriteLine(msg);
|
||||
}
|
||||
else {
|
||||
WScript.StdOut.WriteLine(msg);
|
||||
}
|
||||
}
|
||||
|
||||
function read(filename) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 1);
|
||||
var s=f.ReadAll();
|
||||
f.Close();
|
||||
return s;
|
||||
}
|
||||
|
||||
function checkTargets(targets) {
|
||||
if(!targets) {
|
||||
Log("You do not have any android targets setup. Please create at least one target with the `android` command", true);
|
||||
WScript.Quit(69);
|
||||
}
|
||||
}
|
||||
|
||||
function setTarget() {
|
||||
var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s\d+/g);
|
||||
checkTargets(targets);
|
||||
return targets[targets.length - 1].replace(/id: /, ""); // TODO: give users the option to set their target
|
||||
}
|
||||
function setApiLevel() {
|
||||
var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/API level:\s\d+/g);
|
||||
checkTargets(targets);
|
||||
return targets[targets.length - 1].replace(/API level: /, "");
|
||||
}
|
||||
function write(filename, contents) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 2, true);
|
||||
f.Write(contents);
|
||||
f.Close();
|
||||
}
|
||||
function replaceInFile(filename, regexp, replacement) {
|
||||
write(filename, read(filename).replace(regexp, replacement));
|
||||
}
|
||||
function exec(command) {
|
||||
var oShell=shell.Exec(command);
|
||||
while (oShell.Status == 0) {
|
||||
if(!oShell.StdOut.AtEndOfStream) {
|
||||
var line = oShell.StdOut.ReadLine();
|
||||
// XXX: Change to verbose mode
|
||||
// WScript.StdOut.WriteLine(line);
|
||||
}
|
||||
WScript.sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
function createAppInfoJar() {
|
||||
if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
|
||||
Log("Creating appinfo.jar...");
|
||||
var cur = shell.CurrentDirectory;
|
||||
shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
|
||||
exec("javac ApplicationInfo.java");
|
||||
exec("jar -cfe ..\\appinfo.jar ApplicationInfo ApplicationInfo.class");
|
||||
shell.CurrentDirectory = cur;
|
||||
}
|
||||
}
|
||||
|
||||
// working dir
|
||||
var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
|
||||
if (args.Count() > 0) {
|
||||
// support help flags
|
||||
if (args(0) == "--help" || args(0) == "/?" ||
|
||||
args(0) == "help" || args(0) == "-help" || args(0) == "/help" || args(0) == "-h") {
|
||||
Usage();
|
||||
WScript.Quit(2);
|
||||
}
|
||||
|
||||
PROJECT_PATH=args(0);
|
||||
if (args.Count() > 1) {
|
||||
PACKAGE = args(1);
|
||||
}
|
||||
if (args.Count() > 2) {
|
||||
ACTIVITY = args(2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log("Error : No project path provided.");
|
||||
Usage();
|
||||
WScript.Quit(2);
|
||||
}
|
||||
|
||||
if(fso.FolderExists(PROJECT_PATH)) {
|
||||
Log("Project path already exists!", true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
|
||||
var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
|
||||
var ACTIVITY_DIR=PROJECT_PATH + '\\src\\' + PACKAGE_AS_PATH;
|
||||
var SAFE_ACTIVITY = ACTIVITY.replace(/\W/g, '');
|
||||
var ACTIVITY_PATH=ACTIVITY_DIR+'\\'+SAFE_ACTIVITY+'.java';
|
||||
var MANIFEST_PATH=PROJECT_PATH+'\\AndroidManifest.xml';
|
||||
var STRINGS_PATH=PROJECT_PATH+'\\res\\values\\strings.xml';
|
||||
var TARGET=setTarget();
|
||||
var API_LEVEL=setApiLevel();
|
||||
var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
|
||||
// create the project
|
||||
Log("Creating new android project...");
|
||||
exec('android.bat create project --target "'+TARGET+'" --path "'+PROJECT_PATH+'" --package "'+PACKAGE+'" --activity "'+SAFE_ACTIVITY+'"');
|
||||
|
||||
// build from source. distro should have these files
|
||||
if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
|
||||
!fso.FileExists(ROOT+'\\cordova.js')) {
|
||||
Log("Building jar and js files...");
|
||||
// update the cordova framework project to a target that exists on this machine
|
||||
exec('android.bat update project --target "'+TARGET+'" --path "'+ROOT+'\\framework"');
|
||||
exec('ant.bat -f "'+ ROOT +'\\framework\\build.xml" jar');
|
||||
}
|
||||
|
||||
// copy in the project template
|
||||
Log("Copying template files...");
|
||||
exec('%comspec% /c xcopy "'+ ROOT + '\\bin\\templates\\project\\res" "'+PROJECT_PATH+'\\res\\" /E /Y');
|
||||
exec('%comspec% /c xcopy "'+ ROOT + '\\bin\\templates\\project\\assets" "'+PROJECT_PATH+'\\assets\\" /E /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\project\\AndroidManifest.xml" "' + PROJECT_PATH + '\\AndroidManifest.xml" /Y');
|
||||
exec('%comspec% /c mkdir "' + ACTIVITY_DIR + '"');
|
||||
exec('%comspec% /c copy "' + ROOT + '"\\bin\\templates\\project\\Activity.java "' + ACTIVITY_PATH + '" /Y');
|
||||
|
||||
// check if we have the source or the distro files
|
||||
Log("Copying js, jar & config.xml files...");
|
||||
if(fso.FolderExists(ROOT + '\\framework')) {
|
||||
exec('%comspec% /c copy "'+ROOT+'\\framework\\assets\\www\\cordova.js" "'+PROJECT_PATH+'\\assets\\www\\cordova.js" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\framework\\cordova-'+VERSION+'.jar" "'+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar" /Y');
|
||||
fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\framework\\res\\xml\\config.xml" "' + PROJECT_PATH + '\\res\\xml\\config.xml" /Y');
|
||||
} else {
|
||||
// copy in cordova.js
|
||||
exec('%comspec% /c copy "'+ROOT+'\\cordova.js" "'+PROJECT_PATH+'\\assets\\www\\cordova.js" /Y');
|
||||
// copy in cordova.jar
|
||||
exec('%comspec% /c copy "'+ROOT+'\\cordova-'+VERSION+'.jar" "'+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar" /Y');
|
||||
// copy in xml
|
||||
fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\xml\\config.xml" "' + PROJECT_PATH + '\\res\\xml\\config.xml" /Y');
|
||||
}
|
||||
|
||||
// copy cordova scripts
|
||||
fso.CreateFolder(PROJECT_PATH + '\\cordova');
|
||||
fso.CreateFolder(PROJECT_PATH + '\\cordova\\lib');
|
||||
createAppInfoJar();
|
||||
Log("Copying cordova command tools...");
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\appinfo.jar" "' + PROJECT_PATH + '\\cordova\\appinfo.jar" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\cordova.js" "' + PROJECT_PATH + '\\cordova\\lib\\cordova.js" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\install-device.bat" "' + PROJECT_PATH + '\\cordova\\lib\\install-device.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\install-emulator.bat" "' + PROJECT_PATH + '\\cordova\\lib\\install-emulator.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-emulator-images.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-emulator-images.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-devices.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-devices.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-started-emulators.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-started-emulators.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\start-emulator.bat" "' + PROJECT_PATH + '\\cordova\\lib\\start-emulator.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\cordova.bat" "' + PROJECT_PATH + '\\cordova\\cordova.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\clean.bat" "' + PROJECT_PATH + '\\cordova\\clean.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\build.bat" "' + PROJECT_PATH + '\\cordova\\build.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\log.bat" "' + PROJECT_PATH + '\\cordova\\log.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\run.bat" "' + PROJECT_PATH + '\\cordova\\run.bat" /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\version.bat" "' + PROJECT_PATH + '\\cordova\\version.bat" /Y');
|
||||
|
||||
// interpolate the activity name and package
|
||||
Log("Updating AndroidManifest.xml and Main Activity...");
|
||||
replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||
replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
|
||||
|
||||
replaceInFile(MANIFEST_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||
replaceInFile(MANIFEST_PATH, /__PACKAGE__/, PACKAGE);
|
||||
replaceInFile(MANIFEST_PATH, /__APILEVEL__/, API_LEVEL);
|
||||
|
||||
replaceInFile(STRINGS_PATH, new RegExp('>' + SAFE_ACTIVITY + '<'), '>' + ACTIVITY + '<');
|
||||
@@ -18,9 +18,5 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://git-wip-us.apache.org/repos/asf/incubator-cordova-android.git"
|
||||
},
|
||||
"dependencies":{
|
||||
"coffee-script":"1.1.2",
|
||||
"nodeunit":"0.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
61
bin/templates/cordova/ApplicationInfo/ApplicationInfo.java
Normal file
@@ -0,0 +1,61 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.xml.sax.SAXException;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ApplicationInfo {
|
||||
private static void parseAndroidManifest(String path) {
|
||||
// System.out.println(path);
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
Document dom;
|
||||
try {
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
dom = db.parse(path);
|
||||
|
||||
// getting package information
|
||||
Element manifest = dom.getDocumentElement();
|
||||
String pakkage = manifest.getAttribute("package");
|
||||
|
||||
// getting activity name
|
||||
String activity = ((Element)dom.getElementsByTagName("activity").item(0)).getAttribute("android:name");
|
||||
System.out.println(String.format("%s/.%s", pakkage, activity.replace(".", "")));
|
||||
} catch(ParserConfigurationException pce) {
|
||||
pce.printStackTrace();
|
||||
} catch(SAXException se) {
|
||||
se.printStackTrace();
|
||||
} catch(IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String path;
|
||||
if(args.length > 0) {
|
||||
path = args[0];
|
||||
} else {
|
||||
path = System.getProperty("user.dir") + "/../AndroidManifest.xml";
|
||||
}
|
||||
parseAndroidManifest(path);
|
||||
}
|
||||
}
|
||||
39
bin/templates/cordova/build
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_PATH=$( cd "$DIR/.." && pwd )
|
||||
|
||||
if [[ "$#" -eq 1 ]] ; then
|
||||
if [[ $1 == "--debug" ]] ; then
|
||||
$DIR/clean
|
||||
ant debug -f "$PROJECT_PATH"/build.xml
|
||||
elif [[ $1 == "--release" ]] ; then
|
||||
$DIR/clean
|
||||
ant release -f "$PROJECT_PATH"/build.xml
|
||||
elif [[ $1 == "--nobuild" ]] ; then
|
||||
echo "Skipping build..."
|
||||
else
|
||||
echo "Error : Build command '$1' not recognized."
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
echo "Warning : [ --debug | --release | --nobuild ] not specified, defaulting to --debug"
|
||||
$DIR/clean
|
||||
ant debug -f "$PROJECT_PATH"/build.xml
|
||||
fi
|
||||
18
bin/templates/cordova/build.bat
Normal file
@@ -0,0 +1,18 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
%~dp0\cordova.bat build %*
|
||||
22
bin/templates/cordova/clean
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_PATH=$( cd "$DIR/.." && pwd )
|
||||
echo "Cleaning project..."
|
||||
ant -f "$PROJECT_PATH/build.xml" clean
|
||||
18
bin/templates/cordova/clean.bat
Normal file
@@ -0,0 +1,18 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
%~dp0\cordova.bat clean %*
|
||||
31
bin/templates/cordova/cordova.bat
Normal file
@@ -0,0 +1,31 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
IF NOT DEFINED JAVA_HOME GOTO MISSING
|
||||
FOR %%X in (java.exe ant.bat android.bat) do (
|
||||
SET FOUND=%%~$PATH:X
|
||||
IF NOT DEFINED FOUND GOTO MISSING
|
||||
)
|
||||
cscript %~dp0\lib\cordova.js %* //nologo
|
||||
GOTO END
|
||||
:MISSING
|
||||
ECHO Missing one of the following:
|
||||
ECHO JDK: http://java.oracle.com
|
||||
ECHO Android SDK: http://developer.android.com
|
||||
ECHO Apache ant: http://ant.apache.org
|
||||
EXIT /B 1
|
||||
:END
|
||||
609
bin/templates/cordova/lib/cordova.js
vendored
Normal file
@@ -0,0 +1,609 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\cordova.js').join(''),
|
||||
shell = WScript.CreateObject("WScript.Shell"),
|
||||
fso = WScript.CreateObject('Scripting.FileSystemObject');
|
||||
//device_id for targeting specific device
|
||||
var device_id;
|
||||
//build types
|
||||
var NONE = 0,
|
||||
DEBUG = '--debug',
|
||||
RELEASE = '--release',
|
||||
NO_BUILD = '--nobuild';
|
||||
var build_type = NONE;
|
||||
|
||||
//deploy tpyes
|
||||
var NONE = 0,
|
||||
EMULATOR = 1,
|
||||
DEVICE = 2,
|
||||
TARGET = 3;
|
||||
var deploy_type = NONE;
|
||||
|
||||
|
||||
// log to stdout or stderr
|
||||
function Log(msg, error) {
|
||||
if (error) {
|
||||
WScript.StdErr.WriteLine(msg);
|
||||
}
|
||||
else {
|
||||
WScript.StdOut.WriteLine(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// executes a commmand in the shell, returning stdout
|
||||
function exec(command) {
|
||||
var oExec=shell.Exec(command);
|
||||
var output = new String();
|
||||
while (oExec.Status == 0) {
|
||||
if (!oExec.StdOut.AtEndOfStream) {
|
||||
var line = oExec.StdOut.ReadLine();
|
||||
output += line;
|
||||
}
|
||||
WScript.sleep(100);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// executes a command in the shell, returns stdout or stderr if error
|
||||
function exec_out(command) {
|
||||
var oExec=shell.Exec(command);
|
||||
var output = new String();
|
||||
while (oExec.Status == 0) {
|
||||
if (!oExec.StdOut.AtEndOfStream) {
|
||||
var line = oExec.StdOut.ReadLine();
|
||||
// XXX: Change to verbose mode
|
||||
// WScript.StdOut.WriteLine(line);
|
||||
output += line;
|
||||
}
|
||||
WScript.sleep(100);
|
||||
}
|
||||
//Check to make sure our scripts did not encounter an error
|
||||
if (!oExec.StdErr.AtEndOfStream) {
|
||||
var line = oExec.StdErr.ReadAll();
|
||||
return {'error' : true, 'output' : line};
|
||||
}
|
||||
return {'error' : false, 'output' : output};
|
||||
}
|
||||
|
||||
// executes a commmand in the shell and outputs stdout and fails on stderr
|
||||
function exec_verbose(command) {
|
||||
//Log("Command: " + command);
|
||||
var oShell=shell.Exec(command);
|
||||
while (oShell.Status == 0) {
|
||||
//Wait a little bit so we're not super looping
|
||||
WScript.sleep(100);
|
||||
//Print any stdout output from the script
|
||||
if (!oShell.StdOut.AtEndOfStream) {
|
||||
var line = oShell.StdOut.ReadLine();
|
||||
Log(line);
|
||||
}
|
||||
}
|
||||
//Check to make sure our scripts did not encounter an error
|
||||
if (!oShell.StdErr.AtEndOfStream) {
|
||||
var line = oShell.StdErr.ReadAll();
|
||||
Log(line, true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
|
||||
function version(path) {
|
||||
var cordovajs_path = path + "\\assets\\www\\cordova.js";
|
||||
if(fso.FileExists(cordovajs_path)) {
|
||||
var f = fso.OpenTextFile(cordovajs_path, 1,2);
|
||||
var cordovajs = f.ReadAll();
|
||||
f.Close();
|
||||
var version_regex = /^.*CORDOVA_JS_BUILD_LABEL.*$/m;
|
||||
var version_line = cordovajs.match(version_regex) + "";
|
||||
var version = version_line.match(/(\d+)\.(\d+)\.(\d+)(rc\d)?/) + "";
|
||||
// TODO : figure out why this isn't matching properly so we can remove this substring workaround.
|
||||
Log(version.substr(0, ((version.length/2) -1)));
|
||||
} else {
|
||||
Log("Error : Could not find cordova js.", true);
|
||||
Log("Expected Location : " + cordovajs_path, true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function get_devices() {
|
||||
var device_list = []
|
||||
var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
|
||||
if (local_devices.match(/\w+\tdevice/)) {
|
||||
devices = local_devices.split('\r\n');
|
||||
//format (ID DESCRIPTION)
|
||||
for (i in devices) {
|
||||
if (devices[i].match(/\w+\tdevice/) && !devices[i].match(/emulator/)) {
|
||||
device_list.push(devices[i].replace(/\t/, ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
return device_list
|
||||
}
|
||||
|
||||
function list_devices() {
|
||||
var devices = get_devices();
|
||||
if (devices.length > 0) {
|
||||
for (i in devices) {
|
||||
Log(devices[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log('No devices found, if your device is connected and not showing,');
|
||||
Log(' then try and install the drivers for your device.');
|
||||
Log(' http://developer.android.com/tools/extras/oem-usb.html');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function get_emulator_images() {
|
||||
var avd_list = [];
|
||||
var local_emulators = shell.Exec("%comspec% /c android list avds").StdOut.ReadAll();
|
||||
if (local_emulators.match(/Name\:/)) {
|
||||
emulators = local_emulators.split('\n');
|
||||
var count = 0;
|
||||
var output = '';
|
||||
for (i in emulators) {
|
||||
// Find the line with the emulator name.
|
||||
if (emulators[i].match(/Name\:/)) {
|
||||
// strip description
|
||||
var emulator_name = emulators[i].replace(/\s*Name\:\s/, '') + ' ';
|
||||
avd_list.push(emulator_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return avd_list;
|
||||
}
|
||||
|
||||
function list_emulator_images() {
|
||||
var images = get_emulator_images();
|
||||
if (images.length > 0) {
|
||||
for(i in images) {
|
||||
Log(images[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log('No emulators found, if you would like to create an emulator follow the instructions');
|
||||
Log(' provided here : http://developer.android.com/tools/devices/index.html');
|
||||
Log(' Or run \'android create avd --name <name> --target <targetID>\' in on the command line.');
|
||||
}
|
||||
}
|
||||
|
||||
function get_started_emulators() {
|
||||
var started_emulators = [];
|
||||
var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
|
||||
if (local_devices.match(/emulator/)) {
|
||||
devices = local_devices.split('\r\n');
|
||||
//format (ID DESCRIPTION)
|
||||
for (i in devices) {
|
||||
if (devices[i].match(/\w+\tdevice/) && devices[i].match(/emulator/)) {
|
||||
started_emulators.push(devices[i].replace(/\t/, ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
return started_emulators
|
||||
}
|
||||
|
||||
function list_started_emulators() {
|
||||
var images = get_started_emulators();
|
||||
if (images.length > 0) {
|
||||
for(i in images) {
|
||||
Log(images[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log('No started emulators found, if you would like to start an emulator call ');
|
||||
Log('\'list-emulator-images\'');
|
||||
Log(' to get the name of an emulator and then start the emulator with');
|
||||
Log('\'start-emulator <Name>\'');
|
||||
}
|
||||
}
|
||||
|
||||
function create_emulator() {
|
||||
//get targets
|
||||
var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s\d+/g);
|
||||
if(targets) {
|
||||
exec('%comspec% /c android create avd --name cordova_emulator --target ' + targets[targets.length - 1].replace(/id: /, ""));
|
||||
} else {
|
||||
Log("You do not have any android targets setup. Please create at least one target with the `android` command so that an emulator can be created.", true);
|
||||
WScript.Quit(69);
|
||||
}
|
||||
}
|
||||
|
||||
function start_emulator(name) {
|
||||
var emulators = get_emulator_images();
|
||||
var started_emulators = get_started_emulators();
|
||||
var num_started = started_emulators.length;
|
||||
var emulator_name;
|
||||
var started = false;
|
||||
if (name) {
|
||||
for (i in emulators) {
|
||||
if (emulators[i].substr(0,name.length) == name) {
|
||||
Log("Starting emulator : " + name);
|
||||
shell.Exec("%comspec% /c emulator -avd " + name + " &");
|
||||
//shell.Run("%comspec% /c start cmd /c emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\cache -avd " + name);
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (emulators.length > 0 && started_emulators.length == 0) {
|
||||
emulator_name = emulators[0].split(' ', 1)[0];
|
||||
start_emulator(emulator_name);
|
||||
return;
|
||||
} else if (started_emulators.length > 0) {
|
||||
Log("Emulator already started : " + started_emulators[0].split(' ', 1));
|
||||
return;
|
||||
} else {
|
||||
Log("Error : unable to start emulator, ensure you have emulators availible by checking \'list-emulator-images\'", true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
if (!started) {
|
||||
Log("Error : unable to start emulator, ensure you have emulators availible by checking \'list-emulator-images\'", true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
else {
|
||||
// wait for emulator to get the ID
|
||||
Log('Waiting for emulator...');
|
||||
var boot_anim = null;
|
||||
var emulator_ID = null;
|
||||
var new_started = null;
|
||||
var i = 0;
|
||||
while(emulator_ID == null && i < 10) {
|
||||
new_started = get_started_emulators();
|
||||
if(new_started.length > started_emulators.length) {
|
||||
// find new emulator that was just started to get it's ID
|
||||
for(var i = 0; i < new_started.length; i++) {
|
||||
if (new_started[i] != started_emulators[i]) {
|
||||
emulator_ID = new_started[i].split(' ', 1)[0];
|
||||
boot_anim = exec_out('%comspec% /c adb -s ' + emulator_ID + ' shell getprop init.svc.bootanim');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == 10) {
|
||||
Log('\nEmulator start timed out.');
|
||||
WScript.Quit(2);
|
||||
}
|
||||
i = 0;
|
||||
WScript.Stdout.Write('Booting up emulator (this may take a while).');
|
||||
// use boot animation property to tell when boot is complete.
|
||||
while (!boot_anim.output.match(/stopped/) && i < 100) {
|
||||
boot_anim = exec_out('%comspec% /c adb -s ' + emulator_ID + ' shell getprop init.svc.bootanim');
|
||||
i++;
|
||||
WScript.Stdout.Write('.');
|
||||
WScript.Sleep(2000);
|
||||
}
|
||||
|
||||
if (i < 100) {
|
||||
Log('\nBoot Complete!');
|
||||
// Unlock the device
|
||||
shell.Exec("%comspec% /c adb -s " + emulator_ID + " shell input keyevent 82");
|
||||
} else {
|
||||
Log('\nEmulator boot timed out. Failed to load emulator');
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function get_apk(path) {
|
||||
// check if file .apk has been created
|
||||
if (fso.FolderExists(path + '\\bin')) {
|
||||
var path_to_apk;
|
||||
var out_folder = fso.GetFolder(path + '\\bin');
|
||||
var out_files = new Enumerator(out_folder.Files);
|
||||
for (;!out_files.atEnd(); out_files.moveNext()) {
|
||||
var path = out_files.item() + '';
|
||||
if (fso.GetExtensionName(path) == 'apk' && !path.match(/unaligned/)) {
|
||||
path_to_apk = out_files.item();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (path_to_apk) {
|
||||
return path_to_apk;
|
||||
}
|
||||
else {
|
||||
Log('Failed to find apk, make sure you project is built and there is an ', true);
|
||||
Log(' apk in <project>\\bin\\. To build your project use \'<project>\\cordova\\build\'', true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function install_device(path) {
|
||||
var devices = get_devices();
|
||||
var use_target = false;
|
||||
if (devices.length < 1) {
|
||||
Log("Error : No devices found to install to, make sure there are devices", true);
|
||||
Log(" availible by checking \'<project_dir>\\cordova\\lib\\list-devices\'", true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
launch(path, devices[0].split(' ', 1)[0], true);
|
||||
}
|
||||
|
||||
function install_emulator(path) {
|
||||
var emulators = get_started_emulators();
|
||||
var use_target = false;
|
||||
if (emulators.length < 1) {
|
||||
Log("Error : No emulators found to install to, make sure there are emulators", true);
|
||||
Log(" availible by checking \'<project_dir>\\cordova\\lib\\list-started-emulators\'", true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
launch(path, emulators[0].split(' ', 1)[0], false);
|
||||
}
|
||||
|
||||
function install_target(path) {
|
||||
if(device_id) {
|
||||
var device = false;
|
||||
var emulators = get_started_emulators();
|
||||
var devices = get_devices();
|
||||
var exists = false;
|
||||
for (i in emulators) {
|
||||
if (emulators[i].substr(0,device_id.length) == device_id) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i in devices) {
|
||||
if (devices[i].substr(0,device_id.length) == device_id) {
|
||||
exists = true;
|
||||
device = true
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exists) {
|
||||
Log("Error : Unable to find target " + device_id, true);
|
||||
Log("Please ensure the target exists by checking \'<project>\\cordova\\lib\\list-started-emulators'");
|
||||
Log(" Or \'<project>\\cordova\\lib\\list-devices'");
|
||||
}
|
||||
launch(path, device_id, device);
|
||||
}
|
||||
else {
|
||||
Log("You cannot install to a target without providing a valid target ID.", true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
|
||||
function launch(path, id, device) {
|
||||
if(id) {
|
||||
var path_to_apk = get_apk(path);
|
||||
if (path_to_apk) {
|
||||
var launch_name = exec_out("%comspec% /c java -jar "+path+"\\cordova\\appinfo.jar "+path+"\\AndroidManifest.xml");
|
||||
if (launch_name.error) {
|
||||
Log("Failed to get application name from appinfo.jar + AndroidManifest : ", true);
|
||||
Log("Output : " + launch_name.output, true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
if (device) {
|
||||
// install on device (-d)
|
||||
Log("Installing app on device...");
|
||||
} else {
|
||||
// install on emulator (-e)
|
||||
Log("Installing app on emulator...");
|
||||
}
|
||||
var cmd = '%comspec% /c adb -s ' + id + ' install -r ' + path_to_apk;
|
||||
var install = exec_out(cmd);
|
||||
if ( install.error && install.output.match(/Failure/)) {
|
||||
Log("Error : Could not install apk to emulator : ", true);
|
||||
Log(install.output, true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
else {
|
||||
Log(install.output);
|
||||
}
|
||||
// launch the application
|
||||
Log("Launching application...");
|
||||
cmd = '%comspec% /c adb -s ' + id + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
|
||||
exec_verbose(cmd);
|
||||
}
|
||||
else {
|
||||
Log('Failed to find apk, make sure you project is built and there is an ', true);
|
||||
Log(' apk in <project>\\bin\\. To build your project use \'<project>\\cordova\\build\'', true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log("You cannot install to a target without providing a valid target ID.", true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
|
||||
function clean(path) {
|
||||
Log("Cleaning project...");
|
||||
exec("%comspec% /c ant.bat clean -f "+path+"\\build.xml 2>&1");
|
||||
}
|
||||
|
||||
function log() {
|
||||
// filter out nativeGetEnabledTags spam from latest sdk bug.
|
||||
shell.Run("%comspec% /c adb logcat | grep -v nativeGetEnabledTags");
|
||||
}
|
||||
|
||||
function build(path) {
|
||||
switch (build_type) {
|
||||
case DEBUG :
|
||||
clean(path);
|
||||
Log("Building project...");
|
||||
exec_verbose("%comspec% /c ant.bat debug -f "+path+"\\build.xml 2>&1");
|
||||
break;
|
||||
case RELEASE :
|
||||
clean(path);
|
||||
Log("Building project...");
|
||||
exec_verbose("%comspec% /c ant.bat release -f "+path+"\\build.xml 2>&1");
|
||||
break;
|
||||
case NO_BUILD :
|
||||
Log("Skipping build process.");
|
||||
break;
|
||||
case NONE :
|
||||
clean(path);
|
||||
Log("WARNING: [ --debug | --release | --nobuild ] not specified, defaulting to --debug.");
|
||||
exec_verbose("%comspec% /c ant.bat debug -f "+path+"\\build.xml 2>&1");
|
||||
break;
|
||||
default :
|
||||
Log("Build option not recognized: " + build_type, true);
|
||||
WScript.Quit(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function run(path) {
|
||||
switch(deploy_type) {
|
||||
case EMULATOR :
|
||||
build(path);
|
||||
if(get_started_emulators().length == 0) {
|
||||
start_emulator();
|
||||
}
|
||||
//TODO : Start emulator if one isn't started, and create one if none exists.
|
||||
install_emulator(path);
|
||||
break;
|
||||
case DEVICE :
|
||||
build(path);
|
||||
install_device(path);
|
||||
break;
|
||||
case TARGET :
|
||||
build(path);
|
||||
install_target(path);
|
||||
break;
|
||||
case NONE :
|
||||
if (get_devices().length > 0) {
|
||||
Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, defaulting to --device");
|
||||
deploy_type = DEVICE;
|
||||
} else {
|
||||
Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, defaulting to --emulator");
|
||||
deploy_type = EMULATOR;
|
||||
}
|
||||
run(path);
|
||||
break;
|
||||
default :
|
||||
Log("Deploy option not recognized: " + deploy_type, true);
|
||||
WScript.Quit(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var args = WScript.Arguments;
|
||||
if (args.count() == 0) {
|
||||
Log("Error: no args provided.");
|
||||
WScript.Quit(2);
|
||||
}
|
||||
else {
|
||||
// parse command
|
||||
switch(args(0)) {
|
||||
case "version" :
|
||||
version(ROOT);
|
||||
break;
|
||||
case "build" :
|
||||
if(args.Count() > 1) {
|
||||
if (args(1) == "--release") {
|
||||
build_type = RELEASE;
|
||||
}
|
||||
else if (args(1) == "--debug") {
|
||||
build_type = DEBUG;
|
||||
}
|
||||
else if (args(1) == "--nobuild") {
|
||||
build_type = NO_BUILD;
|
||||
}
|
||||
else {
|
||||
Log('Error: \"' + args(i) + '\" is not recognized as a build option', true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
build(ROOT);
|
||||
break;
|
||||
case "clean" :
|
||||
clean();
|
||||
break;
|
||||
case "list-devices" :
|
||||
list_devices();
|
||||
break;
|
||||
case "list-emulator-images" :
|
||||
list_emulator_images();
|
||||
break;
|
||||
case "list-started-emulators" :
|
||||
list_started_emulators();
|
||||
break;
|
||||
case "start-emulator" :
|
||||
if (args.Count() > 1) {
|
||||
start_emulator(args(1))
|
||||
} else {
|
||||
start_emulator();
|
||||
}
|
||||
break;
|
||||
case "install-emulator" :
|
||||
if (args.Count() == 2) {
|
||||
if (args(1).substr(0,9) == "--target=") {
|
||||
device_id = args(1).split('--target=').join('');
|
||||
install_emulator(ROOT);
|
||||
} else {
|
||||
Log('Error: \"' + args(1) + '\" is not recognized as an install option', true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
} else {
|
||||
install_emulator(ROOT);
|
||||
}
|
||||
break;
|
||||
case "install-device" :
|
||||
if (args.Count() == 2) {
|
||||
if (args(1).substr(0,9) == "--target=") {
|
||||
device_id = args(1).split('--target=').join('');
|
||||
install_target(ROOT);
|
||||
} else {
|
||||
Log('Error: \"' + args(1) + '\" is not recognized as an install option', true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
} else {
|
||||
install_device(ROOT);
|
||||
}
|
||||
break;
|
||||
case "run" :
|
||||
//parse args
|
||||
for(var i = 1; i < args.Count(); i++) {
|
||||
if (args(i) == "--release") {
|
||||
build_type = RELEASE;
|
||||
}
|
||||
else if (args(i) == "--debug") {
|
||||
build_type = DEBUG;
|
||||
}
|
||||
else if (args(i) == "--nobuild") {
|
||||
build_type = NO_BUILD;
|
||||
}
|
||||
else if (args(i) == "--emulator" || args(i) == "-e") {
|
||||
deploy_type = EMULATOR;
|
||||
}
|
||||
else if (args(i) == "--device" || args(i) == "-d") {
|
||||
deploy_type = DEVICE;
|
||||
}
|
||||
else if (args(i).substr(0,9) == "--target=") {
|
||||
device_id = args(i).split("--target=").join("");
|
||||
deploy_type = TARGET;
|
||||
}
|
||||
else {
|
||||
Log('Error: \"' + args(i) + '\" is not recognized as a run option', true);
|
||||
WScript.Quit(2);
|
||||
}
|
||||
}
|
||||
run(ROOT);
|
||||
break;
|
||||
default :
|
||||
Log("Cordova does not regognize the command " + args(0), true);
|
||||
WScript.Quit(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
49
bin/templates/cordova/lib/install-device
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_PATH=$( cd "$DIR/../.." && pwd )
|
||||
device_list=$("$DIR/list-devices")
|
||||
if [ $? != 0 ]; then
|
||||
echo "No devices found to deploy to. Please make sure your device is connected"
|
||||
echo " and you can view it using the 'cordova/lib/list-devices' command."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
apks=`find $PROJECT_PATH/bin -type f -maxdepth 1 | egrep '\.apk$'`
|
||||
apk_list=($apks)
|
||||
if [[ ${#apk_list[@]} > 0 ]] ; then
|
||||
# handle target
|
||||
read -ra device_array <<< "$device_list"
|
||||
if [[ "$#" -eq 1 ]] ; then
|
||||
# deploy to given target
|
||||
target=${1/--target=/}
|
||||
else
|
||||
# delete trailing space and 'device' after device ID
|
||||
target=${device_array[0]}
|
||||
fi
|
||||
echo "Installing ${apk_list[0]} onto device $target..."
|
||||
adb -s $target install -r ${apk_list[0]};
|
||||
echo "Launching application..."
|
||||
launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
|
||||
adb -s $target shell am start -W -a android.intent.action.MAIN -n $launch_str
|
||||
else
|
||||
echo "Application package not found, could not install to device"
|
||||
echo " make sure your application is built before deploying."
|
||||
exit 2
|
||||
fi
|
||||
25
bin/templates/cordova/lib/install-device.bat
Normal file
@@ -0,0 +1,25 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
SET full_path=%~dp0
|
||||
IF EXIST %full_path%cordova.js (
|
||||
cscript "%full_path%cordova.js" install-device %* //nologo
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
|
||||
EXIT /B 1
|
||||
)
|
||||
50
bin/templates/cordova/lib/install-emulator
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_PATH=$( cd "$DIR/../.." && pwd )
|
||||
emulator_list=$("$DIR/list-started-emulators")
|
||||
if [ $? != 0 ]; then
|
||||
echo "No emulators found to deploy to. Please make sure your emulator is started"
|
||||
echo " You can view it using the 'cordova/lib/list-started-emulators' command."
|
||||
echo " You can view created emulator images using the 'cordova/lib/list-emulator-images' command."
|
||||
echo " You can start an emulator image using the 'cordova/lib/start-emulator' command."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
apks=`find $PROJECT_PATH/bin -type f -maxdepth 1 | egrep '\.apk$'`
|
||||
apk_list=($apks)
|
||||
if [[ ${#apk_list[@]} > 0 ]] ; then
|
||||
# handle target emulator
|
||||
if [[ "$#" -eq 1 ]] ; then
|
||||
# deploy to given target
|
||||
target=${1/--target=/}
|
||||
else
|
||||
# delete trailing space and 'device' after emulator ID
|
||||
target=${emulator_list[0]}
|
||||
fi
|
||||
echo "Installing ${apk_list[0]} onto emulator $target..."
|
||||
adb -s $target install -r ${apk_list[0]};
|
||||
echo "Launching application..."
|
||||
launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
|
||||
adb -s $target shell am start -W -a android.intent.action.MAIN -n $launch_str
|
||||
else
|
||||
echo "Application package not found, could not install to device"
|
||||
echo " make sure your application is built before deploying."
|
||||
exit 2
|
||||
fi
|
||||
25
bin/templates/cordova/lib/install-emulator.bat
Normal file
@@ -0,0 +1,25 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
SET full_path=%~dp0
|
||||
IF EXIST %full_path%cordova.js (
|
||||
cscript "%full_path%cordova.js" install-emulator %* //nologo
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
|
||||
EXIT /B 1
|
||||
)
|
||||
30
bin/templates/cordova/lib/list-devices
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator' | awk '{ print $1; }'`
|
||||
device_list=($devices)
|
||||
if [[ ${#device_list[@]} > 0 ]] ; then
|
||||
for i in ${devices[@]}
|
||||
do
|
||||
echo $i
|
||||
done
|
||||
exit 0
|
||||
else
|
||||
echo "No devices found."
|
||||
exit 2
|
||||
fi
|
||||
25
bin/templates/cordova/lib/list-devices.bat
Normal file
@@ -0,0 +1,25 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
SET full_path=%~dp0
|
||||
IF EXIST %full_path%cordova.js (
|
||||
cscript "%full_path%cordova.js" list-devices //nologo
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
|
||||
EXIT /B 1
|
||||
)
|
||||
32
bin/templates/cordova/lib/list-emulator-images
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
|
||||
emulator_list=($emulator_images)
|
||||
if [[ ${#emulator_list[@]} > 0 ]] ; then
|
||||
for i in ${emulator_list[@]}
|
||||
do
|
||||
echo $i
|
||||
done
|
||||
exit 0
|
||||
else
|
||||
echo "No emulators found, if you would like to create an emulator follow the instructions"
|
||||
echo " provided here : http://developer.android.com/tools/devices/index.html"
|
||||
echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
|
||||
exit 2
|
||||
fi
|
||||
25
bin/templates/cordova/lib/list-emulator-images.bat
Normal file
@@ -0,0 +1,25 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
SET full_path=%~dp0
|
||||
IF EXIST %full_path%cordova.js (
|
||||
cscript "%full_path%cordova.js" list-emulator-images //nologo
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
|
||||
EXIT /B 1
|
||||
)
|
||||
32
bin/templates/cordova/lib/list-started-emulators
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print $1;}}' | grep 'emulator' | grep -v 'offline'`
|
||||
read -ra emulator_list <<< "$devices"
|
||||
if [[ ${#emulator_list[@]} > 0 ]] ; then
|
||||
for i in ${emulator_list[@]}
|
||||
do
|
||||
# remove space and 'device'
|
||||
echo $i
|
||||
done
|
||||
exit 0
|
||||
else
|
||||
echo "No started emulators found (it may still be booting up), you can start an emulator by using the command"
|
||||
echo " 'cordova/lib/start-emulator'"
|
||||
exit 2
|
||||
fi
|
||||
25
bin/templates/cordova/lib/list-started-emulators.bat
Normal file
@@ -0,0 +1,25 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
SET full_path=%~dp0
|
||||
IF EXIST %full_path%cordova.js (
|
||||
cscript "%full_path%cordova.js" list-started-emulators //nologo
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
|
||||
EXIT /B 1
|
||||
)
|
||||
111
bin/templates/cordova/lib/start-emulator
Executable file
@@ -0,0 +1,111 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_PATH=$( cd "$( dirname "$0" )/../.." && pwd )
|
||||
|
||||
function dot {
|
||||
sleep 1
|
||||
echo -n "."
|
||||
}
|
||||
|
||||
function wait_for_emulator() {
|
||||
local emulator_log_path="$1"
|
||||
local error_string
|
||||
local status
|
||||
|
||||
# Try to detect fatal errors early
|
||||
sleep 1.5
|
||||
error_string=$(grep -F "ERROR: " ${emulator_log_path})
|
||||
status=$?
|
||||
|
||||
if [ $status -eq 0 ]; then
|
||||
echo "Emulator failed to start, fatal error detected"
|
||||
echo "Error: ${error_string}"
|
||||
echo "Full log available at: ${emulator_log_path}"
|
||||
echo "Exiting..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local i="0"
|
||||
echo -n "Waiting for emulator"
|
||||
emulator_string=$($DIR/list-started-emulators)
|
||||
while [ $? != 0 ]
|
||||
do
|
||||
dot
|
||||
i=$[i+1]
|
||||
emulator_string=$($DIR/list-started-emulators)
|
||||
done
|
||||
read -ra target <<< "$emulator_string"
|
||||
echo ""
|
||||
echo -n "Waiting for it to boot up (this can take a while)"
|
||||
while [ $i -lt 300 ]
|
||||
do
|
||||
boot_anim=$(adb -s $target shell getprop init.svc.bootanim 2>&1)
|
||||
if [[ "$boot_anim" =~ "stopped" ]] ; then
|
||||
break
|
||||
else
|
||||
i=$[i+1]
|
||||
dot
|
||||
fi
|
||||
done
|
||||
# Device timeout: emulator has not started in time
|
||||
if [ $i -eq 300 ]
|
||||
then
|
||||
echo ""
|
||||
echo "Emulator timeout!"
|
||||
exit 69
|
||||
else
|
||||
echo ""
|
||||
echo "Connected!"
|
||||
fi
|
||||
# Unlock the device
|
||||
adb -s $target shell input keyevent 82
|
||||
exit 0
|
||||
}
|
||||
|
||||
emulator_images=$("$DIR/list-emulator-images")
|
||||
if [ $? != 0 ]; then
|
||||
echo "No emulators found, if you would like to create an emulator follow the instructions"
|
||||
echo " provided here : http://developer.android.com/tools/devices/index.html"
|
||||
echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# start first emulator
|
||||
log_path=$(mktemp -t android_emulator)
|
||||
|
||||
# if target emulator is provided
|
||||
if [[ "$#" -eq 1 ]] ; then
|
||||
# check that it exists
|
||||
if [[ $emulator_images =~ $1 ]] ; then
|
||||
#xterm -e emulator -avd $1 &
|
||||
emulator -avd $1 1> "${log_path}" 2>&1 &
|
||||
else
|
||||
echo "Could not find the provided emulator '$1', make sure the emulator exists"
|
||||
echo " by checking 'cordova/lib/list-emulator-images'"
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
read -ra emulator_list <<< "$emulator_images"
|
||||
#xterm -e emulator -avd ${emulator_list[0]} &
|
||||
emulator -avd ${emulator_list[0]} 1> "${log_path}" 2>&1 &
|
||||
fi
|
||||
|
||||
echo "Saving emulator log to: ${log_path}"
|
||||
wait_for_emulator "$log_path"
|
||||
25
bin/templates/cordova/lib/start-emulator.bat
Normal file
@@ -0,0 +1,25 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
SET full_path=%~dp0
|
||||
IF EXIST %full_path%cordova.js (
|
||||
cscript "%full_path%cordova.js" start-emulator %* //nologo
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
|
||||
EXIT /B 1
|
||||
)
|
||||
20
bin/templates/cordova/log
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
# filter out nativeGetEnabledTags spam from latest sdk bug.
|
||||
adb logcat | grep -v nativeGetEnabledTags
|
||||
18
bin/templates/cordova/log.bat
Normal file
@@ -0,0 +1,18 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
%~dp0\cordova.bat log %*
|
||||
81
bin/templates/cordova/run
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_PATH=$( cd "$DIR/.." && pwd )
|
||||
|
||||
function run_on_device_or_emulator {
|
||||
devices=`$DIR/lib/list-devices`
|
||||
if [ $? = 0 ]; then
|
||||
$DIR/lib/install-device
|
||||
else
|
||||
run_on_emulator
|
||||
fi
|
||||
}
|
||||
|
||||
function run_on_emulator {
|
||||
emulators=`$DIR/lib/list-started-emulators`
|
||||
if [ $? = 0 ] ; then
|
||||
$DIR/lib/install-emulator
|
||||
else
|
||||
images=`$DIR/lib/list-emulator-images`
|
||||
if [ $? = 0 ] ; then
|
||||
$DIR/lib/start-emulator
|
||||
$DIR/lib/install-emulator
|
||||
else
|
||||
echo "No devices/emulators started nor images available to start. How are we supposed to do this, then?"
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
if [[ "$#" -eq 2 ]] ; then
|
||||
# TODO: the order of arguments here may be reversed from the assumption below
|
||||
$DIR/build $2
|
||||
if [[ $1 == "--device" ]] ; then
|
||||
$DIR/lib/install-device
|
||||
elif [[ $1 == "--emulator" ]] ; then
|
||||
run_on_emulator
|
||||
elif [[ $1 =~ "--target=" ]]; then
|
||||
$DIR/lib/install-device $1
|
||||
else
|
||||
echo "Error : '$1' is not recognized as an install option"
|
||||
fi
|
||||
elif [[ "$#" -eq 1 ]] ; then
|
||||
if [[ $1 == "--debug" || $1 == "--release" || $1 == "--nobuild" ]] ; then
|
||||
$DIR/build $1
|
||||
run_on_device_or_emulator
|
||||
elif [[ $1 == "--device" ]] ; then
|
||||
$DIR/build
|
||||
$DIR/lib/install-device
|
||||
elif [[ $1 == "--emulator" ]] ; then
|
||||
$DIR/build
|
||||
run_on_emulator
|
||||
elif [[ $1 =~ "--target=" ]]; then
|
||||
$DIR/build
|
||||
$DIR/lib/install-device $1
|
||||
else
|
||||
echo "Error : '$1' is not recognized as an install option"
|
||||
fi
|
||||
else
|
||||
echo "Warning : [ --device | --emulate | --target=<targetID> ] not specified, using defaults."
|
||||
$DIR/build
|
||||
run_on_device_or_emulator
|
||||
fi
|
||||
18
bin/templates/cordova/run.bat
Normal file
@@ -0,0 +1,18 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
%~dp0\cordova.bat run %*
|
||||
19
bin/templates/cordova/version
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
|
||||
echo "2.9.0"
|
||||
18
bin/templates/cordova/version.bat
Normal file
@@ -0,0 +1,18 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
@ECHO OFF
|
||||
%~dp0\cordova.bat version %*
|
||||
@@ -1 +0,0 @@
|
||||
ok...
|
||||
@@ -1,3 +0,0 @@
|
||||
this is local config for cordova stuff to be eventually moved to
|
||||
config.xml ...we think. feedback to @davejohnson/@brianleroux
|
||||
appreciated here!
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package __ID__;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import org.apache.cordova.*;
|
||||
|
||||
@@ -29,7 +28,9 @@ public class __ACTIVITY__ extends DroidGap
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
super.loadUrl("file:///android_asset/www/index.html");
|
||||
// Set by <content src="index.html" /> in config.xml
|
||||
super.loadUrl(Config.getStartUrl());
|
||||
//super.loadUrl("file:///android_asset/www/index.html")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
||||
package="__PACKAGE__" android:versionName="1.1" android:versionCode="5">
|
||||
package="__PACKAGE__" android:versionName="1.0" android:versionCode="1" android:hardwareAccelerated="true">
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
@@ -47,9 +47,11 @@
|
||||
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||
android:hardwareAccelerated="true"
|
||||
android:debuggable="true">
|
||||
<activity android:name="__ACTIVITY__" android:label="@string/app_name"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<activity android:name="__ACTIVITY__" android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@@ -57,5 +59,5 @@
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="5" />
|
||||
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="__APILEVEL__"/>
|
||||
</manifest>
|
||||
115
bin/templates/project/assets/www/css/index.css
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
* {
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
|
||||
-webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
|
||||
-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
|
||||
background-color:#E4E4E4;
|
||||
background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
|
||||
background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
|
||||
background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
|
||||
background-image:-webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
left bottom,
|
||||
color-stop(0, #A7A7A7),
|
||||
color-stop(0.51, #E4E4E4)
|
||||
);
|
||||
background-attachment:fixed;
|
||||
font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
|
||||
font-size:12px;
|
||||
height:100%;
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
text-transform:uppercase;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
/* Portrait layout (default) */
|
||||
.app {
|
||||
background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
|
||||
position:absolute; /* position in the center of the screen */
|
||||
left:50%;
|
||||
top:50%;
|
||||
height:50px; /* text area height */
|
||||
width:225px; /* text area width */
|
||||
text-align:center;
|
||||
padding:180px 0px 0px 0px; /* image height is 200px (bottom 20px are overlapped with text) */
|
||||
margin:-115px 0px 0px -112px; /* offset vertical: half of image height and text area height */
|
||||
/* offset horizontal: half of text area width */
|
||||
}
|
||||
|
||||
/* Landscape layout (with min-width) */
|
||||
@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
|
||||
.app {
|
||||
background-position:left center;
|
||||
padding:75px 0px 75px 170px; /* padding-top + padding-bottom + text area = image height */
|
||||
margin:-90px 0px 0px -198px; /* offset vertical: half of image height */
|
||||
/* offset horizontal: half of image width and text area width */
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size:24px;
|
||||
font-weight:normal;
|
||||
margin:0px;
|
||||
overflow:visible;
|
||||
padding:0px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.event {
|
||||
border-radius:4px;
|
||||
-webkit-border-radius:4px;
|
||||
color:#FFFFFF;
|
||||
font-size:12px;
|
||||
margin:0px 30px;
|
||||
padding:2px 0px;
|
||||
}
|
||||
|
||||
.event.listening {
|
||||
background-color:#333333;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.event.received {
|
||||
background-color:#4B946A;
|
||||
display:none;
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
from { opacity: 1.0; }
|
||||
50% { opacity: 0.4; }
|
||||
to { opacity: 1.0; }
|
||||
}
|
||||
|
||||
@-webkit-keyframes fade {
|
||||
from { opacity: 1.0; }
|
||||
50% { opacity: 0.4; }
|
||||
to { opacity: 1.0; }
|
||||
}
|
||||
|
||||
.blink {
|
||||
animation:fade 3000ms infinite;
|
||||
-webkit-animation:fade 3000ms infinite;
|
||||
}
|
||||
BIN
bin/templates/project/assets/www/img/cordova.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
bin/templates/project/assets/www/img/logo.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
42
bin/templates/project/assets/www/index.html
Normal file
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
|
||||
<link rel="stylesheet" type="text/css" href="css/index.css" />
|
||||
<title>Hello World</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<h1>Apache Cordova</h1>
|
||||
<div id="deviceready" class="blink">
|
||||
<p class="event listening">Connecting to Device</p>
|
||||
<p class="event received">Device is Ready</p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="cordova.js"></script>
|
||||
<script type="text/javascript" src="js/index.js"></script>
|
||||
<script type="text/javascript">
|
||||
app.initialize();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
49
bin/templates/project/assets/www/js/index.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
var app = {
|
||||
// Application Constructor
|
||||
initialize: function() {
|
||||
this.bindEvents();
|
||||
},
|
||||
// Bind Event Listeners
|
||||
//
|
||||
// Bind any events that are required on startup. Common events are:
|
||||
// 'load', 'deviceready', 'offline', and 'online'.
|
||||
bindEvents: function() {
|
||||
document.addEventListener('deviceready', this.onDeviceReady, false);
|
||||
},
|
||||
// deviceready Event Handler
|
||||
//
|
||||
// The scope of 'this' is the event. In order to call the 'receivedEvent'
|
||||
// function, we must explicity call 'app.receivedEvent(...);'
|
||||
onDeviceReady: function() {
|
||||
app.receivedEvent('deviceready');
|
||||
},
|
||||
// Update DOM on a Received Event
|
||||
receivedEvent: function(id) {
|
||||
var parentElement = document.getElementById(id);
|
||||
var listeningElement = parentElement.querySelector('.listening');
|
||||
var receivedElement = parentElement.querySelector('.received');
|
||||
|
||||
listeningElement.setAttribute('style', 'display:none;');
|
||||
receivedElement.setAttribute('style', 'display:block;');
|
||||
|
||||
console.log('Received Event: ' + id);
|
||||
}
|
||||
};
|
||||
@@ -1,58 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
#
|
||||
# create a cordova/android project
|
||||
#
|
||||
# USAGE
|
||||
# ./create [path package activity]
|
||||
#
|
||||
|
||||
# load up the config
|
||||
. ./.cordova/config
|
||||
|
||||
PACKAGE_AS_PATH=$(echo $PACKAGE | sed 's/\./\//g')
|
||||
ACTIVITY_PATH=./src/$PACKAGE_AS_PATH/$ACTIVITY.java
|
||||
MANIFEST_PATH=./AndroidManifest.xml
|
||||
|
||||
# create the project
|
||||
android create project --target $TARGET --path . --package $PACKAGE --activity $ACTIVITY
|
||||
|
||||
# copy all the cordova scripts etc in there
|
||||
cp -R ./cordova/templates/project/* .
|
||||
|
||||
# copy in cordova.js
|
||||
cp ./.cordova/android/cordova-$VERSION.js ./assets/www
|
||||
|
||||
# copy in cordova.jar
|
||||
cp ./.cordova/android/cordova-$VERSION.jar ./libs
|
||||
|
||||
# copy in res/xml
|
||||
mkdir ./res/xml
|
||||
cp ./.cordova/android/cordova.xml ./res/xml
|
||||
cp ./.cordova/android/plugins.xml ./res/xml
|
||||
|
||||
# copy in default activity
|
||||
cat ./cordova/templates/Activity.java > $ACTIVITY_PATH
|
||||
|
||||
# interpolate the acivity name and package
|
||||
find "$ACTIVITY_PATH" | xargs grep '__ACTIVITY__' -sl | xargs -L1 sed -i -e "s/__ACTIVITY__/${ACTIVITY}/g"
|
||||
find "$ACTIVITY_PATH" | xargs grep '__ID__' -sl | xargs -L1 sed -i -e "s/__ID__/${PACKAGE}/g"
|
||||
|
||||
find "$MANIFEST_PATH" | xargs grep '__ACTIVITY__' -sl | xargs -L1 sed -i -e "s/__ACTIVITY__/${ACTIVITY}/g"
|
||||
find "$MANIFEST_PATH" | xargs grep '__PACKAGE__' -sl | xargs -L1 sed -i -e "s/__PACKAGE__/${PACKAGE}/g"
|
||||
@@ -1,2 +0,0 @@
|
||||
echo "BALLS"
|
||||
cscript cordova\create.js
|
||||
69
bin/templates/project/cordova/create.js
vendored
@@ -1,69 +0,0 @@
|
||||
var shell=WScript.CreateObject("WScript.Shell");
|
||||
|
||||
function exec(s, output) {
|
||||
WScript.Echo('Executing ' + s);
|
||||
var o=shell.Exec(s);
|
||||
while (o.Status == 0) {
|
||||
WScript.Sleep(100);
|
||||
}
|
||||
WScript.Echo("Command exited with code " + o.Status);
|
||||
}
|
||||
function read(filename) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 1);
|
||||
var s=f.ReadAll();
|
||||
f.Close();
|
||||
return s;
|
||||
}
|
||||
function write(filename, contents) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 2, true);
|
||||
f.Write(contents);
|
||||
f.Close();
|
||||
}
|
||||
function replaceInFile(filename, regexp, replacement) {
|
||||
write(filename, read(filename).replace(regexp, replacement));
|
||||
}
|
||||
|
||||
// working dir
|
||||
var PWD = WScript.ScriptFullName.split('\\cordova\\create.js').join('');
|
||||
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(PWD + '\\.cordova\\config', 1);
|
||||
while (!f.AtEndOfStream) {
|
||||
var prop = f.ReadLine().split('=');
|
||||
var line = 'var ' + prop[0] + '=' + "'" + prop[1] + "';";
|
||||
eval(line); // hacky shit to load config but whatevs
|
||||
}
|
||||
|
||||
var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
|
||||
var ACTIVITY_PATH=PWD+'\\src\\'+PACKAGE_AS_PATH+'\\'+ACTIVITY+'.java';
|
||||
var MANIFEST_PATH=PWD+'\\AndroidManifest.xml';
|
||||
|
||||
exec('android.bat create project --target ' + TARGET + ' --path ' + PWD + ' --package ' + PACKAGE + ' --activity ' + ACTIVITY);
|
||||
|
||||
// copy in activity and other android assets
|
||||
exec('cmd /c xcopy ' + PWD + '\\cordova\\templates\\project\\* ' + PWD +' /Y /S');
|
||||
|
||||
// copy in cordova.js
|
||||
exec('cmd /c copy ' + PWD + '\\.cordova\\android\\cordova-' + VERSION + '.js ' + PWD + '\\assets\\www /Y');
|
||||
|
||||
// copy in cordova.jar
|
||||
exec('cmd /c copy ' + PWD + '\\.cordova\\android\\cordova-' + VERSION + '.jar ' + PWD + '\\libs /Y');
|
||||
|
||||
// copy in res/xml
|
||||
exec('cmd /c md ' + PWD + '\\res\\xml');
|
||||
exec('cmd /c copy ' + PWD + '\\.cordova\\android\\cordova.xml ' + PWD + '\\res\\xml /Y');
|
||||
exec('cmd /c copy ' + PWD + '\\.cordova\\android\\plugins.xml ' + PWD + '\\res\\xml /Y');
|
||||
|
||||
// copy in default activity
|
||||
exec('cmd /c copy ' + PWD + '\\cordova\\templates\\Activity.java ' + ACTIVITY_PATH + ' /Y');
|
||||
|
||||
// interpolate the activity name and package
|
||||
replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||
replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
|
||||
|
||||
replaceInFile(MANIFEST_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||
replaceInFile(MANIFEST_PATH, /__PACKAGE__/, PACKAGE);
|
||||
|
||||
WScript.Echo('Create completed successfully.');
|
||||
@@ -1,27 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
#
|
||||
|
||||
. ./.cordova/config
|
||||
|
||||
# if there are no devices listed then emulate
|
||||
|
||||
ant clean
|
||||
ant debug install
|
||||
adb shell am start -n $PACKAGE/$PACKAGE.$ACTIVITY
|
||||
@@ -1,31 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
#Available Android Virtual Devices:
|
||||
# Name: default
|
||||
# Path: /Users/davejohnson/.android/avd/default.avd
|
||||
# Target: Android 2.2 (API level 8)
|
||||
# Skin: WVGA800
|
||||
# Sdcard: 100M
|
||||
|
||||
# get the name of the first virtual device or use command line arg or use "default"
|
||||
|
||||
emulator -cpu-delay 0 -no-boot-anim -cache ./tmp/cache -avd default > /dev/null 2>&1 & # put the avd's chatty ass in the background
|
||||
@@ -1,21 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
#
|
||||
|
||||
adb logcat
|
||||
@@ -1,60 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=320; user-scalable=no" />
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>PhoneGap</title>
|
||||
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title">
|
||||
<script type="text/javascript" charset="utf-8" src="cordova-1.8.0.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="main.js"></script>
|
||||
|
||||
</head>
|
||||
<body onload="init();" id="stage" class="theme">
|
||||
<h1>Welcome to Cordova!</h1>
|
||||
<h2>this file is located at assets/www/index.html</h2>
|
||||
<div id="info">
|
||||
<h4>Platform: <span id="platform"> </span>, Version: <span id="version"> </span></h4>
|
||||
<h4>UUID: <span id="uuid"> </span>, Name: <span id="name"> </span></h4>
|
||||
<h4>Width: <span id="width"> </span>, Height: <span id="height">
|
||||
</span>, Color Depth: <span id="colorDepth"></span></h4>
|
||||
</div>
|
||||
<dl id="accel-data">
|
||||
<dt>X:</dt><dd id="x"> </dd>
|
||||
<dt>Y:</dt><dd id="y"> </dd>
|
||||
<dt>Z:</dt><dd id="z"> </dd>
|
||||
</dl>
|
||||
<a href="#" class="btn large" onclick="toggleAccel();">Toggle Accelerometer</a>
|
||||
<a href="#" class="btn large" onclick="getLocation();">Get Location</a>
|
||||
<a href="tel:411" class="btn large">Call 411</a>
|
||||
<a href="#" class="btn large" onclick="beep();">Beep</a>
|
||||
<a href="#" class="btn large" onclick="vibrate();">Vibrate</a>
|
||||
<a href="#" class="btn large" onclick="show_pic();">Get a Picture</a>
|
||||
<a href="#" class="btn large" onclick="get_contacts();return false;">Get Phone's Contacts</a>
|
||||
<a href="#" class="btn large" onclick="check_network();return false;">Check Network</a>
|
||||
<dl>
|
||||
<dt>Compass Heading:</dt><dd id="h">Off</dd>
|
||||
</dl>
|
||||
<a href="#" class="btn large" onclick="toggleCompass();return false;">Toggle Compass</a>
|
||||
<div id="viewport" class="viewport" style="display: none;">
|
||||
<img style="width:60px;height:60px" id="test_img" src="" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
|
||||
exports['you are sane'] = (test) ->
|
||||
test.expect 1
|
||||
test.ok true, "this assertion should always pass"
|
||||
test.done()
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
util = require 'util'
|
||||
exec = require('child_process').exec
|
||||
path = require 'path'
|
||||
|
||||
exports['default example project is generated'] = (test) ->
|
||||
test.expect 1
|
||||
exec './bin/create', (error, stdout, stderr) ->
|
||||
test.ok true, "this assertion should pass" unless error?
|
||||
test.done()
|
||||
|
||||
exports['default example project has a ./.cordova folder'] = (test) ->
|
||||
test.expect 1
|
||||
path.exists './example/.cordova', (exists) ->
|
||||
test.ok exists, 'the cordova folder exists'
|
||||
test.done()
|
||||
|
||||
exports['default example project has a /cordova folder'] = (test) ->
|
||||
test.expect 1
|
||||
path.exists './example/cordova', (exists) ->
|
||||
test.ok exists, 'the other cordova folder exists'
|
||||
test.done()
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
152
bin/tests/test_create_unix.js
Normal file
@@ -0,0 +1,152 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
var build_path = __dirname + '/../..',
|
||||
project_path = '/tmp/example',
|
||||
package_name = 'org.apache.cordova.example',
|
||||
package_as_path = 'org/apache/cordova/example',
|
||||
project_name = 'cordovaExample';
|
||||
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
util = require('util'),
|
||||
assert = require('assert'),
|
||||
spawn = require('child_process').spawn;
|
||||
|
||||
var version = fs.readFileSync(build_path + '/VERSION').toString().replace('\n', '');
|
||||
|
||||
assert(version !== undefined);
|
||||
assert(version !== '');
|
||||
|
||||
var create_project = spawn(build_path + '/bin/create',
|
||||
[project_path,
|
||||
package_name,
|
||||
project_name]);
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
console.log('Caught exception: ' + err);
|
||||
spawn('rm', ['-rf', project_path], function(code) {
|
||||
if(code != 0) {
|
||||
console.log("Could not delete project directory");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
create_project.on('exit', function(code) {
|
||||
|
||||
assert.equal(code, 0, 'Project did not get created');
|
||||
|
||||
// make sure the project was created
|
||||
path.exists(project_path, function(exists) {
|
||||
assert(exists, 'Project path does not exist');
|
||||
});
|
||||
|
||||
// make sure the build directory was cleaned up
|
||||
// path.exists(build_path + '/framework/libs', function(exists) {
|
||||
// assert(!exists, 'libs directory did not get cleaned up');
|
||||
// });
|
||||
path.exists(build_path + util.format('/framework/assets/cordova-%s.js', version), function(exists) {
|
||||
assert(!exists, 'javascript file did not get cleaned up');
|
||||
});
|
||||
path.exists(build_path + util.format('/framework/cordova-%s.jar', version), function(exists) {
|
||||
assert(!exists, 'jar file did not get cleaned up');
|
||||
});
|
||||
|
||||
// make sure AndroidManifest.xml was added
|
||||
path.exists(util.format('%s/AndroidManifest.xml', project_path), function(exists) {
|
||||
assert(exists, 'AndroidManifest.xml did not get created');
|
||||
// TODO check that the activity name was properly substituted
|
||||
});
|
||||
|
||||
// make sure main Activity was added
|
||||
path.exists(util.format('%s/src/%s/%s.java', project_path, package_as_path, project_name), function(exists) {
|
||||
assert(exists, 'Activity did not get created');
|
||||
// TODO check that package name and activity name were substituted properly
|
||||
});
|
||||
|
||||
// make sure plugins.xml was added
|
||||
path.exists(util.format('%s/res/xml/plugins.xml', project_path), function(exists) {
|
||||
assert(exists, 'plugins.xml did not get created');
|
||||
});
|
||||
|
||||
// make sure cordova.xml was added
|
||||
path.exists(util.format('%s/res/xml/cordova.xml', project_path), function(exists) {
|
||||
assert(exists, 'plugins.xml did not get created');
|
||||
});
|
||||
|
||||
// make sure cordova.jar was added
|
||||
path.exists(util.format('%s/libs/cordova-%s.jar', project_path, version), function(exists) {
|
||||
assert(exists, 'cordova.jar did not get added');
|
||||
});
|
||||
|
||||
// make sure cordova.js was added
|
||||
path.exists(util.format('%s/assets/www/cordova-%s.js', project_path, version), function(exists) {
|
||||
assert(exists, 'cordova.js did not get added');
|
||||
});
|
||||
|
||||
// make sure cordova master script was added
|
||||
path.exists(util.format('%s/cordova/cordova', project_path), function(exists) {
|
||||
assert(exists, 'cordova script did not get added');
|
||||
});
|
||||
|
||||
// make sure debug script was added
|
||||
path.exists(util.format('%s/cordova/debug', project_path), function(exists) {
|
||||
assert(exists, 'debug script did not get added');
|
||||
});
|
||||
|
||||
// make sure BOOM script was added
|
||||
path.exists(util.format('%s/cordova/BOOM', project_path), function(exists) {
|
||||
assert(exists, 'BOOM script did not get added');
|
||||
});
|
||||
|
||||
// make sure log script was added
|
||||
path.exists(util.format('%s/cordova/log', project_path), function(exists) {
|
||||
assert(exists, 'log script did not get added');
|
||||
});
|
||||
|
||||
// make sure clean script was added
|
||||
path.exists(util.format('%s/cordova/clean', project_path), function(exists) {
|
||||
assert(exists, 'clean script did not get added');
|
||||
});
|
||||
|
||||
// make sure emulate script was added
|
||||
path.exists(util.format('%s/cordova/emulate', project_path), function(exists) {
|
||||
assert(exists, 'emulate script did not get added');
|
||||
});
|
||||
|
||||
// make sure appinfo.jar script was added
|
||||
path.exists(util.format('%s/cordova/appinfo.jar', project_path), function(exists) {
|
||||
assert(exists, 'appinfo.jar script did not get added');
|
||||
});
|
||||
|
||||
// check that project compiles && creates a cordovaExample-debug.apk
|
||||
var compile_project = spawn('ant', ['debug'], {cwd: project_path});
|
||||
|
||||
compile_project.on('exit', function(code) {
|
||||
assert.equal(code, 0, 'Cordova Android Project does not compile');
|
||||
// make sure cordovaExample-debug.apk was created
|
||||
path.exists(util.format('%s/bin/%s-debug.apk', project_path, project_name), function(exists) {
|
||||
assert(exists, 'Package did not get created');
|
||||
|
||||
// if project compiles properly just AXE it
|
||||
spawn('rm', ['-rf', project_path], function(code) {
|
||||
assert.equal(code, 0, 'Could not remove project directory');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
155
bin/tests/test_create_win.js
Normal file
@@ -0,0 +1,155 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
var build_path = __dirname + '/../..'
|
||||
project_path = process.env.Temp + '\\example',
|
||||
package_name = 'org.apache.cordova.example',
|
||||
package_as_path = 'org/apache/cordova/example',
|
||||
project_name = 'cordovaExample';
|
||||
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
util = require('util'),
|
||||
assert = require('assert'),
|
||||
exec = require('child_process').exec,
|
||||
spawn = require('child_process').spawn;
|
||||
|
||||
var version = fs.readFileSync(build_path + '/VERSION').toString().replace('\r\n', '');
|
||||
|
||||
assert(version !== undefined);
|
||||
assert(version !== '');
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
console.log('Caught exception: ' + err);
|
||||
exec('rd /s /q ' + project_path);
|
||||
});
|
||||
|
||||
var create_project = spawn('cscript',
|
||||
[build_path + '/bin/create.js',
|
||||
project_path,
|
||||
package_name,
|
||||
project_name]
|
||||
);
|
||||
|
||||
create_project.stderr.on('data', function (data) {
|
||||
console.log('ps stderr: ' + data);
|
||||
});
|
||||
|
||||
create_project.stderr.on('data', function(data) {
|
||||
console.log(data.toString());
|
||||
});
|
||||
|
||||
create_project.stdout.on('data', function(data) {
|
||||
console.log(data.toString());
|
||||
});
|
||||
|
||||
create_project.on('exit', function(code) {
|
||||
assert.equal(code, 0, 'Project did not get created');
|
||||
|
||||
// make sure the project was created
|
||||
path.exists(project_path, function(exists) {
|
||||
assert(exists, 'Project path does not exist');
|
||||
});
|
||||
|
||||
// make sure the build directory was cleaned up
|
||||
// path.exists(build_path + '/framework/libs', function(exists) {
|
||||
// assert(!exists, 'libs directory did not get cleaned up');
|
||||
// });
|
||||
path.exists(build_path + util.format('/framework/assets/cordova-%s.js', version), function(exists) {
|
||||
assert(!exists, 'javascript file did not get cleaned up');
|
||||
});
|
||||
path.exists(build_path + util.format('/framework/cordova-%s.jar', version), function(exists) {
|
||||
assert(!exists, 'jar file did not get cleaned up');
|
||||
});
|
||||
|
||||
// make sure AndroidManifest.xml was added
|
||||
path.exists(util.format('%s/AndroidManifest.xml', project_path), function(exists) {
|
||||
assert(exists, 'AndroidManifest.xml did not get created');
|
||||
// TODO check that the activity name was properly substituted
|
||||
});
|
||||
|
||||
// make sure main Activity was added
|
||||
path.exists(util.format('%s/src/%s/%s.java', project_path, package_as_path, project_name), function(exists) {
|
||||
assert(exists, 'Activity did not get created');
|
||||
// TODO check that package name and activity name were substituted properly
|
||||
});
|
||||
|
||||
// make sure config.xml was added
|
||||
path.exists(util.format('%s/res/xml/config.xml', project_path), function(exists) {
|
||||
assert(exists, 'config.xml did not get created');
|
||||
});
|
||||
|
||||
// make sure cordova.jar was added
|
||||
path.exists(util.format('%s/libs/cordova-%s.jar', project_path, version), function(exists) {
|
||||
assert(exists, 'cordova.jar did not get added');
|
||||
});
|
||||
|
||||
// make sure cordova.js was added
|
||||
path.exists(util.format('%s/assets/www/cordova-%s.js', project_path, version), function(exists) {
|
||||
assert(exists, 'cordova.js did not get added');
|
||||
});
|
||||
|
||||
// make sure cordova master script was added
|
||||
path.exists(util.format('%s/cordova/cordova.bat', project_path), function(exists) {
|
||||
assert(exists, 'cordova script did not get added');
|
||||
});
|
||||
|
||||
// make sure debug script was added
|
||||
path.exists(util.format('%s/cordova/debug.bat', project_path), function(exists) {
|
||||
assert(exists, 'debug script did not get added');
|
||||
});
|
||||
|
||||
// make sure BOOM script was added
|
||||
path.exists(util.format('%s/cordova/BOOM.bat', project_path), function(exists) {
|
||||
assert(exists, 'BOOM script did not get added');
|
||||
});
|
||||
|
||||
// make sure log script was added
|
||||
path.exists(util.format('%s/cordova/log.bat', project_path), function(exists) {
|
||||
assert(exists, 'log script did not get added');
|
||||
});
|
||||
|
||||
// make sure clean script was added
|
||||
path.exists(util.format('%s/cordova/clean.bat', project_path), function(exists) {
|
||||
assert(exists, 'clean script did not get added');
|
||||
});
|
||||
|
||||
// make sure emulate script was added
|
||||
path.exists(util.format('%s/cordova/emulate.bat', project_path), function(exists) {
|
||||
assert(exists, 'emulate script did not get added');
|
||||
});
|
||||
|
||||
// make sure appinfo.jar script was added
|
||||
path.exists(util.format('%s/cordova/appinfo.jar', project_path), function(exists) {
|
||||
assert(exists, 'appinfo.jar script did not get added');
|
||||
});
|
||||
|
||||
// check that project compiles && creates a cordovaExample-debug.apk
|
||||
// XXX: !@##!@# WINDOWS
|
||||
exec('ant debug -f ' + project_path + "\\build.xml", function(error, stdout, stderr) {
|
||||
assert(error == null, "Cordova Android Project does not compile");
|
||||
path.exists(util.format('%s/bin/%s-debug.apk', project_path, project_name),
|
||||
function(exists) {
|
||||
assert(exists, 'Package did not get created');
|
||||
// if project compiles properly just AXE it
|
||||
exec('rd /s /q ' + project_path);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
133
bin/update
Executable file
@@ -0,0 +1,133 @@
|
||||
#! /bin/bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
# update a cordova/android project's command line tools
|
||||
#
|
||||
# USAGE
|
||||
# ./update [path]
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$1" ] || [ "$1" == "-h" ]
|
||||
then
|
||||
echo 'usage: update path'
|
||||
echo "Make sure the Android SDK tools folder is in your PATH!"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
BUILD_PATH="$( cd "$( dirname "$0" )/.." && pwd )"
|
||||
VERSION=$(cat "$BUILD_PATH"/VERSION)
|
||||
|
||||
PROJECT_PATH="${1:-'./example'}"
|
||||
|
||||
if [ ! -d "$PROJECT_PATH" ]
|
||||
then
|
||||
echo "The project path has to exist for it to be updated"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
# cleanup after exit and/or on error
|
||||
function on_exit {
|
||||
if [ -f "$BUILD_PATH"/framework/cordova-$VERSION.jar ]
|
||||
then
|
||||
rm "$BUILD_PATH"/framework/cordova-$VERSION.jar
|
||||
fi
|
||||
}
|
||||
|
||||
function createAppInfoJar {
|
||||
(cd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo &&
|
||||
javac ApplicationInfo.java &&
|
||||
jar -cfe ../appinfo.jar ApplicationInfo ApplicationInfo.class
|
||||
)
|
||||
}
|
||||
|
||||
function on_error {
|
||||
echo "An unexpected error occurred: $previous_command exited with $?"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function replace {
|
||||
local pattern=$1
|
||||
local filename=$2
|
||||
# Mac OS X requires -i argument
|
||||
if [[ "$OSTYPE" =~ "darwin" ]]
|
||||
then
|
||||
/usr/bin/sed -i '' -e $pattern "$filename"
|
||||
elif [[ "$OSTYPE" =~ "linux" ]]
|
||||
then
|
||||
/bin/sed -i -e $pattern "$filename"
|
||||
fi
|
||||
}
|
||||
|
||||
# we do not want the script to silently fail
|
||||
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
|
||||
trap on_error ERR
|
||||
trap on_exit EXIT
|
||||
|
||||
ANDROID_BIN="${ANDROID_BIN:=$( which android )}"
|
||||
|
||||
TARGET=$("$ANDROID_BIN" list targets | grep id: | tail -1 | cut -f 2 -d ' ' )
|
||||
API_LEVEL=$("$ANDROID_BIN" list target | grep "API level:" | tail -n 1 | cut -f 2 -d ':' | tr -d ' ')
|
||||
|
||||
# check that build targets exist
|
||||
if [ -z "$TARGET" ] || [ -z "$API_LEVEL" ]
|
||||
then
|
||||
echo "No Android Targets are installed. Please install at least one via the android SDK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# if this a distribution release no need to build a jar
|
||||
if [ ! -e "$BUILD_PATH"/cordova-$VERSION.jar ] && [ -d "$BUILD_PATH"/framework ]
|
||||
then
|
||||
# update the cordova-android framework for the desired target
|
||||
"$ANDROID_BIN" update project --target $TARGET --path "$BUILD_PATH"/framework &> /dev/null
|
||||
|
||||
# compile cordova.js and cordova.jar
|
||||
(cd "$BUILD_PATH"/framework && ant jar &> /dev/null )
|
||||
fi
|
||||
|
||||
# copy cordova.js, cordova.jar and res/xml
|
||||
if [ -d "$BUILD_PATH"/framework ]
|
||||
then
|
||||
cp "$BUILD_PATH"/framework/assets/www/cordova.js "$PROJECT_PATH"/assets/www/cordova.js
|
||||
cp "$BUILD_PATH"/framework/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
|
||||
else
|
||||
cp "$BUILD_PATH"/cordova.js "$PROJECT_PATH"/assets/www/cordova.js
|
||||
cp "$BUILD_PATH"/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
|
||||
fi
|
||||
|
||||
# creating cordova folder and copying run/build/log/launch scripts
|
||||
if [ ! -e "$PROJECT_PATH/cordova" ]
|
||||
then
|
||||
mkdir "$PROJECT_PATH"/cordova
|
||||
mkdir "$PROJECT_PATH"/cordova/lib
|
||||
fi
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/appinfo.jar "$PROJECT_PATH"/cordova/appinfo.jar
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/build "$PROJECT_PATH"/cordova/build
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/clean "$PROJECT_PATH"/cordova/clean
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/log "$PROJECT_PATH"/cordova/log
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/run "$PROJECT_PATH"/cordova/run
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/cordova.js "$PROJECT_PATH"/cordova/lib/cordova.js
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/install-device "$PROJECT_PATH"/cordova/lib/install-device
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/install-emulator "$PROJECT_PATH"/cordova/lib/install-emulator
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/list-devices "$PROJECT_PATH"/cordova/lib/list-devices
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/list-emulator-images "$PROJECT_PATH"/cordova/lib/list-emulator-images
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/list-started-emulators "$PROJECT_PATH"/cordova/lib/list-started-emulators
|
||||
cp "$BUILD_PATH"/bin/templates/cordova/lib/start-emulator "$PROJECT_PATH"/cordova/lib/start-emulator
|
||||
32
bin/update.bat
Normal file
@@ -0,0 +1,32 @@
|
||||
:: Licensed to the Apache Software Foundation (ASF) under one
|
||||
:: or more contributor license agreements. See the NOTICE file
|
||||
:: distributed with this work for additional information
|
||||
:: regarding copyright ownership. The ASF licenses this file
|
||||
:: to you 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.
|
||||
|
||||
@ECHO OFF
|
||||
IF NOT DEFINED JAVA_HOME GOTO MISSING
|
||||
FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
|
||||
SET FOUND=%%~$PATH:X
|
||||
IF NOT DEFINED FOUND GOTO MISSING
|
||||
)
|
||||
cscript "%~dp0\update.js" %*
|
||||
GOTO END
|
||||
:MISSING
|
||||
ECHO Missing one of the following:
|
||||
ECHO JDK: http://java.oracle.com
|
||||
ECHO Android SDK: http://developer.android.com
|
||||
ECHO Apache ant: http://ant.apache.org
|
||||
EXIT /B 1
|
||||
:END
|
||||
157
bin/update.js
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* create a cordova/android project
|
||||
*
|
||||
* USAGE
|
||||
* ./update [path]
|
||||
*/
|
||||
|
||||
var fso = WScript.CreateObject('Scripting.FileSystemObject');
|
||||
|
||||
function read(filename) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 1);
|
||||
var s=f.ReadAll();
|
||||
f.Close();
|
||||
return s;
|
||||
}
|
||||
|
||||
function checkTargets(targets) {
|
||||
if(!targets) {
|
||||
WScript.Echo("You do not have any android targets setup. Please create at least one target with the `android` command");
|
||||
WScript.Quit(69);
|
||||
}
|
||||
}
|
||||
|
||||
function setTarget() {
|
||||
var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s\d+/g);
|
||||
checkTargets(targets);
|
||||
return targets[targets.length - 1].replace(/id: /, ""); // TODO: give users the option to set their target
|
||||
}
|
||||
|
||||
function setApiLevel() {
|
||||
var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/API level:\s\d+/g);
|
||||
checkTargets(targets);
|
||||
return targets[targets.length - 1].replace(/API level: /, "");
|
||||
}
|
||||
|
||||
function write(filename, contents) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 2, true);
|
||||
f.Write(contents);
|
||||
f.Close();
|
||||
}
|
||||
|
||||
function replaceInFile(filename, regexp, replacement) {
|
||||
write(filename, read(filename).replace(regexp, replacement));
|
||||
}
|
||||
|
||||
function exec(command) {
|
||||
var oShell=shell.Exec(command);
|
||||
while (oShell.Status == 0) {
|
||||
if(!oShell.StdOut.AtEndOfStream) {
|
||||
var line = oShell.StdOut.ReadLine();
|
||||
// XXX: Change to verbose mode
|
||||
// WScript.StdOut.WriteLine(line);
|
||||
}
|
||||
WScript.sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
function createAppInfoJar() {
|
||||
if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
|
||||
WScript.Echo("Creating appinfo.jar...");
|
||||
var cur = shell.CurrentDirectory;
|
||||
shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
|
||||
exec("javac ApplicationInfo.java");
|
||||
exec("jar -cfe ..\\appinfo.jar ApplicationInfo ApplicationInfo.class");
|
||||
shell.CurrentDirectory = cur;
|
||||
}
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
if(fso.FileExists(ROOT + '\\framework\\cordova-'+VERSION+'.jar')) {
|
||||
fso.DeleteFile(ROOT + '\\framework\\cordova-'+VERSION+'.jar');
|
||||
}
|
||||
if(fso.FileExists(ROOT + '\\framework\\assets\\www\\cordova-'+VERSION+'.js')) {
|
||||
fso.DeleteFile(ROOT + '\\framework\\assets\\www\\cordova-'+VERSION+'.js');
|
||||
}
|
||||
}
|
||||
|
||||
var args = WScript.Arguments, PROJECT_PATH="example",
|
||||
shell=WScript.CreateObject("WScript.Shell");
|
||||
|
||||
// working dir
|
||||
var ROOT = WScript.ScriptFullName.split('\\bin\\update.js').join('');
|
||||
|
||||
if (args.Count() == 1) {
|
||||
PROJECT_PATH=args(0);
|
||||
}
|
||||
|
||||
if(!fso.FolderExists(PROJECT_PATH)) {
|
||||
WScript.Echo("Project doesn't exist!");
|
||||
WScript.Quit(1);
|
||||
}
|
||||
|
||||
var TARGET=setTarget();
|
||||
var API_LEVEL=setApiLevel();
|
||||
var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
|
||||
|
||||
// build from source. distro should have these files
|
||||
if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
|
||||
!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.js')) {
|
||||
WScript.Echo("Building jar and js files...");
|
||||
// update the cordova framework project to a target that exists on this machine
|
||||
exec('android.bat update project --target '+TARGET+' --path '+ROOT+'\\framework');
|
||||
exec('ant.bat -f \"'+ ROOT +'\\framework\\build.xml\" jar');
|
||||
}
|
||||
|
||||
// check if we have the source or the distro files
|
||||
WScript.Echo("Copying js, jar & config.xml files...");
|
||||
if(fso.FolderExists(ROOT + '\\framework')) {
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\framework\\assets\\www\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
|
||||
} else {
|
||||
// copy in cordova.js
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
|
||||
// copy in cordova.jar
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
|
||||
// copy in xml
|
||||
}
|
||||
|
||||
// update cordova scripts
|
||||
createAppInfoJar();
|
||||
WScript.Echo("Copying cordova command tools...");
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\appinfo.jar ' + PROJECT_PATH + '\\cordova\\appinfo.jar /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.bat ' + PROJECT_PATH + '\\cordova\\cordova.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\clean.bat ' + PROJECT_PATH + '\\cordova\\clean.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\build.bat ' + PROJECT_PATH + '\\cordova\\build.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\log.bat ' + PROJECT_PATH + '\\cordova\\log.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\run.bat ' + PROJECT_PATH + '\\cordova\\run.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\cordova.js ' + PROJECT_PATH + '\\cordova\\lib\\cordova.js /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-device.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-device.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-emulator.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-emulator-images.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-emulator-images.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-devices.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-devices.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-started-emulators.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-started-emulators.bat /Y');
|
||||
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\start-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\start-emulator.bat /Y');
|
||||
|
||||
cleanup();
|
||||
@@ -3,6 +3,6 @@
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="lib" path="libs/commons-codec-1.6.jar"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
||||
package="org.apache.cordova" android:versionName="1.1" android:versionCode="5">
|
||||
package="org.apache.cordova" android:versionName="1.0" android:versionCode="1">
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
@@ -50,19 +50,14 @@
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||
android:debuggable="true">
|
||||
<activity android:name=".StandAlone" android:windowSoftInputMode="adjustPan"
|
||||
android:label="@string/app_name" android:configChanges="orientation|keyboardHidden">
|
||||
<activity android:name="org.apache.cordova.DroidGap" android:label="@string/app_name"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="org.apache.cordova.DroidGap" android:label="@string/app_name"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<intent-filter>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="2" />
|
||||
<uses-sdk android:minSdkVersion="7" />
|
||||
</manifest>
|
||||
|
||||
7026
framework/assets/www/cordova.js
vendored
Normal file
@@ -19,7 +19,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="cordova-1.8.0.js"></script>
|
||||
<script src="cordova.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@@ -26,9 +26,20 @@
|
||||
</filterchain>
|
||||
</loadfile>
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<!-- check that the version of ant is at least 1.8.0 -->
|
||||
<antversion property="thisantversion" atleast="1.8.0" />
|
||||
<fail message="The required minimum version of ant is 1.8.0, you have ${ant.version}"
|
||||
unless="thisantversion" />
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android'
|
||||
tool. (For example "sdkdir/tools/android update project -p ." inside
|
||||
of this directory where the AndroidManifest.xml file exists. This
|
||||
properties file that gets built contains the path to the SDK. It
|
||||
should *NOT* be checked into Version Control Systems since it holds
|
||||
data about the local machine. -->
|
||||
<available file="local.properties" property="exists.local.properties" />
|
||||
<fail message="You need to create the file 'local.properties' by running 'android update project -p .' here."
|
||||
unless="exists.local.properties" />
|
||||
<loadproperties srcFile="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
@@ -52,9 +63,6 @@
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- We need to setup the double quote. -->
|
||||
<property name="dblQuote">"</property>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
@@ -66,13 +74,13 @@
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<!-- version-tag: custom -->
|
||||
<!-- version-tag: custom -->
|
||||
<!-- extension targets. Uncomment the ones where you want to do custom work
|
||||
in between standard targets -->
|
||||
<!--
|
||||
@@ -106,35 +114,12 @@
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
<!-- Combine JavaScript files into one cordova-uncompressed.js file. -->
|
||||
<target name="build-javascript" depends="clean">
|
||||
|
||||
<!-- Clean up existing files -->
|
||||
<!--<delete file="assets/www/cordova_${version}.js"/>-->
|
||||
|
||||
<!-- Create uncompressed JS file -->
|
||||
<concat destfile="assets/www/cordova-${version}.js">
|
||||
<filelist dir="assets/js" files="cordova.android.js"/>
|
||||
</concat>
|
||||
|
||||
<!-- update project files to reference cordova-x.x.x.min.js -->
|
||||
<replaceregexp match="cordova(.*)\.js" replace="cordova-${version}.js" byline="true">
|
||||
<fileset file="assets/www/index.html" />
|
||||
<fileset file="../bin/templates/project/cordova/templates/project/assets/www/index.html" />
|
||||
</replaceregexp>
|
||||
|
||||
<!-- This is sketchy, but it works, ${dblQuote} does not -->
|
||||
<replaceregexp match="cordovaVersion = [\u0022].*[\u0022];" replace='cordovaVersion = ${dblQuote}${version}${dblQuote};' byline="true">
|
||||
<fileset file="src/org/apache/cordova/Device.java" />
|
||||
</replaceregexp>
|
||||
</target>
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
<!-- Build Cordova jar file that includes all native code, and Cordova JS file
|
||||
that includes all JavaScript code.
|
||||
-->
|
||||
<target name="jar" depends="build-javascript, -compile">
|
||||
<target name="jar" depends="-compile">
|
||||
<jar jarfile="cordova-${version}.jar" basedir="bin/classes" excludes="org/apache/cordova/R.class,org/apache/cordova/R$*.class"/>
|
||||
</target>
|
||||
|
||||
@@ -167,10 +152,10 @@
|
||||
</junit>
|
||||
</target>
|
||||
|
||||
<target name="cordova_debug" depends="build-javascript, debug">
|
||||
<target name="cordova_debug" depends="debug">
|
||||
</target>
|
||||
|
||||
<target name="cordova_release" depends="build-javascript, release">
|
||||
<target name="cordova_release" depends="release">
|
||||
</target>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -10,5 +10,7 @@
|
||||
# Indicates whether an apk should be generated for each density.
|
||||
split.density=false
|
||||
# Project target.
|
||||
target=Google Inc.:Google APIs:15
|
||||
target=Google Inc.:Google APIs:17
|
||||
apk-configurations=
|
||||
renderscript.opt.level=O0
|
||||
android.library=true
|
||||
|
||||
107
framework/res/xml/config.xml
Normal file
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<widget xmlns = "http://www.w3.org/ns/widgets"
|
||||
id = "io.cordova.helloCordova"
|
||||
version = "2.0.0">
|
||||
<name>Hello Cordova</name>
|
||||
|
||||
<description>
|
||||
A sample Apache Cordova application that responds to the deviceready event.
|
||||
</description>
|
||||
|
||||
<author href="http://cordova.io" email="dev@cordova.apache.org">
|
||||
Apache Cordova Team
|
||||
</author>
|
||||
|
||||
<access origin="*"/>
|
||||
|
||||
<!-- <content src="http://mysite.com/myapp.html" /> for external pages -->
|
||||
<content src="index.html" />
|
||||
|
||||
<preference name="loglevel" value="DEBUG" />
|
||||
<!--
|
||||
<preference name="splashscreen" value="resourceName" />
|
||||
<preference name="backgroundColor" value="0xFFF" />
|
||||
<preference name="loadUrlTimeoutValue" value="20000" />
|
||||
<preference name="InAppBrowserStorageEnabled" value="true" />
|
||||
<preference name="disallowOverscroll" value="true" />
|
||||
-->
|
||||
|
||||
<feature name="App">
|
||||
<param name="android-package" value="org.apache.cordova.App"/>
|
||||
</feature>
|
||||
<feature name="Geolocation">
|
||||
<param name="android-package" value="org.apache.cordova.GeoBroker"/>
|
||||
</feature>
|
||||
<feature name="Device">
|
||||
<param name="android-package" value="org.apache.cordova.Device"/>
|
||||
</feature>
|
||||
<feature name="Accelerometer">
|
||||
<param name="android-package" value="org.apache.cordova.AccelListener"/>
|
||||
</feature>
|
||||
<feature name="Compass">
|
||||
<param name="android-package" value="org.apache.cordova.CompassListener"/>
|
||||
</feature>
|
||||
<feature name="Media">
|
||||
<param name="android-package" value="org.apache.cordova.AudioHandler"/>
|
||||
</feature>
|
||||
<feature name="Camera">
|
||||
<param name="android-package" value="org.apache.cordova.CameraLauncher"/>
|
||||
</feature>
|
||||
<feature name="Contacts">
|
||||
<param name="android-package" value="org.apache.cordova.ContactManager"/>
|
||||
</feature>
|
||||
<feature name="File">
|
||||
<param name="android-package" value="org.apache.cordova.FileUtils"/>
|
||||
</feature>
|
||||
<feature name="NetworkStatus">
|
||||
<param name="android-package" value="org.apache.cordova.NetworkManager"/>
|
||||
</feature>
|
||||
<feature name="Notification">
|
||||
<param name="android-package" value="org.apache.cordova.Notification"/>
|
||||
</feature>
|
||||
<feature name="Storage">
|
||||
<param name="android-package" value="org.apache.cordova.Storage"/>
|
||||
</feature>
|
||||
<feature name="FileTransfer">
|
||||
<param name="android-package" value="org.apache.cordova.FileTransfer"/>
|
||||
</feature>
|
||||
<feature name="Capture">
|
||||
<param name="android-package" value="org.apache.cordova.Capture"/>
|
||||
</feature>
|
||||
<feature name="Battery">
|
||||
<param name="android-package" value="org.apache.cordova.BatteryListener"/>
|
||||
</feature>
|
||||
<feature name="SplashScreen">
|
||||
<param name="android-package" value="org.apache.cordova.SplashScreen"/>
|
||||
</feature>
|
||||
<feature name="Echo">
|
||||
<param name="android-package" value="org.apache.cordova.Echo"/>
|
||||
</feature>
|
||||
<feature name="Globalization">
|
||||
<param name="android-package" value="org.apache.cordova.Globalization"/>
|
||||
</feature>
|
||||
<feature name="InAppBrowser">
|
||||
<param name="android-package" value="org.apache.cordova.InAppBrowser"/>
|
||||
</feature>
|
||||
<!-- Deprecated plugins element. Remove in 3.0 -->
|
||||
<plugins>
|
||||
</plugins>
|
||||
</widget>
|
||||
@@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<cordova>
|
||||
<!--
|
||||
access elements control the Android whitelist.
|
||||
Domains are assumed blocked unless set otherwise
|
||||
-->
|
||||
|
||||
<access origin="http://127.0.0.1*"/> <!-- allow local pages -->
|
||||
|
||||
<!-- <access origin="https://example.com" /> allow any secure requests to example.com -->
|
||||
<!-- <access origin="https://example.com" subdomains="true" /> such as above, but including subdomains, such as www -->
|
||||
<!-- <access origin=".*"/> Allow all domains, suggested development use only -->
|
||||
|
||||
<log level="DEBUG"/>
|
||||
<preference name="classicRender" value="true" />
|
||||
</cordova>
|
||||
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
<plugins>
|
||||
<plugin name="App" value="org.apache.cordova.App"/>
|
||||
<plugin name="Geolocation" value="org.apache.cordova.GeoBroker"/>
|
||||
<plugin name="Device" value="org.apache.cordova.Device"/>
|
||||
<plugin name="Accelerometer" value="org.apache.cordova.AccelListener"/>
|
||||
<plugin name="Compass" value="org.apache.cordova.CompassListener"/>
|
||||
<plugin name="Media" value="org.apache.cordova.AudioHandler"/>
|
||||
<plugin name="Camera" value="org.apache.cordova.CameraLauncher"/>
|
||||
<plugin name="Contacts" value="org.apache.cordova.ContactManager"/>
|
||||
<plugin name="File" value="org.apache.cordova.FileUtils"/>
|
||||
<plugin name="NetworkStatus" value="org.apache.cordova.NetworkManager"/>
|
||||
<plugin name="Notification" value="org.apache.cordova.Notification"/>
|
||||
<plugin name="Storage" value="org.apache.cordova.Storage"/>
|
||||
<plugin name="Temperature" value="org.apache.cordova.TempListener"/>
|
||||
<plugin name="FileTransfer" value="org.apache.cordova.FileTransfer"/>
|
||||
<plugin name="Capture" value="org.apache.cordova.Capture"/>
|
||||
<plugin name="Battery" value="org.apache.cordova.BatteryListener"/>
|
||||
<plugin name="SplashScreen" value="org.apache.cordova.SplashScreen"/>
|
||||
</plugins>
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
/**
|
||||
* Plugin interface must be implemented by any plugin classes.
|
||||
*
|
||||
* The execute method is called by the PluginManager.
|
||||
*/
|
||||
public interface IPlugin extends org.apache.cordova.api.IPlugin {
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
/**
|
||||
* Log to Android logging system.
|
||||
*
|
||||
* Log message can be a string or a printf formatted string with arguments.
|
||||
* See http://developer.android.com/reference/java/util/Formatter.html
|
||||
*/
|
||||
public class LOG extends org.apache.cordova.api.LOG {
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* The Cordova activity abstract class that is extended by DroidGap.
|
||||
* It is used to isolate plugin development, and remove dependency on entire Cordova library.
|
||||
*/
|
||||
public abstract class PhonegapActivity extends Activity implements org.apache.cordova.api.CordovaInterface {
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
/**
|
||||
* Plugin interface must be implemented by any plugin classes.
|
||||
*
|
||||
* The execute method is called by the PluginManager.
|
||||
*/
|
||||
public abstract class Plugin extends org.apache.cordova.api.Plugin {
|
||||
}
|
||||
111
framework/src/com/squareup/okhttp/Address.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import java.net.Proxy;
|
||||
import java.net.UnknownHostException;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import static com.squareup.okhttp.internal.Util.equal;
|
||||
|
||||
/**
|
||||
* A specification for a connection to an origin server. For simple connections,
|
||||
* this is the server's hostname and port. If an explicit proxy is requested (or
|
||||
* {@link Proxy#NO_PROXY no proxy} is explicitly requested), this also includes
|
||||
* that proxy information. For secure connections the address also includes the
|
||||
* SSL socket factory and hostname verifier.
|
||||
*
|
||||
* <p>HTTP requests that share the same {@code Address} may also share the same
|
||||
* {@link Connection}.
|
||||
*/
|
||||
public final class Address {
|
||||
final Proxy proxy;
|
||||
final String uriHost;
|
||||
final int uriPort;
|
||||
final SSLSocketFactory sslSocketFactory;
|
||||
final HostnameVerifier hostnameVerifier;
|
||||
|
||||
public Address(String uriHost, int uriPort, SSLSocketFactory sslSocketFactory,
|
||||
HostnameVerifier hostnameVerifier, Proxy proxy) throws UnknownHostException {
|
||||
if (uriHost == null) throw new NullPointerException("uriHost == null");
|
||||
if (uriPort <= 0) throw new IllegalArgumentException("uriPort <= 0: " + uriPort);
|
||||
this.proxy = proxy;
|
||||
this.uriHost = uriHost;
|
||||
this.uriPort = uriPort;
|
||||
this.sslSocketFactory = sslSocketFactory;
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
}
|
||||
|
||||
/** Returns the hostname of the origin server. */
|
||||
public String getUriHost() {
|
||||
return uriHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port of the origin server; typically 80 or 443. Unlike
|
||||
* may {@code getPort()} accessors, this method never returns -1.
|
||||
*/
|
||||
public int getUriPort() {
|
||||
return uriPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SSL socket factory, or null if this is not an HTTPS
|
||||
* address.
|
||||
*/
|
||||
public SSLSocketFactory getSslSocketFactory() {
|
||||
return sslSocketFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname verifier, or null if this is not an HTTPS
|
||||
* address.
|
||||
*/
|
||||
public HostnameVerifier getHostnameVerifier() {
|
||||
return hostnameVerifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this address's explicitly-specified HTTP proxy, or null to
|
||||
* delegate to the HTTP client's proxy selector.
|
||||
*/
|
||||
public Proxy getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object other) {
|
||||
if (other instanceof Address) {
|
||||
Address that = (Address) other;
|
||||
return equal(this.proxy, that.proxy)
|
||||
&& this.uriHost.equals(that.uriHost)
|
||||
&& this.uriPort == that.uriPort
|
||||
&& equal(this.sslSocketFactory, that.sslSocketFactory)
|
||||
&& equal(this.hostnameVerifier, that.hostnameVerifier);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
int result = 17;
|
||||
result = 31 * result + uriHost.hashCode();
|
||||
result = 31 * result + uriPort;
|
||||
result = 31 * result + (sslSocketFactory != null ? sslSocketFactory.hashCode() : 0);
|
||||
result = 31 * result + (hostnameVerifier != null ? hostnameVerifier.hashCode() : 0);
|
||||
result = 31 * result + (proxy != null ? proxy.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
291
framework/src/com/squareup/okhttp/Connection.java
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.Platform;
|
||||
import com.squareup.okhttp.internal.http.HttpAuthenticator;
|
||||
import com.squareup.okhttp.internal.http.HttpEngine;
|
||||
import com.squareup.okhttp.internal.http.HttpTransport;
|
||||
import com.squareup.okhttp.internal.http.RawHeaders;
|
||||
import com.squareup.okhttp.internal.http.SpdyTransport;
|
||||
import com.squareup.okhttp.internal.spdy.SpdyConnection;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Proxy;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import static java.net.HttpURLConnection.HTTP_OK;
|
||||
import static java.net.HttpURLConnection.HTTP_PROXY_AUTH;
|
||||
|
||||
/**
|
||||
* Holds the sockets and streams of an HTTP, HTTPS, or HTTPS+SPDY connection,
|
||||
* which may be used for multiple HTTP request/response exchanges. Connections
|
||||
* may be direct to the origin server or via a proxy.
|
||||
*
|
||||
* <p>Typically instances of this class are created, connected and exercised
|
||||
* automatically by the HTTP client. Applications may use this class to monitor
|
||||
* HTTP connections as members of a {@link ConnectionPool connection pool}.
|
||||
*
|
||||
* <p>Do not confuse this class with the misnamed {@code HttpURLConnection},
|
||||
* which isn't so much a connection as a single request/response exchange.
|
||||
*
|
||||
* <h3>Modern TLS</h3>
|
||||
* There are tradeoffs when selecting which options to include when negotiating
|
||||
* a secure connection to a remote host. Newer TLS options are quite useful:
|
||||
* <ul>
|
||||
* <li>Server Name Indication (SNI) enables one IP address to negotiate secure
|
||||
* connections for multiple domain names.
|
||||
* <li>Next Protocol Negotiation (NPN) enables the HTTPS port (443) to be used
|
||||
* for both HTTP and SPDY transports.
|
||||
* </ul>
|
||||
* Unfortunately, older HTTPS servers refuse to connect when such options are
|
||||
* presented. Rather than avoiding these options entirely, this class allows a
|
||||
* connection to be attempted with modern options and then retried without them
|
||||
* should the attempt fail.
|
||||
*/
|
||||
public final class Connection implements Closeable {
|
||||
private static final byte[] NPN_PROTOCOLS = new byte[] {
|
||||
6, 's', 'p', 'd', 'y', '/', '3',
|
||||
8, 'h', 't', 't', 'p', '/', '1', '.', '1'
|
||||
};
|
||||
private static final byte[] SPDY3 = new byte[] {
|
||||
's', 'p', 'd', 'y', '/', '3'
|
||||
};
|
||||
private static final byte[] HTTP_11 = new byte[] {
|
||||
'h', 't', 't', 'p', '/', '1', '.', '1'
|
||||
};
|
||||
|
||||
private final Route route;
|
||||
|
||||
private Socket socket;
|
||||
private InputStream in;
|
||||
private OutputStream out;
|
||||
private boolean connected = false;
|
||||
private SpdyConnection spdyConnection;
|
||||
private int httpMinorVersion = 1; // Assume HTTP/1.1
|
||||
private long idleStartTimeNs;
|
||||
|
||||
public Connection(Route route) {
|
||||
this.route = route;
|
||||
}
|
||||
|
||||
public void connect(int connectTimeout, int readTimeout, TunnelRequest tunnelRequest)
|
||||
throws IOException {
|
||||
if (connected) {
|
||||
throw new IllegalStateException("already connected");
|
||||
}
|
||||
connected = true;
|
||||
socket = (route.proxy.type() != Proxy.Type.HTTP) ? new Socket(route.proxy) : new Socket();
|
||||
socket.connect(route.inetSocketAddress, connectTimeout);
|
||||
socket.setSoTimeout(readTimeout);
|
||||
in = socket.getInputStream();
|
||||
out = socket.getOutputStream();
|
||||
|
||||
if (route.address.sslSocketFactory != null) {
|
||||
upgradeToTls(tunnelRequest);
|
||||
}
|
||||
|
||||
// Use MTU-sized buffers to send fewer packets.
|
||||
int mtu = Platform.get().getMtu(socket);
|
||||
in = new BufferedInputStream(in, mtu);
|
||||
out = new BufferedOutputStream(out, mtu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@code SSLSocket} and perform the TLS handshake and certificate
|
||||
* validation.
|
||||
*/
|
||||
private void upgradeToTls(TunnelRequest tunnelRequest) throws IOException {
|
||||
Platform platform = Platform.get();
|
||||
|
||||
// Make an SSL Tunnel on the first message pair of each SSL + proxy connection.
|
||||
if (requiresTunnel()) {
|
||||
makeTunnel(tunnelRequest);
|
||||
}
|
||||
|
||||
// Create the wrapper over connected socket.
|
||||
socket = route.address.sslSocketFactory
|
||||
.createSocket(socket, route.address.uriHost, route.address.uriPort, true /* autoClose */);
|
||||
SSLSocket sslSocket = (SSLSocket) socket;
|
||||
if (route.modernTls) {
|
||||
platform.enableTlsExtensions(sslSocket, route.address.uriHost);
|
||||
} else {
|
||||
platform.supportTlsIntolerantServer(sslSocket);
|
||||
}
|
||||
|
||||
if (route.modernTls) {
|
||||
platform.setNpnProtocols(sslSocket, NPN_PROTOCOLS);
|
||||
}
|
||||
|
||||
// Force handshake. This can throw!
|
||||
sslSocket.startHandshake();
|
||||
|
||||
// Verify that the socket's certificates are acceptable for the target host.
|
||||
if (!route.address.hostnameVerifier.verify(route.address.uriHost, sslSocket.getSession())) {
|
||||
throw new IOException("Hostname '" + route.address.uriHost + "' was not verified");
|
||||
}
|
||||
|
||||
out = sslSocket.getOutputStream();
|
||||
in = sslSocket.getInputStream();
|
||||
|
||||
byte[] selectedProtocol;
|
||||
if (route.modernTls
|
||||
&& (selectedProtocol = platform.getNpnSelectedProtocol(sslSocket)) != null) {
|
||||
if (Arrays.equals(selectedProtocol, SPDY3)) {
|
||||
sslSocket.setSoTimeout(0); // SPDY timeouts are set per-stream.
|
||||
spdyConnection = new SpdyConnection.Builder(route.address.getUriHost(), true, in, out)
|
||||
.build();
|
||||
} else if (!Arrays.equals(selectedProtocol, HTTP_11)) {
|
||||
throw new IOException(
|
||||
"Unexpected NPN transport " + new String(selectedProtocol, "ISO-8859-1"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if {@link #connect} has been attempted on this connection. */
|
||||
public boolean isConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
@Override public void close() throws IOException {
|
||||
socket.close();
|
||||
}
|
||||
|
||||
/** Returns the route used by this connection. */
|
||||
public Route getRoute() {
|
||||
return route;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the socket that this connection uses, or null if the connection
|
||||
* is not currently connected.
|
||||
*/
|
||||
public Socket getSocket() {
|
||||
return socket;
|
||||
}
|
||||
|
||||
/** Returns true if this connection is alive. */
|
||||
public boolean isAlive() {
|
||||
return !socket.isClosed() && !socket.isInputShutdown() && !socket.isOutputShutdown();
|
||||
}
|
||||
|
||||
public void resetIdleStartTime() {
|
||||
if (spdyConnection != null) {
|
||||
throw new IllegalStateException("spdyConnection != null");
|
||||
}
|
||||
this.idleStartTimeNs = System.nanoTime();
|
||||
}
|
||||
|
||||
/** Returns true if this connection is idle. */
|
||||
public boolean isIdle() {
|
||||
return spdyConnection == null || spdyConnection.isIdle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this connection has been idle for longer than
|
||||
* {@code keepAliveDurationNs}.
|
||||
*/
|
||||
public boolean isExpired(long keepAliveDurationNs) {
|
||||
return isIdle() && System.nanoTime() - getIdleStartTimeNs() > keepAliveDurationNs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in ns when this connection became idle. Undefined if
|
||||
* this connection is not idle.
|
||||
*/
|
||||
public long getIdleStartTimeNs() {
|
||||
return spdyConnection == null ? idleStartTimeNs : spdyConnection.getIdleStartTimeNs();
|
||||
}
|
||||
|
||||
/** Returns the transport appropriate for this connection. */
|
||||
public Object newTransport(HttpEngine httpEngine) throws IOException {
|
||||
return (spdyConnection != null) ? new SpdyTransport(httpEngine, spdyConnection)
|
||||
: new HttpTransport(httpEngine, out, in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a SPDY connection. Such connections can be used
|
||||
* in multiple HTTP requests simultaneously.
|
||||
*/
|
||||
public boolean isSpdy() {
|
||||
return spdyConnection != null;
|
||||
}
|
||||
|
||||
public SpdyConnection getSpdyConnection() {
|
||||
return spdyConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minor HTTP version that should be used for future requests on
|
||||
* this connection. Either 0 for HTTP/1.0, or 1 for HTTP/1.1. The default
|
||||
* value is 1 for new connections.
|
||||
*/
|
||||
public int getHttpMinorVersion() {
|
||||
return httpMinorVersion;
|
||||
}
|
||||
|
||||
public void setHttpMinorVersion(int httpMinorVersion) {
|
||||
this.httpMinorVersion = httpMinorVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the HTTP connection needs to tunnel one protocol over
|
||||
* another, such as when using HTTPS through an HTTP proxy. When doing so,
|
||||
* we must avoid buffering bytes intended for the higher-level protocol.
|
||||
*/
|
||||
public boolean requiresTunnel() {
|
||||
return route.address.sslSocketFactory != null && route.proxy.type() == Proxy.Type.HTTP;
|
||||
}
|
||||
|
||||
/**
|
||||
* To make an HTTPS connection over an HTTP proxy, send an unencrypted
|
||||
* CONNECT request to create the proxy connection. This may need to be
|
||||
* retried if the proxy requires authorization.
|
||||
*/
|
||||
private void makeTunnel(TunnelRequest tunnelRequest) throws IOException {
|
||||
RawHeaders requestHeaders = tunnelRequest.getRequestHeaders();
|
||||
while (true) {
|
||||
out.write(requestHeaders.toBytes());
|
||||
RawHeaders responseHeaders = RawHeaders.fromBytes(in);
|
||||
|
||||
switch (responseHeaders.getResponseCode()) {
|
||||
case HTTP_OK:
|
||||
return;
|
||||
case HTTP_PROXY_AUTH:
|
||||
requestHeaders = new RawHeaders(requestHeaders);
|
||||
URL url = new URL("https", tunnelRequest.host, tunnelRequest.port, "/");
|
||||
boolean credentialsFound = HttpAuthenticator.processAuthHeader(HTTP_PROXY_AUTH,
|
||||
responseHeaders, requestHeaders, route.proxy, url);
|
||||
if (credentialsFound) {
|
||||
continue;
|
||||
} else {
|
||||
throw new IOException("Failed to authenticate with proxy");
|
||||
}
|
||||
default:
|
||||
throw new IOException(
|
||||
"Unexpected response code for CONNECT: " + responseHeaders.getResponseCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
273
framework/src/com/squareup/okhttp/ConnectionPool.java
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.Platform;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Manages reuse of HTTP and SPDY connections for reduced network latency. HTTP
|
||||
* requests that share the same {@link com.squareup.okhttp.Address} may share a
|
||||
* {@link com.squareup.okhttp.Connection}. This class implements the policy of
|
||||
* which connections to keep open for future use.
|
||||
*
|
||||
* <p>The {@link #getDefault() system-wide default} uses system properties for
|
||||
* tuning parameters:
|
||||
* <ul>
|
||||
* <li>{@code http.keepAlive} true if HTTP and SPDY connections should be
|
||||
* pooled at all. Default is true.
|
||||
* <li>{@code http.maxConnections} maximum number of idle connections to
|
||||
* each to keep in the pool. Default is 5.
|
||||
* <li>{@code http.keepAliveDuration} Time in milliseconds to keep the
|
||||
* connection alive in the pool before closing it. Default is 5 minutes.
|
||||
* This property isn't used by {@code HttpURLConnection}.
|
||||
* </ul>
|
||||
*
|
||||
* <p>The default instance <i>doesn't</i> adjust its configuration as system
|
||||
* properties are changed. This assumes that the applications that set these
|
||||
* parameters do so before making HTTP connections, and that this class is
|
||||
* initialized lazily.
|
||||
*/
|
||||
public class ConnectionPool {
|
||||
private static final int MAX_CONNECTIONS_TO_CLEANUP = 2;
|
||||
private static final long DEFAULT_KEEP_ALIVE_DURATION_MS = 5 * 60 * 1000; // 5 min
|
||||
|
||||
private static final ConnectionPool systemDefault;
|
||||
|
||||
static {
|
||||
String keepAlive = System.getProperty("http.keepAlive");
|
||||
String keepAliveDuration = System.getProperty("http.keepAliveDuration");
|
||||
String maxIdleConnections = System.getProperty("http.maxConnections");
|
||||
long keepAliveDurationMs = keepAliveDuration != null ? Long.parseLong(keepAliveDuration)
|
||||
: DEFAULT_KEEP_ALIVE_DURATION_MS;
|
||||
if (keepAlive != null && !Boolean.parseBoolean(keepAlive)) {
|
||||
systemDefault = new ConnectionPool(0, keepAliveDurationMs);
|
||||
} else if (maxIdleConnections != null) {
|
||||
systemDefault = new ConnectionPool(Integer.parseInt(maxIdleConnections), keepAliveDurationMs);
|
||||
} else {
|
||||
systemDefault = new ConnectionPool(5, keepAliveDurationMs);
|
||||
}
|
||||
}
|
||||
|
||||
/** The maximum number of idle connections for each address. */
|
||||
private final int maxIdleConnections;
|
||||
private final long keepAliveDurationNs;
|
||||
|
||||
private final LinkedList<Connection> connections = new LinkedList<Connection>();
|
||||
|
||||
/** We use a single background thread to cleanup expired connections. */
|
||||
private final ExecutorService executorService =
|
||||
new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
private final Callable<Void> connectionsCleanupCallable = new Callable<Void>() {
|
||||
@Override public Void call() throws Exception {
|
||||
List<Connection> expiredConnections = new ArrayList<Connection>(MAX_CONNECTIONS_TO_CLEANUP);
|
||||
int idleConnectionCount = 0;
|
||||
synchronized (ConnectionPool.this) {
|
||||
for (ListIterator<Connection> i = connections.listIterator(connections.size());
|
||||
i.hasPrevious(); ) {
|
||||
Connection connection = i.previous();
|
||||
if (!connection.isAlive() || connection.isExpired(keepAliveDurationNs)) {
|
||||
i.remove();
|
||||
expiredConnections.add(connection);
|
||||
if (expiredConnections.size() == MAX_CONNECTIONS_TO_CLEANUP) break;
|
||||
} else if (connection.isIdle()) {
|
||||
idleConnectionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (ListIterator<Connection> i = connections.listIterator(connections.size());
|
||||
i.hasPrevious() && idleConnectionCount > maxIdleConnections; ) {
|
||||
Connection connection = i.previous();
|
||||
if (connection.isIdle()) {
|
||||
expiredConnections.add(connection);
|
||||
i.remove();
|
||||
--idleConnectionCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Connection expiredConnection : expiredConnections) {
|
||||
Util.closeQuietly(expiredConnection);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public ConnectionPool(int maxIdleConnections, long keepAliveDurationMs) {
|
||||
this.maxIdleConnections = maxIdleConnections;
|
||||
this.keepAliveDurationNs = keepAliveDurationMs * 1000 * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the connections in this pool, ordered from newest to
|
||||
* oldest. Waits for the cleanup callable to run if it is currently scheduled.
|
||||
*/
|
||||
List<Connection> getConnections() {
|
||||
waitForCleanupCallableToRun();
|
||||
synchronized (this) {
|
||||
return new ArrayList<Connection>(connections);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until the executor service has processed all currently enqueued
|
||||
* jobs.
|
||||
*/
|
||||
private void waitForCleanupCallableToRun() {
|
||||
try {
|
||||
executorService.submit(new Runnable() {
|
||||
@Override public void run() {
|
||||
}
|
||||
}).get();
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public static ConnectionPool getDefault() {
|
||||
return systemDefault;
|
||||
}
|
||||
|
||||
/** Returns total number of connections in the pool. */
|
||||
public synchronized int getConnectionCount() {
|
||||
return connections.size();
|
||||
}
|
||||
|
||||
/** Returns total number of spdy connections in the pool. */
|
||||
public synchronized int getSpdyConnectionCount() {
|
||||
int total = 0;
|
||||
for (Connection connection : connections) {
|
||||
if (connection.isSpdy()) total++;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Returns total number of http connections in the pool. */
|
||||
public synchronized int getHttpConnectionCount() {
|
||||
int total = 0;
|
||||
for (Connection connection : connections) {
|
||||
if (!connection.isSpdy()) total++;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Returns a recycled connection to {@code address}, or null if no such connection exists. */
|
||||
public synchronized Connection get(Address address) {
|
||||
Connection foundConnection = null;
|
||||
for (ListIterator<Connection> i = connections.listIterator(connections.size());
|
||||
i.hasPrevious(); ) {
|
||||
Connection connection = i.previous();
|
||||
if (!connection.getRoute().getAddress().equals(address)
|
||||
|| !connection.isAlive()
|
||||
|| System.nanoTime() - connection.getIdleStartTimeNs() >= keepAliveDurationNs) {
|
||||
continue;
|
||||
}
|
||||
i.remove();
|
||||
if (!connection.isSpdy()) {
|
||||
try {
|
||||
Platform.get().tagSocket(connection.getSocket());
|
||||
} catch (SocketException e) {
|
||||
Util.closeQuietly(connection);
|
||||
// When unable to tag, skip recycling and close
|
||||
Platform.get().logW("Unable to tagSocket(): " + e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
foundConnection = connection;
|
||||
break;
|
||||
}
|
||||
|
||||
if (foundConnection != null && foundConnection.isSpdy()) {
|
||||
connections.addFirst(foundConnection); // Add it back after iteration.
|
||||
}
|
||||
|
||||
executorService.submit(connectionsCleanupCallable);
|
||||
return foundConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives {@code connection} to the pool. The pool may store the connection,
|
||||
* or close it, as its policy describes.
|
||||
*
|
||||
* <p>It is an error to use {@code connection} after calling this method.
|
||||
*/
|
||||
public void recycle(Connection connection) {
|
||||
executorService.submit(connectionsCleanupCallable);
|
||||
|
||||
if (connection.isSpdy()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!connection.isAlive()) {
|
||||
Util.closeQuietly(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Platform.get().untagSocket(connection.getSocket());
|
||||
} catch (SocketException e) {
|
||||
// When unable to remove tagging, skip recycling and close.
|
||||
Platform.get().logW("Unable to untagSocket(): " + e);
|
||||
Util.closeQuietly(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
connections.addFirst(connection);
|
||||
connection.resetIdleStartTime();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shares the SPDY connection with the pool. Callers to this method may
|
||||
* continue to use {@code connection}.
|
||||
*/
|
||||
public void maybeShare(Connection connection) {
|
||||
executorService.submit(connectionsCleanupCallable);
|
||||
if (!connection.isSpdy()) {
|
||||
// Only SPDY connections are sharable.
|
||||
return;
|
||||
}
|
||||
if (connection.isAlive()) {
|
||||
synchronized (this) {
|
||||
connections.addFirst(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Close and remove all connections in the pool. */
|
||||
public void evictAll() {
|
||||
List<Connection> connections;
|
||||
synchronized (this) {
|
||||
connections = new ArrayList<Connection>(this.connections);
|
||||
this.connections.clear();
|
||||
}
|
||||
|
||||
for (Connection connection : connections) {
|
||||
Util.closeQuietly(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
693
framework/src/com/squareup/okhttp/HttpResponseCache.java
Normal file
@@ -0,0 +1,693 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.Base64;
|
||||
import com.squareup.okhttp.internal.DiskLruCache;
|
||||
import com.squareup.okhttp.internal.StrictLineReader;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import com.squareup.okhttp.internal.http.HttpEngine;
|
||||
import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
|
||||
import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
|
||||
import com.squareup.okhttp.internal.http.OkResponseCache;
|
||||
import com.squareup.okhttp.internal.http.RawHeaders;
|
||||
import com.squareup.okhttp.internal.http.ResponseHeaders;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.net.CacheRequest;
|
||||
import java.net.CacheResponse;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.ResponseCache;
|
||||
import java.net.SecureCacheResponse;
|
||||
import java.net.URI;
|
||||
import java.net.URLConnection;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
|
||||
import static com.squareup.okhttp.internal.Util.US_ASCII;
|
||||
import static com.squareup.okhttp.internal.Util.UTF_8;
|
||||
|
||||
/**
|
||||
* Caches HTTP and HTTPS responses to the filesystem so they may be reused,
|
||||
* saving time and bandwidth.
|
||||
*
|
||||
* <h3>Cache Optimization</h3>
|
||||
* To measure cache effectiveness, this class tracks three statistics:
|
||||
* <ul>
|
||||
* <li><strong>{@link #getRequestCount() Request Count:}</strong> the number
|
||||
* of HTTP requests issued since this cache was created.
|
||||
* <li><strong>{@link #getNetworkCount() Network Count:}</strong> the
|
||||
* number of those requests that required network use.
|
||||
* <li><strong>{@link #getHitCount() Hit Count:}</strong> the number of
|
||||
* those requests whose responses were served by the cache.
|
||||
* </ul>
|
||||
* Sometimes a request will result in a conditional cache hit. If the cache
|
||||
* contains a stale copy of the response, the client will issue a conditional
|
||||
* {@code GET}. The server will then send either the updated response if it has
|
||||
* changed, or a short 'not modified' response if the client's copy is still
|
||||
* valid. Such responses increment both the network count and hit count.
|
||||
*
|
||||
* <p>The best way to improve the cache hit rate is by configuring the web
|
||||
* server to return cacheable responses. Although this client honors all <a
|
||||
* href="http://www.ietf.org/rfc/rfc2616.txt">HTTP/1.1 (RFC 2068)</a> cache
|
||||
* headers, it doesn't cache partial responses.
|
||||
*
|
||||
* <h3>Force a Network Response</h3>
|
||||
* In some situations, such as after a user clicks a 'refresh' button, it may be
|
||||
* necessary to skip the cache, and fetch data directly from the server. To force
|
||||
* a full refresh, add the {@code no-cache} directive: <pre> {@code
|
||||
* connection.addRequestProperty("Cache-Control", "no-cache");
|
||||
* }</pre>
|
||||
* If it is only necessary to force a cached response to be validated by the
|
||||
* server, use the more efficient {@code max-age=0} instead: <pre> {@code
|
||||
* connection.addRequestProperty("Cache-Control", "max-age=0");
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Force a Cache Response</h3>
|
||||
* Sometimes you'll want to show resources if they are available immediately,
|
||||
* but not otherwise. This can be used so your application can show
|
||||
* <i>something</i> while waiting for the latest data to be downloaded. To
|
||||
* restrict a request to locally-cached resources, add the {@code
|
||||
* only-if-cached} directive: <pre> {@code
|
||||
* try {
|
||||
* connection.addRequestProperty("Cache-Control", "only-if-cached");
|
||||
* InputStream cached = connection.getInputStream();
|
||||
* // the resource was cached! show it
|
||||
* } catch (FileNotFoundException e) {
|
||||
* // the resource was not cached
|
||||
* }
|
||||
* }</pre>
|
||||
* This technique works even better in situations where a stale response is
|
||||
* better than no response. To permit stale cached responses, use the {@code
|
||||
* max-stale} directive with the maximum staleness in seconds: <pre> {@code
|
||||
* int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
|
||||
* connection.addRequestProperty("Cache-Control", "max-stale=" + maxStale);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class HttpResponseCache extends ResponseCache {
|
||||
private static final char[] DIGITS =
|
||||
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
|
||||
// TODO: add APIs to iterate the cache?
|
||||
private static final int VERSION = 201105;
|
||||
private static final int ENTRY_METADATA = 0;
|
||||
private static final int ENTRY_BODY = 1;
|
||||
private static final int ENTRY_COUNT = 2;
|
||||
|
||||
private final DiskLruCache cache;
|
||||
|
||||
/* read and write statistics, all guarded by 'this' */
|
||||
private int writeSuccessCount;
|
||||
private int writeAbortCount;
|
||||
private int networkCount;
|
||||
private int hitCount;
|
||||
private int requestCount;
|
||||
|
||||
/**
|
||||
* Although this class only exposes the limited ResponseCache API, it
|
||||
* implements the full OkResponseCache interface. This field is used as a
|
||||
* package private handle to the complete implementation. It delegates to
|
||||
* public and private members of this type.
|
||||
*/
|
||||
final OkResponseCache okResponseCache = new OkResponseCache() {
|
||||
@Override public CacheResponse get(URI uri, String requestMethod,
|
||||
Map<String, List<String>> requestHeaders) throws IOException {
|
||||
return HttpResponseCache.this.get(uri, requestMethod, requestHeaders);
|
||||
}
|
||||
|
||||
@Override public CacheRequest put(URI uri, URLConnection connection) throws IOException {
|
||||
return HttpResponseCache.this.put(uri, connection);
|
||||
}
|
||||
|
||||
@Override public void update(
|
||||
CacheResponse conditionalCacheHit, HttpURLConnection connection) throws IOException {
|
||||
HttpResponseCache.this.update(conditionalCacheHit, connection);
|
||||
}
|
||||
|
||||
@Override public void trackConditionalCacheHit() {
|
||||
HttpResponseCache.this.trackConditionalCacheHit();
|
||||
}
|
||||
|
||||
@Override public void trackResponse(ResponseSource source) {
|
||||
HttpResponseCache.this.trackResponse(source);
|
||||
}
|
||||
};
|
||||
|
||||
public HttpResponseCache(File directory, long maxSize) throws IOException {
|
||||
cache = DiskLruCache.open(directory, VERSION, ENTRY_COUNT, maxSize);
|
||||
}
|
||||
|
||||
private String uriToKey(URI uri) {
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
|
||||
byte[] md5bytes = messageDigest.digest(uri.toString().getBytes("UTF-8"));
|
||||
return bytesToHexString(md5bytes);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String bytesToHexString(byte[] bytes) {
|
||||
char[] digits = DIGITS;
|
||||
char[] buf = new char[bytes.length * 2];
|
||||
int c = 0;
|
||||
for (byte b : bytes) {
|
||||
buf[c++] = digits[(b >> 4) & 0xf];
|
||||
buf[c++] = digits[b & 0xf];
|
||||
}
|
||||
return new String(buf);
|
||||
}
|
||||
|
||||
@Override public CacheResponse get(URI uri, String requestMethod,
|
||||
Map<String, List<String>> requestHeaders) {
|
||||
String key = uriToKey(uri);
|
||||
DiskLruCache.Snapshot snapshot;
|
||||
Entry entry;
|
||||
try {
|
||||
snapshot = cache.get(key);
|
||||
if (snapshot == null) {
|
||||
return null;
|
||||
}
|
||||
entry = new Entry(snapshot.getInputStream(ENTRY_METADATA));
|
||||
} catch (IOException e) {
|
||||
// Give up because the cache cannot be read.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!entry.matches(uri, requestMethod, requestHeaders)) {
|
||||
snapshot.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
return entry.isHttps() ? new EntrySecureCacheResponse(entry, snapshot)
|
||||
: new EntryCacheResponse(entry, snapshot);
|
||||
}
|
||||
|
||||
@Override public CacheRequest put(URI uri, URLConnection urlConnection) throws IOException {
|
||||
if (!(urlConnection instanceof HttpURLConnection)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpURLConnection httpConnection = (HttpURLConnection) urlConnection;
|
||||
String requestMethod = httpConnection.getRequestMethod();
|
||||
String key = uriToKey(uri);
|
||||
|
||||
if (requestMethod.equals("POST") || requestMethod.equals("PUT") || requestMethod.equals(
|
||||
"DELETE")) {
|
||||
try {
|
||||
cache.remove(key);
|
||||
} catch (IOException ignored) {
|
||||
// The cache cannot be written.
|
||||
}
|
||||
return null;
|
||||
} else if (!requestMethod.equals("GET")) {
|
||||
// Don't cache non-GET responses. We're technically allowed to cache
|
||||
// HEAD requests and some POST requests, but the complexity of doing
|
||||
// so is high and the benefit is low.
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpEngine httpEngine = getHttpEngine(httpConnection);
|
||||
if (httpEngine == null) {
|
||||
// Don't cache unless the HTTP implementation is ours.
|
||||
return null;
|
||||
}
|
||||
|
||||
ResponseHeaders response = httpEngine.getResponseHeaders();
|
||||
if (response.hasVaryAll()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
RawHeaders varyHeaders =
|
||||
httpEngine.getRequestHeaders().getHeaders().getAll(response.getVaryFields());
|
||||
Entry entry = new Entry(uri, varyHeaders, httpConnection);
|
||||
DiskLruCache.Editor editor = null;
|
||||
try {
|
||||
editor = cache.edit(key);
|
||||
if (editor == null) {
|
||||
return null;
|
||||
}
|
||||
entry.writeTo(editor);
|
||||
return new CacheRequestImpl(editor);
|
||||
} catch (IOException e) {
|
||||
abortQuietly(editor);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void update(CacheResponse conditionalCacheHit, HttpURLConnection httpConnection)
|
||||
throws IOException {
|
||||
HttpEngine httpEngine = getHttpEngine(httpConnection);
|
||||
URI uri = httpEngine.getUri();
|
||||
ResponseHeaders response = httpEngine.getResponseHeaders();
|
||||
RawHeaders varyHeaders =
|
||||
httpEngine.getRequestHeaders().getHeaders().getAll(response.getVaryFields());
|
||||
Entry entry = new Entry(uri, varyHeaders, httpConnection);
|
||||
DiskLruCache.Snapshot snapshot = (conditionalCacheHit instanceof EntryCacheResponse)
|
||||
? ((EntryCacheResponse) conditionalCacheHit).snapshot
|
||||
: ((EntrySecureCacheResponse) conditionalCacheHit).snapshot;
|
||||
DiskLruCache.Editor editor = null;
|
||||
try {
|
||||
editor = snapshot.edit(); // returns null if snapshot is not current
|
||||
if (editor != null) {
|
||||
entry.writeTo(editor);
|
||||
editor.commit();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
abortQuietly(editor);
|
||||
}
|
||||
}
|
||||
|
||||
private void abortQuietly(DiskLruCache.Editor editor) {
|
||||
// Give up because the cache cannot be written.
|
||||
try {
|
||||
if (editor != null) {
|
||||
editor.abort();
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private HttpEngine getHttpEngine(URLConnection httpConnection) {
|
||||
if (httpConnection instanceof HttpURLConnectionImpl) {
|
||||
return ((HttpURLConnectionImpl) httpConnection).getHttpEngine();
|
||||
} else if (httpConnection instanceof HttpsURLConnectionImpl) {
|
||||
return ((HttpsURLConnectionImpl) httpConnection).getHttpEngine();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the cache and deletes all of its stored values. This will delete
|
||||
* all files in the cache directory including files that weren't created by
|
||||
* the cache.
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
cache.delete();
|
||||
}
|
||||
|
||||
public synchronized int getWriteAbortCount() {
|
||||
return writeAbortCount;
|
||||
}
|
||||
|
||||
public synchronized int getWriteSuccessCount() {
|
||||
return writeSuccessCount;
|
||||
}
|
||||
|
||||
private synchronized void trackResponse(ResponseSource source) {
|
||||
requestCount++;
|
||||
|
||||
switch (source) {
|
||||
case CACHE:
|
||||
hitCount++;
|
||||
break;
|
||||
case CONDITIONAL_CACHE:
|
||||
case NETWORK:
|
||||
networkCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void trackConditionalCacheHit() {
|
||||
hitCount++;
|
||||
}
|
||||
|
||||
public synchronized int getNetworkCount() {
|
||||
return networkCount;
|
||||
}
|
||||
|
||||
public synchronized int getHitCount() {
|
||||
return hitCount;
|
||||
}
|
||||
|
||||
public synchronized int getRequestCount() {
|
||||
return requestCount;
|
||||
}
|
||||
|
||||
private final class CacheRequestImpl extends CacheRequest {
|
||||
private final DiskLruCache.Editor editor;
|
||||
private OutputStream cacheOut;
|
||||
private boolean done;
|
||||
private OutputStream body;
|
||||
|
||||
public CacheRequestImpl(final DiskLruCache.Editor editor) throws IOException {
|
||||
this.editor = editor;
|
||||
this.cacheOut = editor.newOutputStream(ENTRY_BODY);
|
||||
this.body = new FilterOutputStream(cacheOut) {
|
||||
@Override public void close() throws IOException {
|
||||
synchronized (HttpResponseCache.this) {
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
writeSuccessCount++;
|
||||
}
|
||||
super.close();
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int length) throws IOException {
|
||||
// Since we don't override "write(int oneByte)", we can write directly to "out"
|
||||
// and avoid the inefficient implementation from the FilterOutputStream.
|
||||
out.write(buffer, offset, length);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override public void abort() {
|
||||
synchronized (HttpResponseCache.this) {
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
writeAbortCount++;
|
||||
}
|
||||
Util.closeQuietly(cacheOut);
|
||||
try {
|
||||
editor.abort();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public OutputStream getBody() throws IOException {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Entry {
|
||||
private final String uri;
|
||||
private final RawHeaders varyHeaders;
|
||||
private final String requestMethod;
|
||||
private final RawHeaders responseHeaders;
|
||||
private final String cipherSuite;
|
||||
private final Certificate[] peerCertificates;
|
||||
private final Certificate[] localCertificates;
|
||||
|
||||
/**
|
||||
* Reads an entry from an input stream. A typical entry looks like this:
|
||||
* <pre>{@code
|
||||
* http://google.com/foo
|
||||
* GET
|
||||
* 2
|
||||
* Accept-Language: fr-CA
|
||||
* Accept-Charset: UTF-8
|
||||
* HTTP/1.1 200 OK
|
||||
* 3
|
||||
* Content-Type: image/png
|
||||
* Content-Length: 100
|
||||
* Cache-Control: max-age=600
|
||||
* }</pre>
|
||||
*
|
||||
* <p>A typical HTTPS file looks like this:
|
||||
* <pre>{@code
|
||||
* https://google.com/foo
|
||||
* GET
|
||||
* 2
|
||||
* Accept-Language: fr-CA
|
||||
* Accept-Charset: UTF-8
|
||||
* HTTP/1.1 200 OK
|
||||
* 3
|
||||
* Content-Type: image/png
|
||||
* Content-Length: 100
|
||||
* Cache-Control: max-age=600
|
||||
*
|
||||
* AES_256_WITH_MD5
|
||||
* 2
|
||||
* base64-encoded peerCertificate[0]
|
||||
* base64-encoded peerCertificate[1]
|
||||
* -1
|
||||
* }</pre>
|
||||
* The file is newline separated. The first two lines are the URL and
|
||||
* the request method. Next is the number of HTTP Vary request header
|
||||
* lines, followed by those lines.
|
||||
*
|
||||
* <p>Next is the response status line, followed by the number of HTTP
|
||||
* response header lines, followed by those lines.
|
||||
*
|
||||
* <p>HTTPS responses also contain SSL session information. This begins
|
||||
* with a blank line, and then a line containing the cipher suite. Next
|
||||
* is the length of the peer certificate chain. These certificates are
|
||||
* base64-encoded and appear each on their own line. The next line
|
||||
* contains the length of the local certificate chain. These
|
||||
* certificates are also base64-encoded and appear each on their own
|
||||
* line. A length of -1 is used to encode a null array.
|
||||
*/
|
||||
public Entry(InputStream in) throws IOException {
|
||||
try {
|
||||
StrictLineReader reader = new StrictLineReader(in, US_ASCII);
|
||||
uri = reader.readLine();
|
||||
requestMethod = reader.readLine();
|
||||
varyHeaders = new RawHeaders();
|
||||
int varyRequestHeaderLineCount = reader.readInt();
|
||||
for (int i = 0; i < varyRequestHeaderLineCount; i++) {
|
||||
varyHeaders.addLine(reader.readLine());
|
||||
}
|
||||
|
||||
responseHeaders = new RawHeaders();
|
||||
responseHeaders.setStatusLine(reader.readLine());
|
||||
int responseHeaderLineCount = reader.readInt();
|
||||
for (int i = 0; i < responseHeaderLineCount; i++) {
|
||||
responseHeaders.addLine(reader.readLine());
|
||||
}
|
||||
|
||||
if (isHttps()) {
|
||||
String blank = reader.readLine();
|
||||
if (blank.length() > 0) {
|
||||
throw new IOException("expected \"\" but was \"" + blank + "\"");
|
||||
}
|
||||
cipherSuite = reader.readLine();
|
||||
peerCertificates = readCertArray(reader);
|
||||
localCertificates = readCertArray(reader);
|
||||
} else {
|
||||
cipherSuite = null;
|
||||
peerCertificates = null;
|
||||
localCertificates = null;
|
||||
}
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
public Entry(URI uri, RawHeaders varyHeaders, HttpURLConnection httpConnection)
|
||||
throws IOException {
|
||||
this.uri = uri.toString();
|
||||
this.varyHeaders = varyHeaders;
|
||||
this.requestMethod = httpConnection.getRequestMethod();
|
||||
this.responseHeaders = RawHeaders.fromMultimap(httpConnection.getHeaderFields(), true);
|
||||
|
||||
if (isHttps()) {
|
||||
HttpsURLConnection httpsConnection = (HttpsURLConnection) httpConnection;
|
||||
cipherSuite = httpsConnection.getCipherSuite();
|
||||
Certificate[] peerCertificatesNonFinal = null;
|
||||
try {
|
||||
peerCertificatesNonFinal = httpsConnection.getServerCertificates();
|
||||
} catch (SSLPeerUnverifiedException ignored) {
|
||||
}
|
||||
peerCertificates = peerCertificatesNonFinal;
|
||||
localCertificates = httpsConnection.getLocalCertificates();
|
||||
} else {
|
||||
cipherSuite = null;
|
||||
peerCertificates = null;
|
||||
localCertificates = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTo(DiskLruCache.Editor editor) throws IOException {
|
||||
OutputStream out = editor.newOutputStream(ENTRY_METADATA);
|
||||
Writer writer = new BufferedWriter(new OutputStreamWriter(out, UTF_8));
|
||||
|
||||
writer.write(uri + '\n');
|
||||
writer.write(requestMethod + '\n');
|
||||
writer.write(Integer.toString(varyHeaders.length()) + '\n');
|
||||
for (int i = 0; i < varyHeaders.length(); i++) {
|
||||
writer.write(varyHeaders.getFieldName(i) + ": " + varyHeaders.getValue(i) + '\n');
|
||||
}
|
||||
|
||||
writer.write(responseHeaders.getStatusLine() + '\n');
|
||||
writer.write(Integer.toString(responseHeaders.length()) + '\n');
|
||||
for (int i = 0; i < responseHeaders.length(); i++) {
|
||||
writer.write(responseHeaders.getFieldName(i) + ": " + responseHeaders.getValue(i) + '\n');
|
||||
}
|
||||
|
||||
if (isHttps()) {
|
||||
writer.write('\n');
|
||||
writer.write(cipherSuite + '\n');
|
||||
writeCertArray(writer, peerCertificates);
|
||||
writeCertArray(writer, localCertificates);
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
|
||||
private boolean isHttps() {
|
||||
return uri.startsWith("https://");
|
||||
}
|
||||
|
||||
private Certificate[] readCertArray(StrictLineReader reader) throws IOException {
|
||||
int length = reader.readInt();
|
||||
if (length == -1) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
||||
Certificate[] result = new Certificate[length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
String line = reader.readLine();
|
||||
byte[] bytes = Base64.decode(line.getBytes("US-ASCII"));
|
||||
result[i] = certificateFactory.generateCertificate(new ByteArrayInputStream(bytes));
|
||||
}
|
||||
return result;
|
||||
} catch (CertificateException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeCertArray(Writer writer, Certificate[] certificates) throws IOException {
|
||||
if (certificates == null) {
|
||||
writer.write("-1\n");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
writer.write(Integer.toString(certificates.length) + '\n');
|
||||
for (Certificate certificate : certificates) {
|
||||
byte[] bytes = certificate.getEncoded();
|
||||
String line = Base64.encode(bytes);
|
||||
writer.write(line + '\n');
|
||||
}
|
||||
} catch (CertificateEncodingException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matches(URI uri, String requestMethod,
|
||||
Map<String, List<String>> requestHeaders) {
|
||||
return this.uri.equals(uri.toString())
|
||||
&& this.requestMethod.equals(requestMethod)
|
||||
&& new ResponseHeaders(uri, responseHeaders).varyMatches(varyHeaders.toMultimap(false),
|
||||
requestHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an input stream that reads the body of a snapshot, closing the
|
||||
* snapshot when the stream is closed.
|
||||
*/
|
||||
private static InputStream newBodyInputStream(final DiskLruCache.Snapshot snapshot) {
|
||||
return new FilterInputStream(snapshot.getInputStream(ENTRY_BODY)) {
|
||||
@Override public void close() throws IOException {
|
||||
snapshot.close();
|
||||
super.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class EntryCacheResponse extends CacheResponse {
|
||||
private final Entry entry;
|
||||
private final DiskLruCache.Snapshot snapshot;
|
||||
private final InputStream in;
|
||||
|
||||
public EntryCacheResponse(Entry entry, DiskLruCache.Snapshot snapshot) {
|
||||
this.entry = entry;
|
||||
this.snapshot = snapshot;
|
||||
this.in = newBodyInputStream(snapshot);
|
||||
}
|
||||
|
||||
@Override public Map<String, List<String>> getHeaders() {
|
||||
return entry.responseHeaders.toMultimap(true);
|
||||
}
|
||||
|
||||
@Override public InputStream getBody() {
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
static class EntrySecureCacheResponse extends SecureCacheResponse {
|
||||
private final Entry entry;
|
||||
private final DiskLruCache.Snapshot snapshot;
|
||||
private final InputStream in;
|
||||
|
||||
public EntrySecureCacheResponse(Entry entry, DiskLruCache.Snapshot snapshot) {
|
||||
this.entry = entry;
|
||||
this.snapshot = snapshot;
|
||||
this.in = newBodyInputStream(snapshot);
|
||||
}
|
||||
|
||||
@Override public Map<String, List<String>> getHeaders() {
|
||||
return entry.responseHeaders.toMultimap(true);
|
||||
}
|
||||
|
||||
@Override public InputStream getBody() {
|
||||
return in;
|
||||
}
|
||||
|
||||
@Override public String getCipherSuite() {
|
||||
return entry.cipherSuite;
|
||||
}
|
||||
|
||||
@Override public List<Certificate> getServerCertificateChain()
|
||||
throws SSLPeerUnverifiedException {
|
||||
if (entry.peerCertificates == null || entry.peerCertificates.length == 0) {
|
||||
throw new SSLPeerUnverifiedException(null);
|
||||
}
|
||||
return Arrays.asList(entry.peerCertificates.clone());
|
||||
}
|
||||
|
||||
@Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
|
||||
if (entry.peerCertificates == null || entry.peerCertificates.length == 0) {
|
||||
throw new SSLPeerUnverifiedException(null);
|
||||
}
|
||||
return ((X509Certificate) entry.peerCertificates[0]).getSubjectX500Principal();
|
||||
}
|
||||
|
||||
@Override public List<Certificate> getLocalCertificateChain() {
|
||||
if (entry.localCertificates == null || entry.localCertificates.length == 0) {
|
||||
return null;
|
||||
}
|
||||
return Arrays.asList(entry.localCertificates.clone());
|
||||
}
|
||||
|
||||
@Override public Principal getLocalPrincipal() {
|
||||
if (entry.localCertificates == null || entry.localCertificates.length == 0) {
|
||||
return null;
|
||||
}
|
||||
return ((X509Certificate) entry.localCertificates[0]).getSubjectX500Principal();
|
||||
}
|
||||
}
|
||||
}
|
||||
216
framework/src/com/squareup/okhttp/OkHttpClient.java
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Square, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
|
||||
import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
|
||||
import com.squareup.okhttp.internal.http.OkResponseCache;
|
||||
import com.squareup.okhttp.internal.http.OkResponseCacheAdapter;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.ResponseCache;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
/** Configures and creates HTTP connections. */
|
||||
public final class OkHttpClient {
|
||||
private Proxy proxy;
|
||||
private Set<Route> failedRoutes = Collections.synchronizedSet(new LinkedHashSet<Route>());
|
||||
private ProxySelector proxySelector;
|
||||
private CookieHandler cookieHandler;
|
||||
private ResponseCache responseCache;
|
||||
private SSLSocketFactory sslSocketFactory;
|
||||
private HostnameVerifier hostnameVerifier;
|
||||
private ConnectionPool connectionPool;
|
||||
private boolean followProtocolRedirects = true;
|
||||
|
||||
/**
|
||||
* Sets the HTTP proxy that will be used by connections created by this
|
||||
* client. This takes precedence over {@link #setProxySelector}, which is
|
||||
* only honored when this proxy is null (which it is by default). To disable
|
||||
* proxy use completely, call {@code setProxy(Proxy.NO_PROXY)}.
|
||||
*/
|
||||
public OkHttpClient setProxy(Proxy proxy) {
|
||||
this.proxy = proxy;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Proxy getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the proxy selection policy to be used if no {@link #setProxy proxy}
|
||||
* is specified explicitly. The proxy selector may return multiple proxies;
|
||||
* in that case they will be tried in sequence until a successful connection
|
||||
* is established.
|
||||
*
|
||||
* <p>If unset, the {@link ProxySelector#getDefault() system-wide default}
|
||||
* proxy selector will be used.
|
||||
*/
|
||||
public OkHttpClient setProxySelector(ProxySelector proxySelector) {
|
||||
this.proxySelector = proxySelector;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProxySelector getProxySelector() {
|
||||
return proxySelector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cookie handler to be used to read outgoing cookies and write
|
||||
* incoming cookies.
|
||||
*
|
||||
* <p>If unset, the {@link CookieHandler#getDefault() system-wide default}
|
||||
* cookie handler will be used.
|
||||
*/
|
||||
public OkHttpClient setCookieHandler(CookieHandler cookieHandler) {
|
||||
this.cookieHandler = cookieHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CookieHandler getCookieHandler() {
|
||||
return cookieHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the response cache to be used to read and write cached responses.
|
||||
*
|
||||
* <p>If unset, the {@link ResponseCache#getDefault() system-wide default}
|
||||
* response cache will be used.
|
||||
*/
|
||||
public OkHttpClient setResponseCache(ResponseCache responseCache) {
|
||||
this.responseCache = responseCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResponseCache getResponseCache() {
|
||||
return responseCache;
|
||||
}
|
||||
|
||||
private OkResponseCache okResponseCache() {
|
||||
if (responseCache instanceof HttpResponseCache) {
|
||||
return ((HttpResponseCache) responseCache).okResponseCache;
|
||||
} else if (responseCache != null) {
|
||||
return new OkResponseCacheAdapter(responseCache);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the socket factory used to secure HTTPS connections.
|
||||
*
|
||||
* <p>If unset, the {@link HttpsURLConnection#getDefaultSSLSocketFactory()
|
||||
* system-wide default} SSL socket factory will be used.
|
||||
*/
|
||||
public OkHttpClient setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
|
||||
this.sslSocketFactory = sslSocketFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SSLSocketFactory getSslSocketFactory() {
|
||||
return sslSocketFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the verifier used to confirm that response certificates apply to
|
||||
* requested hostnames for HTTPS connections.
|
||||
*
|
||||
* <p>If unset, the {@link HttpsURLConnection#getDefaultHostnameVerifier()
|
||||
* system-wide default} hostname verifier will be used.
|
||||
*/
|
||||
public OkHttpClient setHostnameVerifier(HostnameVerifier hostnameVerifier) {
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HostnameVerifier getHostnameVerifier() {
|
||||
return hostnameVerifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the connection pool used to recycle HTTP and HTTPS connections.
|
||||
*
|
||||
* <p>If unset, the {@link ConnectionPool#getDefault() system-wide
|
||||
* default} connection pool will be used.
|
||||
*/
|
||||
public OkHttpClient setConnectionPool(ConnectionPool connectionPool) {
|
||||
this.connectionPool = connectionPool;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectionPool getConnectionPool() {
|
||||
return connectionPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure this client to follow redirects from HTTPS to HTTP and from HTTP
|
||||
* to HTTPS.
|
||||
*
|
||||
* <p>If unset, protocol redirects will be followed. This is different than
|
||||
* the built-in {@code HttpURLConnection}'s default.
|
||||
*/
|
||||
public OkHttpClient setFollowProtocolRedirects(boolean followProtocolRedirects) {
|
||||
this.followProtocolRedirects = followProtocolRedirects;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getFollowProtocolRedirects() {
|
||||
return followProtocolRedirects;
|
||||
}
|
||||
|
||||
public HttpURLConnection open(URL url) {
|
||||
String protocol = url.getProtocol();
|
||||
OkHttpClient copy = copyWithDefaults();
|
||||
if (protocol.equals("http")) {
|
||||
return new HttpURLConnectionImpl(url, copy, copy.okResponseCache(), copy.failedRoutes);
|
||||
} else if (protocol.equals("https")) {
|
||||
return new HttpsURLConnectionImpl(url, copy, copy.okResponseCache(), copy.failedRoutes);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unexpected protocol: " + protocol);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shallow copy of this OkHttpClient that uses the system-wide default for
|
||||
* each field that hasn't been explicitly configured.
|
||||
*/
|
||||
private OkHttpClient copyWithDefaults() {
|
||||
OkHttpClient result = new OkHttpClient();
|
||||
result.proxy = proxy;
|
||||
result.failedRoutes = failedRoutes;
|
||||
result.proxySelector = proxySelector != null ? proxySelector : ProxySelector.getDefault();
|
||||
result.cookieHandler = cookieHandler != null ? cookieHandler : CookieHandler.getDefault();
|
||||
result.responseCache = responseCache != null ? responseCache : ResponseCache.getDefault();
|
||||
result.sslSocketFactory = sslSocketFactory != null
|
||||
? sslSocketFactory
|
||||
: HttpsURLConnection.getDefaultSSLSocketFactory();
|
||||
result.hostnameVerifier = hostnameVerifier != null
|
||||
? hostnameVerifier
|
||||
: HttpsURLConnection.getDefaultHostnameVerifier();
|
||||
result.connectionPool = connectionPool != null ? connectionPool : ConnectionPool.getDefault();
|
||||
result.followProtocolRedirects = followProtocolRedirects;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
38
framework/src/com/squareup/okhttp/OkResponseCache.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.CacheResponse;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
/**
|
||||
* A response cache that supports statistics tracking and updating stored
|
||||
* responses. Implementations of {@link java.net.ResponseCache} should implement
|
||||
* this interface to receive additional support from the HTTP engine.
|
||||
*/
|
||||
public interface OkResponseCache {
|
||||
|
||||
/** Track an HTTP response being satisfied by {@code source}. */
|
||||
void trackResponse(ResponseSource source);
|
||||
|
||||
/** Track an conditional GET that was satisfied by this cache. */
|
||||
void trackConditionalCacheHit();
|
||||
|
||||
/** Updates stored HTTP headers using a hit on a conditional GET. */
|
||||
void update(CacheResponse conditionalCacheHit, HttpURLConnection httpConnection)
|
||||
throws IOException;
|
||||
}
|
||||
37
framework/src/com/squareup/okhttp/ResponseSource.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
/** The source of an HTTP response. */
|
||||
public enum ResponseSource {
|
||||
|
||||
/** The response was returned from the local cache. */
|
||||
CACHE,
|
||||
|
||||
/**
|
||||
* The response is available in the cache but must be validated with the
|
||||
* network. The cache result will be used if it is still valid; otherwise
|
||||
* the network's response will be used.
|
||||
*/
|
||||
CONDITIONAL_CACHE,
|
||||
|
||||
/** The response was returned from the network. */
|
||||
NETWORK;
|
||||
|
||||
public boolean requiresConnection() {
|
||||
return this == CONDITIONAL_CACHE || this == NETWORK;
|
||||
}
|
||||
}
|
||||
91
framework/src/com/squareup/okhttp/Route.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Square, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
|
||||
/** Represents the route used by a connection to reach an endpoint. */
|
||||
public class Route {
|
||||
final Address address;
|
||||
final Proxy proxy;
|
||||
final InetSocketAddress inetSocketAddress;
|
||||
final boolean modernTls;
|
||||
|
||||
public Route(Address address, Proxy proxy, InetSocketAddress inetSocketAddress,
|
||||
boolean modernTls) {
|
||||
if (address == null) throw new NullPointerException("address == null");
|
||||
if (proxy == null) throw new NullPointerException("proxy == null");
|
||||
if (inetSocketAddress == null) throw new NullPointerException("inetSocketAddress == null");
|
||||
this.address = address;
|
||||
this.proxy = proxy;
|
||||
this.inetSocketAddress = inetSocketAddress;
|
||||
this.modernTls = modernTls;
|
||||
}
|
||||
|
||||
/** Returns the {@link Address} of this route. */
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Proxy} of this route.
|
||||
*
|
||||
* <strong>Warning:</strong> This may be different than the proxy returned
|
||||
* by {@link #getAddress}! That is the proxy that the user asked to be
|
||||
* connected to; this returns the proxy that they were actually connected
|
||||
* to. The two may disagree when a proxy selector selects a different proxy
|
||||
* for a connection.
|
||||
*/
|
||||
public Proxy getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/** Returns the {@link InetSocketAddress} of this route. */
|
||||
public InetSocketAddress getSocketAddress() {
|
||||
return inetSocketAddress;
|
||||
}
|
||||
|
||||
/** Returns true if this route uses modern tls. */
|
||||
public boolean isModernTls() {
|
||||
return modernTls;
|
||||
}
|
||||
|
||||
/** Returns a copy of this route with flipped tls mode. */
|
||||
public Route flipTlsMode() {
|
||||
return new Route(address, proxy, inetSocketAddress, !modernTls);
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object obj) {
|
||||
if (obj instanceof Route) {
|
||||
Route other = (Route) obj;
|
||||
return (address.equals(other.address)
|
||||
&& proxy.equals(other.proxy)
|
||||
&& inetSocketAddress.equals(other.inetSocketAddress)
|
||||
&& modernTls == other.modernTls);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
int result = 17;
|
||||
result = 31 * result + address.hashCode();
|
||||
result = 31 * result + proxy.hashCode();
|
||||
result = 31 * result + inetSocketAddress.hashCode();
|
||||
result = result + (modernTls ? (31 * result) : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
75
framework/src/com/squareup/okhttp/TunnelRequest.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.http.RawHeaders;
|
||||
|
||||
import static com.squareup.okhttp.internal.Util.getDefaultPort;
|
||||
|
||||
/**
|
||||
* Routing and authentication information sent to an HTTP proxy to create a
|
||||
* HTTPS to an origin server. Everything in the tunnel request is sent
|
||||
* unencrypted to the proxy server.
|
||||
*
|
||||
* <p>See <a href="http://www.ietf.org/rfc/rfc2817.txt">RFC 2817, Section
|
||||
* 5.2</a>.
|
||||
*/
|
||||
public final class TunnelRequest {
|
||||
final String host;
|
||||
final int port;
|
||||
final String userAgent;
|
||||
final String proxyAuthorization;
|
||||
|
||||
/**
|
||||
* @param host the origin server's hostname. Not null.
|
||||
* @param port the origin server's port, like 80 or 443.
|
||||
* @param userAgent the client's user-agent. Not null.
|
||||
* @param proxyAuthorization proxy authorization, or null if the proxy is
|
||||
* used without an authorization header.
|
||||
*/
|
||||
public TunnelRequest(String host, int port, String userAgent, String proxyAuthorization) {
|
||||
if (host == null) throw new NullPointerException("host == null");
|
||||
if (userAgent == null) throw new NullPointerException("userAgent == null");
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.userAgent = userAgent;
|
||||
this.proxyAuthorization = proxyAuthorization;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we're creating a TLS tunnel, send only the minimum set of headers.
|
||||
* This avoids sending potentially sensitive data like HTTP cookies to
|
||||
* the proxy unencrypted.
|
||||
*/
|
||||
RawHeaders getRequestHeaders() {
|
||||
RawHeaders result = new RawHeaders();
|
||||
result.setRequestLine("CONNECT " + host + ":" + port + " HTTP/1.1");
|
||||
|
||||
// Always set Host and User-Agent.
|
||||
result.set("Host", port == getDefaultPort("https") ? host : (host + ":" + port));
|
||||
result.set("User-Agent", userAgent);
|
||||
|
||||
// Copy over the Proxy-Authorization header if it exists.
|
||||
if (proxyAuthorization != null) {
|
||||
result.set("Proxy-Authorization", proxyAuthorization);
|
||||
}
|
||||
|
||||
// Always set the Proxy-Connection to Keep-Alive for the benefit of
|
||||
// HTTP/1.0 proxies like Squid.
|
||||
result.set("Proxy-Connection", "Keep-Alive");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.squareup.okhttp.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* An output stream for an HTTP request body.
|
||||
*
|
||||
* <p>Since a single socket's output stream may be used to write multiple HTTP
|
||||
* requests to the same server, subclasses should not close the socket stream.
|
||||
*/
|
||||
public abstract class AbstractOutputStream extends OutputStream {
|
||||
protected boolean closed;
|
||||
|
||||
@Override public final void write(int data) throws IOException {
|
||||
write(new byte[] { (byte) data });
|
||||
}
|
||||
|
||||
protected final void checkNotClosed() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if this stream was closed locally. */
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
}
|
||||
164
framework/src/com/squareup/okhttp/internal/Base64.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Alexander Y. Kleymenov
|
||||
*/
|
||||
|
||||
package com.squareup.okhttp.internal;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import static com.squareup.okhttp.internal.Util.EMPTY_BYTE_ARRAY;
|
||||
|
||||
/**
|
||||
* <a href="http://www.ietf.org/rfc/rfc2045.txt">Base64</a> encoder/decoder.
|
||||
* In violation of the RFC, this encoder doesn't wrap lines at 76 columns.
|
||||
*/
|
||||
public final class Base64 {
|
||||
private Base64() {
|
||||
}
|
||||
|
||||
public static byte[] decode(byte[] in) {
|
||||
return decode(in, in.length);
|
||||
}
|
||||
|
||||
public static byte[] decode(byte[] in, int len) {
|
||||
// approximate output length
|
||||
int length = len / 4 * 3;
|
||||
// return an empty array on empty or short input without padding
|
||||
if (length == 0) {
|
||||
return EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
// temporary array
|
||||
byte[] out = new byte[length];
|
||||
// number of padding characters ('=')
|
||||
int pad = 0;
|
||||
byte chr;
|
||||
// compute the number of the padding characters
|
||||
// and adjust the length of the input
|
||||
for (; ; len--) {
|
||||
chr = in[len - 1];
|
||||
// skip the neutral characters
|
||||
if ((chr == '\n') || (chr == '\r') || (chr == ' ') || (chr == '\t')) {
|
||||
continue;
|
||||
}
|
||||
if (chr == '=') {
|
||||
pad++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// index in the output array
|
||||
int outIndex = 0;
|
||||
// index in the input array
|
||||
int inIndex = 0;
|
||||
// holds the value of the input character
|
||||
int bits = 0;
|
||||
// holds the value of the input quantum
|
||||
int quantum = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
chr = in[i];
|
||||
// skip the neutral characters
|
||||
if ((chr == '\n') || (chr == '\r') || (chr == ' ') || (chr == '\t')) {
|
||||
continue;
|
||||
}
|
||||
if ((chr >= 'A') && (chr <= 'Z')) {
|
||||
// char ASCII value
|
||||
// A 65 0
|
||||
// Z 90 25 (ASCII - 65)
|
||||
bits = chr - 65;
|
||||
} else if ((chr >= 'a') && (chr <= 'z')) {
|
||||
// char ASCII value
|
||||
// a 97 26
|
||||
// z 122 51 (ASCII - 71)
|
||||
bits = chr - 71;
|
||||
} else if ((chr >= '0') && (chr <= '9')) {
|
||||
// char ASCII value
|
||||
// 0 48 52
|
||||
// 9 57 61 (ASCII + 4)
|
||||
bits = chr + 4;
|
||||
} else if (chr == '+') {
|
||||
bits = 62;
|
||||
} else if (chr == '/') {
|
||||
bits = 63;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
// append the value to the quantum
|
||||
quantum = (quantum << 6) | (byte) bits;
|
||||
if (inIndex % 4 == 3) {
|
||||
// 4 characters were read, so make the output:
|
||||
out[outIndex++] = (byte) (quantum >> 16);
|
||||
out[outIndex++] = (byte) (quantum >> 8);
|
||||
out[outIndex++] = (byte) quantum;
|
||||
}
|
||||
inIndex++;
|
||||
}
|
||||
if (pad > 0) {
|
||||
// adjust the quantum value according to the padding
|
||||
quantum = quantum << (6 * pad);
|
||||
// make output
|
||||
out[outIndex++] = (byte) (quantum >> 16);
|
||||
if (pad == 1) {
|
||||
out[outIndex++] = (byte) (quantum >> 8);
|
||||
}
|
||||
}
|
||||
// create the resulting array
|
||||
byte[] result = new byte[outIndex];
|
||||
System.arraycopy(out, 0, result, 0, outIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final byte[] MAP = new byte[] {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
|
||||
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
|
||||
'5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
public static String encode(byte[] in) {
|
||||
int length = (in.length + 2) * 4 / 3;
|
||||
byte[] out = new byte[length];
|
||||
int index = 0, end = in.length - in.length % 3;
|
||||
for (int i = 0; i < end; i += 3) {
|
||||
out[index++] = MAP[(in[i] & 0xff) >> 2];
|
||||
out[index++] = MAP[((in[i] & 0x03) << 4) | ((in[i + 1] & 0xff) >> 4)];
|
||||
out[index++] = MAP[((in[i + 1] & 0x0f) << 2) | ((in[i + 2] & 0xff) >> 6)];
|
||||
out[index++] = MAP[(in[i + 2] & 0x3f)];
|
||||
}
|
||||
switch (in.length % 3) {
|
||||
case 1:
|
||||
out[index++] = MAP[(in[end] & 0xff) >> 2];
|
||||
out[index++] = MAP[(in[end] & 0x03) << 4];
|
||||
out[index++] = '=';
|
||||
out[index++] = '=';
|
||||
break;
|
||||
case 2:
|
||||
out[index++] = MAP[(in[end] & 0xff) >> 2];
|
||||
out[index++] = MAP[((in[end] & 0x03) << 4) | ((in[end + 1] & 0xff) >> 4)];
|
||||
out[index++] = MAP[((in[end + 1] & 0x0f) << 2)];
|
||||
out[index++] = '=';
|
||||
break;
|
||||
}
|
||||
try {
|
||||
return new String(out, 0, index, "US-ASCII");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
926
framework/src/com/squareup/okhttp/internal/DiskLruCache.java
Normal file
@@ -0,0 +1,926 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.squareup.okhttp.internal;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A cache that uses a bounded amount of space on a filesystem. Each cache
|
||||
* entry has a string key and a fixed number of values. Each key must match
|
||||
* the regex <strong>[a-z0-9_-]{1,64}</strong>. Values are byte sequences,
|
||||
* accessible as streams or files. Each value must be between {@code 0} and
|
||||
* {@code Integer.MAX_VALUE} bytes in length.
|
||||
*
|
||||
* <p>The cache stores its data in a directory on the filesystem. This
|
||||
* directory must be exclusive to the cache; the cache may delete or overwrite
|
||||
* files from its directory. It is an error for multiple processes to use the
|
||||
* same cache directory at the same time.
|
||||
*
|
||||
* <p>This cache limits the number of bytes that it will store on the
|
||||
* filesystem. When the number of stored bytes exceeds the limit, the cache will
|
||||
* remove entries in the background until the limit is satisfied. The limit is
|
||||
* not strict: the cache may temporarily exceed it while waiting for files to be
|
||||
* deleted. The limit does not include filesystem overhead or the cache
|
||||
* journal so space-sensitive applications should set a conservative limit.
|
||||
*
|
||||
* <p>Clients call {@link #edit} to create or update the values of an entry. An
|
||||
* entry may have only one editor at one time; if a value is not available to be
|
||||
* edited then {@link #edit} will return null.
|
||||
* <ul>
|
||||
* <li>When an entry is being <strong>created</strong> it is necessary to
|
||||
* supply a full set of values; the empty value should be used as a
|
||||
* placeholder if necessary.
|
||||
* <li>When an entry is being <strong>edited</strong>, it is not necessary
|
||||
* to supply data for every value; values default to their previous
|
||||
* value.
|
||||
* </ul>
|
||||
* Every {@link #edit} call must be matched by a call to {@link Editor#commit}
|
||||
* or {@link Editor#abort}. Committing is atomic: a read observes the full set
|
||||
* of values as they were before or after the commit, but never a mix of values.
|
||||
*
|
||||
* <p>Clients call {@link #get} to read a snapshot of an entry. The read will
|
||||
* observe the value at the time that {@link #get} was called. Updates and
|
||||
* removals after the call do not impact ongoing reads.
|
||||
*
|
||||
* <p>This class is tolerant of some I/O errors. If files are missing from the
|
||||
* filesystem, the corresponding entries will be dropped from the cache. If
|
||||
* an error occurs while writing a cache value, the edit will fail silently.
|
||||
* Callers should handle other problems by catching {@code IOException} and
|
||||
* responding appropriately.
|
||||
*/
|
||||
public final class DiskLruCache implements Closeable {
|
||||
static final String JOURNAL_FILE = "journal";
|
||||
static final String JOURNAL_FILE_TEMP = "journal.tmp";
|
||||
static final String JOURNAL_FILE_BACKUP = "journal.bkp";
|
||||
static final String MAGIC = "libcore.io.DiskLruCache";
|
||||
static final String VERSION_1 = "1";
|
||||
static final long ANY_SEQUENCE_NUMBER = -1;
|
||||
static final Pattern LEGAL_KEY_PATTERN = Pattern.compile("[a-z0-9_-]{1,64}");
|
||||
private static final String CLEAN = "CLEAN";
|
||||
private static final String DIRTY = "DIRTY";
|
||||
private static final String REMOVE = "REMOVE";
|
||||
private static final String READ = "READ";
|
||||
|
||||
/*
|
||||
* This cache uses a journal file named "journal". A typical journal file
|
||||
* looks like this:
|
||||
* libcore.io.DiskLruCache
|
||||
* 1
|
||||
* 100
|
||||
* 2
|
||||
*
|
||||
* CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
|
||||
* DIRTY 335c4c6028171cfddfbaae1a9c313c52
|
||||
* CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
|
||||
* REMOVE 335c4c6028171cfddfbaae1a9c313c52
|
||||
* DIRTY 1ab96a171faeeee38496d8b330771a7a
|
||||
* CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
|
||||
* READ 335c4c6028171cfddfbaae1a9c313c52
|
||||
* READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
|
||||
*
|
||||
* The first five lines of the journal form its header. They are the
|
||||
* constant string "libcore.io.DiskLruCache", the disk cache's version,
|
||||
* the application's version, the value count, and a blank line.
|
||||
*
|
||||
* Each of the subsequent lines in the file is a record of the state of a
|
||||
* cache entry. Each line contains space-separated values: a state, a key,
|
||||
* and optional state-specific values.
|
||||
* o DIRTY lines track that an entry is actively being created or updated.
|
||||
* Every successful DIRTY action should be followed by a CLEAN or REMOVE
|
||||
* action. DIRTY lines without a matching CLEAN or REMOVE indicate that
|
||||
* temporary files may need to be deleted.
|
||||
* o CLEAN lines track a cache entry that has been successfully published
|
||||
* and may be read. A publish line is followed by the lengths of each of
|
||||
* its values.
|
||||
* o READ lines track accesses for LRU.
|
||||
* o REMOVE lines track entries that have been deleted.
|
||||
*
|
||||
* The journal file is appended to as cache operations occur. The journal may
|
||||
* occasionally be compacted by dropping redundant lines. A temporary file named
|
||||
* "journal.tmp" will be used during compaction; that file should be deleted if
|
||||
* it exists when the cache is opened.
|
||||
*/
|
||||
|
||||
private final File directory;
|
||||
private final File journalFile;
|
||||
private final File journalFileTmp;
|
||||
private final File journalFileBackup;
|
||||
private final int appVersion;
|
||||
private long maxSize;
|
||||
private final int valueCount;
|
||||
private long size = 0;
|
||||
private Writer journalWriter;
|
||||
private final LinkedHashMap<String, Entry> lruEntries =
|
||||
new LinkedHashMap<String, Entry>(0, 0.75f, true);
|
||||
private int redundantOpCount;
|
||||
|
||||
/**
|
||||
* To differentiate between old and current snapshots, each entry is given
|
||||
* a sequence number each time an edit is committed. A snapshot is stale if
|
||||
* its sequence number is not equal to its entry's sequence number.
|
||||
*/
|
||||
private long nextSequenceNumber = 0;
|
||||
|
||||
/** This cache uses a single background thread to evict entries. */
|
||||
final ThreadPoolExecutor executorService =
|
||||
new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
private final Callable<Void> cleanupCallable = new Callable<Void>() {
|
||||
public Void call() throws Exception {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (journalWriter == null) {
|
||||
return null; // Closed.
|
||||
}
|
||||
trimToSize();
|
||||
if (journalRebuildRequired()) {
|
||||
rebuildJournal();
|
||||
redundantOpCount = 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
|
||||
this.directory = directory;
|
||||
this.appVersion = appVersion;
|
||||
this.journalFile = new File(directory, JOURNAL_FILE);
|
||||
this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP);
|
||||
this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);
|
||||
this.valueCount = valueCount;
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the cache in {@code directory}, creating a cache if none exists
|
||||
* there.
|
||||
*
|
||||
* @param directory a writable directory
|
||||
* @param valueCount the number of values per cache entry. Must be positive.
|
||||
* @param maxSize the maximum number of bytes this cache should use to store
|
||||
* @throws IOException if reading or writing the cache directory fails
|
||||
*/
|
||||
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
|
||||
throws IOException {
|
||||
if (maxSize <= 0) {
|
||||
throw new IllegalArgumentException("maxSize <= 0");
|
||||
}
|
||||
if (valueCount <= 0) {
|
||||
throw new IllegalArgumentException("valueCount <= 0");
|
||||
}
|
||||
|
||||
// If a bkp file exists, use it instead.
|
||||
File backupFile = new File(directory, JOURNAL_FILE_BACKUP);
|
||||
if (backupFile.exists()) {
|
||||
File journalFile = new File(directory, JOURNAL_FILE);
|
||||
// If journal file also exists just delete backup file.
|
||||
if (journalFile.exists()) {
|
||||
backupFile.delete();
|
||||
} else {
|
||||
renameTo(backupFile, journalFile, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer to pick up where we left off.
|
||||
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
|
||||
if (cache.journalFile.exists()) {
|
||||
try {
|
||||
cache.readJournal();
|
||||
cache.processJournal();
|
||||
cache.journalWriter = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(cache.journalFile, true), Util.US_ASCII));
|
||||
return cache;
|
||||
} catch (IOException journalIsCorrupt) {
|
||||
Platform.get().logW("DiskLruCache " + directory + " is corrupt: "
|
||||
+ journalIsCorrupt.getMessage() + ", removing");
|
||||
cache.delete();
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new empty cache.
|
||||
directory.mkdirs();
|
||||
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
|
||||
cache.rebuildJournal();
|
||||
return cache;
|
||||
}
|
||||
|
||||
private void readJournal() throws IOException {
|
||||
StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII);
|
||||
try {
|
||||
String magic = reader.readLine();
|
||||
String version = reader.readLine();
|
||||
String appVersionString = reader.readLine();
|
||||
String valueCountString = reader.readLine();
|
||||
String blank = reader.readLine();
|
||||
if (!MAGIC.equals(magic)
|
||||
|| !VERSION_1.equals(version)
|
||||
|| !Integer.toString(appVersion).equals(appVersionString)
|
||||
|| !Integer.toString(valueCount).equals(valueCountString)
|
||||
|| !"".equals(blank)) {
|
||||
throw new IOException("unexpected journal header: [" + magic + ", " + version + ", "
|
||||
+ valueCountString + ", " + blank + "]");
|
||||
}
|
||||
|
||||
int lineCount = 0;
|
||||
while (true) {
|
||||
try {
|
||||
readJournalLine(reader.readLine());
|
||||
lineCount++;
|
||||
} catch (EOFException endOfJournal) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
redundantOpCount = lineCount - lruEntries.size();
|
||||
} finally {
|
||||
Util.closeQuietly(reader);
|
||||
}
|
||||
}
|
||||
|
||||
private void readJournalLine(String line) throws IOException {
|
||||
int firstSpace = line.indexOf(' ');
|
||||
if (firstSpace == -1) {
|
||||
throw new IOException("unexpected journal line: " + line);
|
||||
}
|
||||
|
||||
int keyBegin = firstSpace + 1;
|
||||
int secondSpace = line.indexOf(' ', keyBegin);
|
||||
final String key;
|
||||
if (secondSpace == -1) {
|
||||
key = line.substring(keyBegin);
|
||||
if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) {
|
||||
lruEntries.remove(key);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
key = line.substring(keyBegin, secondSpace);
|
||||
}
|
||||
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (entry == null) {
|
||||
entry = new Entry(key);
|
||||
lruEntries.put(key, entry);
|
||||
}
|
||||
|
||||
if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) {
|
||||
String[] parts = line.substring(secondSpace + 1).split(" ");
|
||||
entry.readable = true;
|
||||
entry.currentEditor = null;
|
||||
entry.setLengths(parts);
|
||||
} else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) {
|
||||
entry.currentEditor = new Editor(entry);
|
||||
} else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) {
|
||||
// This work was already done by calling lruEntries.get().
|
||||
} else {
|
||||
throw new IOException("unexpected journal line: " + line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the initial size and collects garbage as a part of opening the
|
||||
* cache. Dirty entries are assumed to be inconsistent and will be deleted.
|
||||
*/
|
||||
private void processJournal() throws IOException {
|
||||
deleteIfExists(journalFileTmp);
|
||||
for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {
|
||||
Entry entry = i.next();
|
||||
if (entry.currentEditor == null) {
|
||||
for (int t = 0; t < valueCount; t++) {
|
||||
size += entry.lengths[t];
|
||||
}
|
||||
} else {
|
||||
entry.currentEditor = null;
|
||||
for (int t = 0; t < valueCount; t++) {
|
||||
deleteIfExists(entry.getCleanFile(t));
|
||||
deleteIfExists(entry.getDirtyFile(t));
|
||||
}
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new journal that omits redundant information. This replaces the
|
||||
* current journal if it exists.
|
||||
*/
|
||||
private synchronized void rebuildJournal() throws IOException {
|
||||
if (journalWriter != null) {
|
||||
journalWriter.close();
|
||||
}
|
||||
|
||||
Writer writer = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(journalFileTmp), Util.US_ASCII));
|
||||
try {
|
||||
writer.write(MAGIC);
|
||||
writer.write("\n");
|
||||
writer.write(VERSION_1);
|
||||
writer.write("\n");
|
||||
writer.write(Integer.toString(appVersion));
|
||||
writer.write("\n");
|
||||
writer.write(Integer.toString(valueCount));
|
||||
writer.write("\n");
|
||||
writer.write("\n");
|
||||
|
||||
for (Entry entry : lruEntries.values()) {
|
||||
if (entry.currentEditor != null) {
|
||||
writer.write(DIRTY + ' ' + entry.key + '\n');
|
||||
} else {
|
||||
writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
writer.close();
|
||||
}
|
||||
|
||||
if (journalFile.exists()) {
|
||||
renameTo(journalFile, journalFileBackup, true);
|
||||
}
|
||||
renameTo(journalFileTmp, journalFile, false);
|
||||
journalFileBackup.delete();
|
||||
|
||||
journalWriter = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII));
|
||||
}
|
||||
|
||||
private static void deleteIfExists(File file) throws IOException {
|
||||
if (file.exists() && !file.delete()) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void renameTo(File from, File to, boolean deleteDestination) throws IOException {
|
||||
if (deleteDestination) {
|
||||
deleteIfExists(to);
|
||||
}
|
||||
if (!from.renameTo(to)) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the entry named {@code key}, or null if it doesn't
|
||||
* exist is not currently readable. If a value is returned, it is moved to
|
||||
* the head of the LRU queue.
|
||||
*/
|
||||
public synchronized Snapshot get(String key) throws IOException {
|
||||
checkNotClosed();
|
||||
validateKey(key);
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!entry.readable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Open all streams eagerly to guarantee that we see a single published
|
||||
// snapshot. If we opened streams lazily then the streams could come
|
||||
// from different edits.
|
||||
InputStream[] ins = new InputStream[valueCount];
|
||||
try {
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
ins[i] = new FileInputStream(entry.getCleanFile(i));
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// A file must have been deleted manually!
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
if (ins[i] != null) {
|
||||
Util.closeQuietly(ins[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
redundantOpCount++;
|
||||
journalWriter.append(READ + ' ' + key + '\n');
|
||||
if (journalRebuildRequired()) {
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
|
||||
return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an editor for the entry named {@code key}, or null if another
|
||||
* edit is in progress.
|
||||
*/
|
||||
public Editor edit(String key) throws IOException {
|
||||
return edit(key, ANY_SEQUENCE_NUMBER);
|
||||
}
|
||||
|
||||
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
|
||||
checkNotClosed();
|
||||
validateKey(key);
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null
|
||||
|| entry.sequenceNumber != expectedSequenceNumber)) {
|
||||
return null; // Snapshot is stale.
|
||||
}
|
||||
if (entry == null) {
|
||||
entry = new Entry(key);
|
||||
lruEntries.put(key, entry);
|
||||
} else if (entry.currentEditor != null) {
|
||||
return null; // Another edit is in progress.
|
||||
}
|
||||
|
||||
Editor editor = new Editor(entry);
|
||||
entry.currentEditor = editor;
|
||||
|
||||
// Flush the journal before creating files to prevent file leaks.
|
||||
journalWriter.write(DIRTY + ' ' + key + '\n');
|
||||
journalWriter.flush();
|
||||
return editor;
|
||||
}
|
||||
|
||||
/** Returns the directory where this cache stores its data. */
|
||||
public File getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of bytes that this cache should use to store
|
||||
* its data.
|
||||
*/
|
||||
public long getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the maximum number of bytes the cache can store and queues a job
|
||||
* to trim the existing store, if necessary.
|
||||
*/
|
||||
public synchronized void setMaxSize(long maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes currently being used to store the values in
|
||||
* this cache. This may be greater than the max size if a background
|
||||
* deletion is pending.
|
||||
*/
|
||||
public synchronized long size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
|
||||
Entry entry = editor.entry;
|
||||
if (entry.currentEditor != editor) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
// If this edit is creating the entry for the first time, every index must have a value.
|
||||
if (success && !entry.readable) {
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
if (!editor.written[i]) {
|
||||
editor.abort();
|
||||
throw new IllegalStateException("Newly created entry didn't create value for index " + i);
|
||||
}
|
||||
if (!entry.getDirtyFile(i).exists()) {
|
||||
editor.abort();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
File dirty = entry.getDirtyFile(i);
|
||||
if (success) {
|
||||
if (dirty.exists()) {
|
||||
File clean = entry.getCleanFile(i);
|
||||
dirty.renameTo(clean);
|
||||
long oldLength = entry.lengths[i];
|
||||
long newLength = clean.length();
|
||||
entry.lengths[i] = newLength;
|
||||
size = size - oldLength + newLength;
|
||||
}
|
||||
} else {
|
||||
deleteIfExists(dirty);
|
||||
}
|
||||
}
|
||||
|
||||
redundantOpCount++;
|
||||
entry.currentEditor = null;
|
||||
if (entry.readable | success) {
|
||||
entry.readable = true;
|
||||
journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
||||
if (success) {
|
||||
entry.sequenceNumber = nextSequenceNumber++;
|
||||
}
|
||||
} else {
|
||||
lruEntries.remove(entry.key);
|
||||
journalWriter.write(REMOVE + ' ' + entry.key + '\n');
|
||||
}
|
||||
journalWriter.flush();
|
||||
|
||||
if (size > maxSize || journalRebuildRequired()) {
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We only rebuild the journal when it will halve the size of the journal
|
||||
* and eliminate at least 2000 ops.
|
||||
*/
|
||||
private boolean journalRebuildRequired() {
|
||||
final int redundantOpCompactThreshold = 2000;
|
||||
return redundantOpCount >= redundantOpCompactThreshold //
|
||||
&& redundantOpCount >= lruEntries.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the entry for {@code key} if it exists and can be removed. Entries
|
||||
* actively being edited cannot be removed.
|
||||
*
|
||||
* @return true if an entry was removed.
|
||||
*/
|
||||
public synchronized boolean remove(String key) throws IOException {
|
||||
checkNotClosed();
|
||||
validateKey(key);
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (entry == null || entry.currentEditor != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
File file = entry.getCleanFile(i);
|
||||
if (!file.delete()) {
|
||||
throw new IOException("failed to delete " + file);
|
||||
}
|
||||
size -= entry.lengths[i];
|
||||
entry.lengths[i] = 0;
|
||||
}
|
||||
|
||||
redundantOpCount++;
|
||||
journalWriter.append(REMOVE + ' ' + key + '\n');
|
||||
lruEntries.remove(key);
|
||||
|
||||
if (journalRebuildRequired()) {
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns true if this cache has been closed. */
|
||||
public boolean isClosed() {
|
||||
return journalWriter == null;
|
||||
}
|
||||
|
||||
private void checkNotClosed() {
|
||||
if (journalWriter == null) {
|
||||
throw new IllegalStateException("cache is closed");
|
||||
}
|
||||
}
|
||||
|
||||
/** Force buffered operations to the filesystem. */
|
||||
public synchronized void flush() throws IOException {
|
||||
checkNotClosed();
|
||||
trimToSize();
|
||||
journalWriter.flush();
|
||||
}
|
||||
|
||||
/** Closes this cache. Stored values will remain on the filesystem. */
|
||||
public synchronized void close() throws IOException {
|
||||
if (journalWriter == null) {
|
||||
return; // Already closed.
|
||||
}
|
||||
for (Entry entry : new ArrayList<Entry>(lruEntries.values())) {
|
||||
if (entry.currentEditor != null) {
|
||||
entry.currentEditor.abort();
|
||||
}
|
||||
}
|
||||
trimToSize();
|
||||
journalWriter.close();
|
||||
journalWriter = null;
|
||||
}
|
||||
|
||||
private void trimToSize() throws IOException {
|
||||
while (size > maxSize) {
|
||||
Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();
|
||||
remove(toEvict.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the cache and deletes all of its stored values. This will delete
|
||||
* all files in the cache directory including files that weren't created by
|
||||
* the cache.
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
close();
|
||||
Util.deleteContents(directory);
|
||||
}
|
||||
|
||||
private void validateKey(String key) {
|
||||
Matcher matcher = LEGAL_KEY_PATTERN.matcher(key);
|
||||
if (!matcher.matches()) {
|
||||
throw new IllegalArgumentException("keys must match regex [a-z0-9_-]{1,64}: \"" + key + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
private static String inputStreamToString(InputStream in) throws IOException {
|
||||
return Util.readFully(new InputStreamReader(in, Util.UTF_8));
|
||||
}
|
||||
|
||||
/** A snapshot of the values for an entry. */
|
||||
public final class Snapshot implements Closeable {
|
||||
private final String key;
|
||||
private final long sequenceNumber;
|
||||
private final InputStream[] ins;
|
||||
private final long[] lengths;
|
||||
|
||||
private Snapshot(String key, long sequenceNumber, InputStream[] ins, long[] lengths) {
|
||||
this.key = key;
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
this.ins = ins;
|
||||
this.lengths = lengths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an editor for this snapshot's entry, or null if either the
|
||||
* entry has changed since this snapshot was created or if another edit
|
||||
* is in progress.
|
||||
*/
|
||||
public Editor edit() throws IOException {
|
||||
return DiskLruCache.this.edit(key, sequenceNumber);
|
||||
}
|
||||
|
||||
/** Returns the unbuffered stream with the value for {@code index}. */
|
||||
public InputStream getInputStream(int index) {
|
||||
return ins[index];
|
||||
}
|
||||
|
||||
/** Returns the string value for {@code index}. */
|
||||
public String getString(int index) throws IOException {
|
||||
return inputStreamToString(getInputStream(index));
|
||||
}
|
||||
|
||||
/** Returns the byte length of the value for {@code index}. */
|
||||
public long getLength(int index) {
|
||||
return lengths[index];
|
||||
}
|
||||
|
||||
public void close() {
|
||||
for (InputStream in : ins) {
|
||||
Util.closeQuietly(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
// Eat all writes silently. Nom nom.
|
||||
}
|
||||
};
|
||||
|
||||
/** Edits the values for an entry. */
|
||||
public final class Editor {
|
||||
private final Entry entry;
|
||||
private final boolean[] written;
|
||||
private boolean hasErrors;
|
||||
private boolean committed;
|
||||
|
||||
private Editor(Entry entry) {
|
||||
this.entry = entry;
|
||||
this.written = (entry.readable) ? null : new boolean[valueCount];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unbuffered input stream to read the last committed value,
|
||||
* or null if no value has been committed.
|
||||
*/
|
||||
public InputStream newInputStream(int index) throws IOException {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (entry.currentEditor != this) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (!entry.readable) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new FileInputStream(entry.getCleanFile(index));
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last committed value as a string, or null if no value
|
||||
* has been committed.
|
||||
*/
|
||||
public String getString(int index) throws IOException {
|
||||
InputStream in = newInputStream(index);
|
||||
return in != null ? inputStreamToString(in) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new unbuffered output stream to write the value at
|
||||
* {@code index}. If the underlying output stream encounters errors
|
||||
* when writing to the filesystem, this edit will be aborted when
|
||||
* {@link #commit} is called. The returned output stream does not throw
|
||||
* IOExceptions.
|
||||
*/
|
||||
public OutputStream newOutputStream(int index) throws IOException {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (entry.currentEditor != this) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (!entry.readable) {
|
||||
written[index] = true;
|
||||
}
|
||||
File dirtyFile = entry.getDirtyFile(index);
|
||||
FileOutputStream outputStream;
|
||||
try {
|
||||
outputStream = new FileOutputStream(dirtyFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
// Attempt to recreate the cache directory.
|
||||
directory.mkdirs();
|
||||
try {
|
||||
outputStream = new FileOutputStream(dirtyFile);
|
||||
} catch (FileNotFoundException e2) {
|
||||
// We are unable to recover. Silently eat the writes.
|
||||
return NULL_OUTPUT_STREAM;
|
||||
}
|
||||
}
|
||||
return new FaultHidingOutputStream(outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the value at {@code index} to {@code value}. */
|
||||
public void set(int index, String value) throws IOException {
|
||||
Writer writer = null;
|
||||
try {
|
||||
writer = new OutputStreamWriter(newOutputStream(index), Util.UTF_8);
|
||||
writer.write(value);
|
||||
} finally {
|
||||
Util.closeQuietly(writer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits this edit so it is visible to readers. This releases the
|
||||
* edit lock so another edit may be started on the same key.
|
||||
*/
|
||||
public void commit() throws IOException {
|
||||
if (hasErrors) {
|
||||
completeEdit(this, false);
|
||||
remove(entry.key); // The previous entry is stale.
|
||||
} else {
|
||||
completeEdit(this, true);
|
||||
}
|
||||
committed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts this edit. This releases the edit lock so another edit may be
|
||||
* started on the same key.
|
||||
*/
|
||||
public void abort() throws IOException {
|
||||
completeEdit(this, false);
|
||||
}
|
||||
|
||||
public void abortUnlessCommitted() {
|
||||
if (!committed) {
|
||||
try {
|
||||
abort();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FaultHidingOutputStream extends FilterOutputStream {
|
||||
private FaultHidingOutputStream(OutputStream out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
@Override public void write(int oneByte) {
|
||||
try {
|
||||
out.write(oneByte);
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void write(byte[] buffer, int offset, int length) {
|
||||
try {
|
||||
out.write(buffer, offset, length);
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void close() {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void flush() {
|
||||
try {
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class Entry {
|
||||
private final String key;
|
||||
|
||||
/** Lengths of this entry's files. */
|
||||
private final long[] lengths;
|
||||
|
||||
/** True if this entry has ever been published. */
|
||||
private boolean readable;
|
||||
|
||||
/** The ongoing edit or null if this entry is not being edited. */
|
||||
private Editor currentEditor;
|
||||
|
||||
/** The sequence number of the most recently committed edit to this entry. */
|
||||
private long sequenceNumber;
|
||||
|
||||
private Entry(String key) {
|
||||
this.key = key;
|
||||
this.lengths = new long[valueCount];
|
||||
}
|
||||
|
||||
public String getLengths() throws IOException {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (long size : lengths) {
|
||||
result.append(' ').append(size);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/** Set lengths using decimal numbers like "10123". */
|
||||
private void setLengths(String[] strings) throws IOException {
|
||||
if (strings.length != valueCount) {
|
||||
throw invalidLengths(strings);
|
||||
}
|
||||
|
||||
try {
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
lengths[i] = Long.parseLong(strings[i]);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw invalidLengths(strings);
|
||||
}
|
||||
}
|
||||
|
||||
private IOException invalidLengths(String[] strings) throws IOException {
|
||||
throw new IOException("unexpected journal line: " + java.util.Arrays.toString(strings));
|
||||
}
|
||||
|
||||
public File getCleanFile(int i) {
|
||||
return new File(directory, key + "." + i);
|
||||
}
|
||||
|
||||
public File getDirtyFile(int i) {
|
||||
return new File(directory, key + "." + i + ".tmp");
|
||||
}
|
||||
}
|
||||
}
|
||||