Compare commits
907 Commits
v0.9.21.1
...
release/1.
Author | SHA1 | Date | |
---|---|---|---|
0397c66c4d | |||
0cdc7647aa | |||
c5d7faefe9 | |||
d7211dec79 | |||
cea2c0eedf | |||
b738172dcc | |||
abdc3d3c77 | |||
80901e8288 | |||
465796c3a8 | |||
9c05284bd1 | |||
56edaa1653 | |||
8865fda872 | |||
b0df9b164c | |||
72188234aa | |||
8c0619d29c | |||
16a3a4303f | |||
eaed7584f1 | |||
0262ba58cb | |||
e088998867 | |||
db5ec711e8 | |||
9d49c80783 | |||
b1fdb9f38e | |||
a606dc274b | |||
c9d6fba07d | |||
228fc5a83a | |||
c28dc03f6d | |||
dcb276a0dd | |||
53864a73db | |||
cf65a127e1 | |||
fd64dce6a5 | |||
d60b07249c | |||
7b99278eb0 | |||
aaf8ae1d0b | |||
a83fdd0046 | |||
b1a219b0ec | |||
487b3b0f7b | |||
4ca3d49307 | |||
98f4c936f2 | |||
344277d026 | |||
3add8cfdb0 | |||
8b5a65c14a | |||
0646cc8d14 | |||
97d22be318 | |||
4c62ce831b | |||
b041aed660 | |||
cd6d703e94 | |||
dd140beb73 | |||
06afabb631 | |||
505b77a0d5 | |||
c3f5403b64 | |||
589f1c85b9 | |||
492d5454b1 | |||
4f95e2f9ec | |||
eb2d168710 | |||
d25634662b | |||
819ecd4508 | |||
5d6d40f329 | |||
b08abe64e4 | |||
0b53a5c673 | |||
e84f3ec1d4 | |||
b1af5af30e | |||
423c2f499c | |||
a2333bcbb4 | |||
c6578d2336 | |||
c5972b4ac7 | |||
0c9c5439d4 | |||
193c62fdba | |||
d673c34c8d | |||
df54510e3e | |||
ee04b71887 | |||
4b5c99d97f | |||
9e7d5d9d3b | |||
b2d18393c4 | |||
335d7f4855 | |||
4fb28e0dab | |||
bdae4fd573 | |||
e813626ee1 | |||
7bb77c02da | |||
ea54283b30 | |||
46fbd34c70 | |||
3ff5cfd028 | |||
922f881c3d | |||
bfcac89881 | |||
db06906c4f | |||
3016f23864 | |||
e5fba8fd70 | |||
916d155467 | |||
c5cb6e8e70 | |||
3791831081 | |||
7e6c1f8024 | |||
ceb0739ba1 | |||
37c1a8f69d | |||
6ea28f93b9 | |||
1208ac83d5 | |||
aa22cf323e | |||
492e5049d7 | |||
042c3290b3 | |||
518dc87db3 | |||
6391ec0c8f | |||
2739233719 | |||
83ee39448e | |||
35cd355c14 | |||
d764bd0584 | |||
666a7dda36 | |||
45618d5f6b | |||
d4c2e9de32 | |||
6220707e03 | |||
4c30f0f9ac | |||
5615fc4714 | |||
fa7b3b7276 | |||
b0aec6402a | |||
cc29b4bc27 | |||
b7e8d954ef | |||
4f7fc7b23f | |||
457a3c8f76 | |||
e6bb9c1cad | |||
aa4502060b | |||
b533aaa765 | |||
35add89c87 | |||
46e7c8512e | |||
ec9620fb2f | |||
6c7f5e3d0e | |||
dd521ece3f | |||
bcc1660abc | |||
62559ac330 | |||
30afd37604 | |||
cd4cc309ae | |||
3be9046c21 | |||
9c3db1be1d | |||
9bb575be7d | |||
0f04af5916 | |||
481b221279 | |||
80eb8f46b7 | |||
3a983d2419 | |||
47460b3b4a | |||
0a1ff68c11 | |||
ab16ce70fc | |||
08caeedd84 | |||
6f69b4d61f | |||
2feb23c1da | |||
efd7da0ce8 | |||
acd85fe95f | |||
4dfcd6012b | |||
546c0f631c | |||
0e33fbdcb9 | |||
8150c0a726 | |||
e8c1399bbf | |||
1cbab291a9 | |||
8181929c9a | |||
d9efaf754c | |||
6afdc52483 | |||
29e2fb38f8 | |||
03129e7c93 | |||
f0e94b4d71 | |||
f857fb7600 | |||
ff97059a99 | |||
1959346793 | |||
fc17a527bc | |||
a4df9d74ea | |||
eb82ca4563 | |||
09b6983175 | |||
65a26e40a8 | |||
fc2e33c594 | |||
1d72aaa0cd | |||
cf66826223 | |||
56ed408436 | |||
6be527dd52 | |||
effe9cc2cf | |||
89525fcb4e | |||
c2590af7fd | |||
9f6016e877 | |||
75f41dedca | |||
744af9f497 | |||
529fb7a7d7 | |||
5caff3bc24 | |||
507869bff1 | |||
70d5d791cc | |||
d6f2c0a76f | |||
bb418a43c1 | |||
2e5242f9bb | |||
1ae80aaf64 | |||
41de1cb723 | |||
29ab1fa8a5 | |||
60454da650 | |||
cb2c10d862 | |||
d05305473e | |||
be935bff84 | |||
f43c07cb3c | |||
af51dc4d63 | |||
aac2b6ae4c | |||
5db8f447d5 | |||
6fc85f1ec2 | |||
2c8ed76e01 | |||
393d675690 | |||
a748afce03 | |||
c14f0a4471 | |||
ba95e445e1 | |||
8c4d493c66 | |||
a5d5387dee | |||
130f3b270a | |||
61ca780f3b | |||
57dff6f1d7 | |||
7ffabf1d39 | |||
6fdddc5ac9 | |||
02c6af66bf | |||
ec866b066a | |||
056e9dd393 | |||
9226369b5d | |||
a2ce7b9950 | |||
d8fe64acaa | |||
4c490db6af | |||
b047f05e7e | |||
8d016ced6b | |||
7625b07dd9 | |||
8f504063f4 | |||
e896cab82c | |||
5f3792c2a7 | |||
01fe972113 | |||
ccbb56b4f2 | |||
2aeeb72fa5 | |||
7c4ed8055c | |||
992e4f83cb | |||
a8ebf756c7 | |||
5d9df7348d | |||
ac80ec59dc | |||
e349fac97d | |||
aba901e13c | |||
07db098ccf | |||
855e76fddd | |||
4d11747836 | |||
6ca3a44638 | |||
4460dc9d1a | |||
2a5a55efaf | |||
c850c41ec1 | |||
76821d167a | |||
fccc7d71eb | |||
d0bb90c69e | |||
992dc74efd | |||
0b22ad99c1 | |||
a8889b092b | |||
11b8d1df59 | |||
8743cc1c1c | |||
a0566c1058 | |||
3d0c6a8345 | |||
c3d6228023 | |||
7098ec691c | |||
e0e5f74776 | |||
ceaf1c080b | |||
1d42888d30 | |||
654564e164 | |||
9d8b512b27 | |||
b39042db56 | |||
d1e93db3eb | |||
059a1e9e4e | |||
5e7db8f5cd | |||
a7d22658ad | |||
29d53b2073 | |||
61ccc39b56 | |||
f9264e87ec | |||
a355777ff8 | |||
a0191910fc | |||
b9ebdffd83 | |||
1169ec7681 | |||
d099a42c85 | |||
7e69392249 | |||
216fc267fa | |||
d84638bd31 | |||
b0a5be4495 | |||
e64625aa82 | |||
c6dbe9dc07 | |||
662285074e | |||
e9c0b5431c | |||
fdbf8be735 | |||
5757a0edb5 | |||
04910c902a | |||
ffbe5656ff | |||
c0343c8f17 | |||
6d92fdc0df | |||
6b2a03faa2 | |||
c6e2af14c0 | |||
8774fdcd64 | |||
3ea6b5ae32 | |||
d02f07a983 | |||
b98b444179 | |||
1ce40d7581 | |||
92ef33d97a | |||
302187ae39 | |||
bf99d5b33c | |||
e5b820c47b | |||
bde2ff0343 | |||
803b3c4a82 | |||
0609fcf030 | |||
792b0ddccd | |||
6260b86c15 | |||
43e4a6501b | |||
7bd71fa800 | |||
7f92e708c5 | |||
b426301467 | |||
6994a3daaa | |||
821e01b013 | |||
ee73f09727 | |||
dc58568a25 | |||
f1a4a6e563 | |||
8363aba7ac | |||
d23ec6c419 | |||
22c7ce0162 | |||
983a33cf11 | |||
72e2613a9f | |||
67e6f74e9a | |||
d21c2bfb68 | |||
6b5532ab0d | |||
139439dcdc | |||
2b3957f373 | |||
55424a11af | |||
57c911c398 | |||
3ce17d2862 | |||
99ca4b619b | |||
b53f701c27 | |||
1989d1491a | |||
4ee7f6fc88 | |||
6d596b1ad1 | |||
d36c25bcbc | |||
2e0b56a72b | |||
2737baa657 | |||
f87501b1c5 | |||
3ff272b618 | |||
29297d3b82 | |||
ce5c94e471 | |||
f202563777 | |||
36a6b16a3b | |||
603192cfa7 | |||
a4a4e9fcf8 | |||
3e1d635f8d | |||
9ac1b4e59e | |||
5fdf72b1ab | |||
c3f6c322c0 | |||
5c25403b13 | |||
fd764d4ff7 | |||
60c2ccd99c | |||
9cf7913c61 | |||
7633dfdc08 | |||
6fb810adaa | |||
398d08a8dd | |||
07c3de3f75 | |||
a40a91d60f | |||
c590b505ed | |||
3deded28a5 | |||
46bd6c43db | |||
42a14b8a09 | |||
9c69c051ba | |||
53e042f0c4 | |||
4c2ba1af1d | |||
0fa2750fc9 | |||
8c4c7ea192 | |||
d1e589289c | |||
0743243dce | |||
d5871fc200 | |||
4180ca7fe4 | |||
a9659e6dcf | |||
8d3faf69d0 | |||
baea8e87e5 | |||
01ec4dbb12 | |||
a86452d22c | |||
49336675f3 | |||
516362bcad | |||
30444db020 | |||
c941a39b75 | |||
8507c867b9 | |||
6931267324 | |||
6ff956394a | |||
ac0637c413 | |||
b6d40a9312 | |||
c5d6fcbaba | |||
24554629b1 | |||
7c6ef0ddac | |||
1b26d4f220 | |||
e82100367f | |||
a67a15528a | |||
7b9fbb088a | |||
6415ed0730 | |||
e4f9ec886b | |||
8eaaf24b1e | |||
13c25036ea | |||
ecd19919c5 | |||
90d45f0397 | |||
b91b581b80 | |||
629705ad53 | |||
5ec6ecc511 | |||
a9ada0b5ba | |||
37c5ff392f | |||
2a7411bc96 | |||
497a7f1717 | |||
026ee40650 | |||
11c8f83a58 | |||
057bc237ad | |||
8b64e041d6 | |||
2a1b722d04 | |||
7c2af1c117 | |||
2cea410656 | |||
430bcdb219 | |||
53a6145a2b | |||
15e169e5b6 | |||
4365668462 | |||
55dd8fd621 | |||
2f4cbe22f5 | |||
5afebc2a4b | |||
f5abc9f188 | |||
753d62a4dd | |||
ae36beb38f | |||
bdd63837ea | |||
aa699a1283 | |||
aaddc99c35 | |||
e4b54f18c6 | |||
a3fdef7529 | |||
a977f3c0dc | |||
30b27336ea | |||
787a61bb27 | |||
4a1e82cf3f | |||
5721fcf668 | |||
be303ba186 | |||
1f34daccc3 | |||
6add45cd10 | |||
7ec8c257ff | |||
a9d6846f92 | |||
8f372c867d | |||
e952bb65e7 | |||
2642e091e9 | |||
dfd18d245a | |||
4699ebf534 | |||
5daf8729be | |||
4673b04503 | |||
cc0b451119 | |||
f2a2164184 | |||
f475a01326 | |||
2628103f1d | |||
ad56aef5d2 | |||
c3b80123e3 | |||
f9f9352ceb | |||
1e3f4877c0 | |||
e79cc42dfe | |||
263903378b | |||
f06f220c7c | |||
d6233c7d2d | |||
b42b70eb5f | |||
610adfd83f | |||
3c7b64ce20 | |||
a977cecbe4 | |||
6e212bdc6d | |||
2e8016c80d | |||
0930e190a7 | |||
3f94d09c1f | |||
70da79f04c | |||
8dcbdcad0a | |||
aa250e228a | |||
cf7c44a7f6 | |||
21fa29111b | |||
9c03c374e3 | |||
6d817e16c1 | |||
b240983e2b | |||
30a9939388 | |||
fc7abd9886 | |||
0fc71877a7 | |||
80833f8137 | |||
faae8b7dd8 | |||
2dd6a62f67 | |||
2937903299 | |||
66d3dc8690 | |||
f9a0a13fa9 | |||
2a0528303f | |||
6f5c6150b7 | |||
645dfd9693 | |||
1bca2f6ec4 | |||
90c4493a10 | |||
aaac1f0cdd | |||
287f990891 | |||
02d629af8f | |||
55a796b7c3 | |||
359e6414e5 | |||
4bb9a61049 | |||
22080e1fdd | |||
e2c2d8e15e | |||
b3c07f167f | |||
ec6a7b35f6 | |||
ebaa9b9feb | |||
7584e68c21 | |||
1fe617fa57 | |||
87dace1fa9 | |||
aa258dcc5f | |||
3c93034a32 | |||
594a34a88d | |||
1b59f89095 | |||
bbfa0a3dcb | |||
348f1562e2 | |||
7e41d7ac51 | |||
bd38428f33 | |||
87b62f75a7 | |||
c6c443385b | |||
5f8e5a4875 | |||
cc9ae39933 | |||
08d72a9245 | |||
09d0d55fc5 | |||
faab931ce1 | |||
d2a87f6f72 | |||
4b9b633dfe | |||
cb7f2d43b6 | |||
8aea85e374 | |||
0a600a03ee | |||
862117e4bd | |||
a1a475fb92 | |||
2a0d888326 | |||
8ebf2d8fad | |||
2f55a1d798 | |||
6609d45ef4 | |||
13bd452faf | |||
37111aa4bd | |||
f599a1b5f1 | |||
9e9bd35557 | |||
979ebfc126 | |||
8482855bc7 | |||
acb59f3243 | |||
5cfae0536f | |||
e7627623b9 | |||
f94c5473ad | |||
10af69b57c | |||
3c1cccc801 | |||
e61db7145a | |||
355b1e3bb1 | |||
b9affbf9fe | |||
2e0694b606 | |||
fc2a061d51 | |||
065aff9ffa | |||
4407524d13 | |||
29f7902fee | |||
65a48f9cd8 | |||
c4af70d0cc | |||
271fb20ecb | |||
858a6f0be9 | |||
f249ccaa89 | |||
a8e4cb6dfe | |||
cf3aabb9d3 | |||
261a8077c4 | |||
1774c49456 | |||
6fb6e6679e | |||
38c61f6f25 | |||
ff5b3ef087 | |||
468501cb86 | |||
b3d5ce7d48 | |||
dffe6d32d6 | |||
6a5c9aff3b | |||
e972a116ac | |||
1cbbfbe7fa | |||
7e58949c3f | |||
667f5a09c3 | |||
bac9a94ddf | |||
14994fa21b | |||
bc6031e7bb | |||
93f4852844 | |||
5950755b12 | |||
4541c22964 | |||
d652a58ada | |||
fecf214175 | |||
5f341e5db5 | |||
73c355591f | |||
8dc3048f65 | |||
3239aca69b | |||
2c24a73e25 | |||
6c73a59806 | |||
41b2008a66 | |||
7aefe123e9 | |||
fda49f2b52 | |||
d6f4c515f5 | |||
c71ab2a6a3 | |||
7842559353 | |||
6e3b58e491 | |||
365576620a | |||
15166f880b | |||
ad5b5a4895 | |||
d8e55a5cc3 | |||
e885a2912b | |||
ebf2aabd25 | |||
60b780c21b | |||
76148515fa | |||
ff84352fb7 | |||
f371e6c81a | |||
046411866b | |||
ca8cb65b73 | |||
07baf66200 | |||
1a96798642 | |||
1c364b6beb | |||
c8a9a4e76d | |||
d09ead546c | |||
f86707713c | |||
3054fd4811 | |||
7da8ebdfd0 | |||
44147d057d | |||
190c1b688a | |||
05cae69d72 | |||
087949227c | |||
3f4ce70d92 | |||
11f65cf885 | |||
a5b977aa90 | |||
0f1cdfa53a | |||
81ceac1b96 | |||
5245bd7b20 | |||
8216bb901c | |||
55b7c14554 | |||
75522f95ce | |||
a9c058dfe0 | |||
9ed166c196 | |||
44e5ff7d15 | |||
6244b10a8f | |||
fdccce781e | |||
8c012e103f | |||
6f415b96b3 | |||
4ed3509a02 | |||
c4f224932f | |||
63c6cedb14 | |||
4b2dd44711 | |||
2d627995cf | |||
b40c796ff7 | |||
1d7bf3d39f | |||
6d497f61c6 | |||
9da0232eef | |||
0275fcb3d3 | |||
abdfcda4dd | |||
84bc93d8cb | |||
eedb25b22a | |||
c6faa18ec9 | |||
6c27e2aaf6 | |||
0b493910d3 | |||
4ab0cedf42 | |||
2729e6294a | |||
ed621aae33 | |||
e822f440b0 | |||
d65b64c884 | |||
89c9320d80 | |||
43ceb0f5c7 | |||
7ab87f9f6e | |||
b94a76d17e | |||
8c28126984 | |||
94e525ae12 | |||
328ef60b85 | |||
94e4aa6ea9 | |||
067e66b348 | |||
fc6a5ae3ec | |||
6a831ca015 | |||
8b4605c336 | |||
246db4250b | |||
45152dead5 | |||
10fc733767 | |||
912cf7ba04 | |||
0f51ee6c88 | |||
dcdb4554d7 | |||
cf5ad266f6 | |||
d754c25cc8 | |||
24cca2f18d | |||
28c32d1b1b | |||
2bb0e48a7b | |||
9dd12a64a7 | |||
9b27fb91c0 | |||
36c0db2ac9 | |||
140d883901 | |||
d09a6e5421 | |||
5197aed7db | |||
ec7a2c3442 | |||
5721c43585 | |||
ca31d71107 | |||
08befff8f1 | |||
770a0e7839 | |||
b26f5e0bb7 | |||
fa4aefee44 | |||
8610314918 | |||
71d9367edc | |||
122d2db095 | |||
0cd72369f7 | |||
02f785af70 | |||
c9ed9d253a | |||
48fb0c3213 | |||
ea2718c946 | |||
edbd902a1b | |||
3ec159ab6b | |||
c9a546c310 | |||
827bccb64b | |||
14e7192d9c | |||
9085b10508 | |||
0fa9d2431f | |||
8a76b45253 | |||
8962af2e42 | |||
55bf5051ad | |||
5a692ba4f6 | |||
147a699c65 | |||
32e1b104f8 | |||
55b60e699b | |||
e7e2cbfc01 | |||
5b14fdb94b | |||
057d36b049 | |||
a906a84950 | |||
b7fc85d68e | |||
b4818a003a | |||
0e703d92ac | |||
12b90600eb | |||
2587b0ea62 | |||
f082c1b895 | |||
d51d74eb55 | |||
35806ccc1c | |||
b25e8b7079 | |||
e5d7627427 | |||
a225ef9c13 | |||
b6e137b2b4 | |||
03178a77b6 | |||
16038b4e67 | |||
109f995684 | |||
75f5ae80fd | |||
9138955ba5 | |||
4baa5ca963 | |||
598e454d46 | |||
9f467c387a | |||
8add3bb009 | |||
29b0480cfb | |||
e84bbcce3c | |||
e1fe75e3b6 | |||
a8bc2181c9 | |||
67effb94b6 | |||
705beb4c25 | |||
74706a0f02 | |||
8e4512a5e7 | |||
651030c98d | |||
62671c93c4 | |||
3b9808f23c | |||
e3253b5d5e | |||
27e0d2a973 | |||
5479be9f64 | |||
903b95fffa | |||
020006a8ed | |||
5235e01b8d | |||
7595716816 | |||
3f91ee4ff8 | |||
8951a03db3 | |||
e13f413ef5 | |||
69f7a1da5a | |||
912ae80350 | |||
12650e16d3 | |||
34729c365b | |||
bf5f0b1d0c | |||
4b29e5ba85 | |||
14955bd454 | |||
de12183d38 | |||
6019f1bb0a | |||
f5ce848cfe | |||
70867904a0 | |||
2c532a7255 | |||
aada35af9b | |||
be2b0501b5 | |||
3590591e67 | |||
222249e622 | |||
b2f2806055 | |||
9253fc337e | |||
612f01400f | |||
3630432dfb | |||
f539ed1e66 | |||
5076170f34 | |||
6078aa08eb | |||
64174f196f | |||
6a674ffea5 | |||
b1f7b5d1f6 | |||
c37389f19c | |||
a55f408c10 | |||
39b1fe8e44 | |||
365eea9fba | |||
4de8213887 | |||
68898a4d6b | |||
e1a0ee8fc5 | |||
278183c7e7 | |||
ceea1a7051 | |||
eae0927597 | |||
3083ec5e32 | |||
2f2dd80e48 | |||
d74ee40c86 | |||
e6b143b00d | |||
3386ecb59a | |||
52b4e51366 | |||
0a85260bcd | |||
245f30c59b | |||
fd38ea4149 | |||
6c2f6f5b03 | |||
a6b46420d0 | |||
f6f81169fe | |||
03faccfb08 | |||
0de13b0bba | |||
eafdc1f8e3 | |||
5044eb4b26 | |||
b419e2631a | |||
cc318ff8db | |||
e221a449e0 | |||
9e1fd70b50 | |||
1440f9a37a | |||
9f38ef5d97 | |||
64564da20b | |||
7b93341836 | |||
dbdc5fd4b3 | |||
2f249fea44 | |||
394826f520 | |||
c31f8e2bd7 | |||
f1ce5877ba | |||
8a7fb5fd34 | |||
97433f5ef1 | |||
ba295ec6fe | |||
b2b9b3b567 | |||
7381be8edb | |||
f7415c0bbc | |||
6539ccae7c | |||
01ddaf5670 | |||
f5e112ae5a | |||
821b578f7e | |||
6ad817e17b | |||
13e662f6de | |||
054abe20b8 | |||
8c25a83708 | |||
2c1c78a6d9 | |||
cbd3ae6906 | |||
af24c271c7 | |||
3ea9868b65 | |||
4600ecb5c7 | |||
f1cc3619f5 | |||
af28736bd0 | |||
06a041589f | |||
bed80133e0 | |||
1da145675d | |||
a61e6788db | |||
90b672f1af | |||
bf7dcfce36 | |||
907848997b | |||
207bd55751 | |||
84cd618585 | |||
ef8744d9fc | |||
ff1630834c | |||
52db6d8be5 | |||
e8b22b9253 | |||
9bde7fd72e | |||
8fe8ec84f6 | |||
0300eef94d | |||
6b83a0a589 | |||
adaa49d2cc | |||
3c8227b935 | |||
6f54eb6d9a | |||
00ec4132f8 | |||
e1d1417729 | |||
00f59f5014 | |||
b0ae84aa0d | |||
ea893aca8f | |||
d92172f3d4 | |||
4201a18117 | |||
22b694ee1e | |||
f9abcee0f9 | |||
9617aa8e19 | |||
f5af1fdca8 | |||
648b352424 | |||
79042223dc | |||
b14ee6ce16 | |||
8dac28f2e3 | |||
87a05c8f38 | |||
32b8565022 | |||
af8ada45e7 | |||
46d6470c43 | |||
9b825e2728 | |||
748263d2f0 | |||
7d9a13e0d5 | |||
6c2ad7b72e | |||
b7baceefda | |||
4755caeb2d | |||
5422fe5125 | |||
bd0c0a633b | |||
d6adadc5e3 | |||
0864f1fc8e | |||
f14feea436 | |||
36a4ba3248 | |||
40717465bc | |||
59c0d01418 | |||
bc5e60cd63 | |||
fe41bd6fe8 | |||
a3a5f8b593 | |||
54b5c8273d | |||
a2598e649d | |||
62d76b8e1f | |||
a528bd04db | |||
677796b351 | |||
6a72cd45e2 | |||
1d51cada3c | |||
d381d9a74c | |||
60561cdca2 | |||
7778740315 | |||
c67424ecc8 | |||
36419defd1 | |||
67d44519ce | |||
54f0f82dd1 | |||
e323f0e831 | |||
280b7f23af | |||
915fc0e581 | |||
3a51d5e80c | |||
443d024843 | |||
27782bbade | |||
426c70ac0b | |||
28ba374f27 | |||
ad99089567 | |||
69f8a1b01a | |||
61e8296bd8 | |||
4b2ee6c30c |
47
.mailmap
@ -11,4 +11,51 @@ Nick Savers <nicksavers@gmail.com>
|
|||||||
|
|
||||||
Maran Hidskes <maran.hidskes@gmail.com>
|
Maran Hidskes <maran.hidskes@gmail.com>
|
||||||
|
|
||||||
|
Taylor Gerring <taylor.gerring@gmail.com>
|
||||||
Taylor Gerring <taylor.gerring@gmail.com> <taylor.gerring@ethereum.org>
|
Taylor Gerring <taylor.gerring@gmail.com> <taylor.gerring@ethereum.org>
|
||||||
|
|
||||||
|
Bas van Kervel <bas@ethdev.com>
|
||||||
|
Bas van Kervel <bas@ethdev.com> <basvankervel@ziggo.nl>
|
||||||
|
Bas van Kervel <bas@ethdev.com> <basvankervel@gmail.com>
|
||||||
|
|
||||||
|
Sven Ehlert <sven@ethdev.com>
|
||||||
|
|
||||||
|
Vitalik Buterin <v@buterin.com>
|
||||||
|
|
||||||
|
Marian Oancea <contact@siteshop.ro>
|
||||||
|
|
||||||
|
Christoph Jentzsch <jentzsch.software@gmail.com>
|
||||||
|
|
||||||
|
Heiko Hees <heiko@heiko.org>
|
||||||
|
|
||||||
|
Alex Leverington <alex@ethdev.com>
|
||||||
|
Alex Leverington <alex@ethdev.com> <subtly@users.noreply.github.com>
|
||||||
|
|
||||||
|
Zsolt Felföldi <zsfelfoldi@gmail.com>
|
||||||
|
|
||||||
|
Gavin Wood <i@gavwood.com>
|
||||||
|
|
||||||
|
Martin Becze <mjbecze@gmail.com>
|
||||||
|
Martin Becze <mjbecze@gmail.com> <wanderer@users.noreply.github.com>
|
||||||
|
|
||||||
|
Dimitry Khokhlov <winsvega@mail.ru>
|
||||||
|
|
||||||
|
Roman Mandeleil <roman.mandeleil@gmail.com>
|
||||||
|
|
||||||
|
Alec Perseghin <aperseghin@gmail.com>
|
||||||
|
|
||||||
|
Alon Muroch <alonmuroch@gmail.com>
|
||||||
|
|
||||||
|
Arkadiy Paronyan <arkadiy@ethdev.com>
|
||||||
|
|
||||||
|
Jae Kwon <jkwon.work@gmail.com>
|
||||||
|
|
||||||
|
Aaron Kumavis <kumavis@users.noreply.github.com>
|
||||||
|
|
||||||
|
Nick Dodson <silentcicero@outlook.com>
|
||||||
|
|
||||||
|
Jason Carver <jacarver@linkedin.com>
|
||||||
|
Jason Carver <jacarver@linkedin.com> <ut96caarrs@snkmail.com>
|
||||||
|
|
||||||
|
Joseph Chow <ethereum@outlook.com>
|
||||||
|
Joseph Chow <ethereum@outlook.com> ethers <TODO>
|
||||||
|
11
.travis.yml
@ -2,9 +2,8 @@ language: go
|
|||||||
go:
|
go:
|
||||||
- 1.4.2
|
- 1.4.2
|
||||||
before_install:
|
before_install:
|
||||||
- sudo add-apt-repository ppa:beineri/opt-qt541 -y
|
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
- sudo apt-get install -yqq libgmp3-dev qt54quickcontrols qt54webengine
|
- sudo apt-get install -yqq libgmp3-dev
|
||||||
install:
|
install:
|
||||||
# - go get code.google.com/p/go.tools/cmd/goimports
|
# - go get code.google.com/p/go.tools/cmd/goimports
|
||||||
# - go get github.com/golang/lint/golint
|
# - go get github.com/golang/lint/golint
|
||||||
@ -22,14 +21,12 @@ after_success:
|
|||||||
- if [ "$COVERALLS_TOKEN" ]; then goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN; fi
|
- if [ "$COVERALLS_TOKEN" ]; then goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN; fi
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- PKG_CONFIG_PATH=/opt/qt54/lib/pkgconfig
|
|
||||||
- LD_LIBRARY_PATH=/opt/qt54/lib
|
|
||||||
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
|
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
webhooks:
|
webhooks:
|
||||||
urls:
|
urls:
|
||||||
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
|
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
|
||||||
on_success: change # options: [always|never|change] default: always
|
on_success: change
|
||||||
on_failure: always # options: [always|never|change] default: always
|
on_failure: always
|
||||||
on_start: false # default: false
|
on_start: false
|
||||||
|
24
AUTHORS
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# This is the official list of go-ethereum authors for copyright purposes.
|
||||||
|
|
||||||
|
Alex Leverington <alex@ethdev.com>
|
||||||
|
Alexandre Van de Sande <alex.vandesande@ethdev.com>
|
||||||
|
Bas van Kervel <bas@ethdev.com>
|
||||||
|
Daniel A. Nagy <nagy.da@gmail.com>
|
||||||
|
Ethan Buchman <ethan@coinculture.info>
|
||||||
|
Fabian Vogelsteller <fabian@frozeman.de>
|
||||||
|
Felix Lange <fjl@twurst.com>
|
||||||
|
Gustav Simonsson <gustav.simonsson@gmail.com>
|
||||||
|
Jae Kwon <jkwon.work@gmail.com>
|
||||||
|
Jason Carver <jacarver@linkedin.com>
|
||||||
|
Jeffrey Wilcke <jeffrey@ethereum.org>
|
||||||
|
Joseph Chow <ethereum@outlook.com>
|
||||||
|
Kobi Gurkan <kobigurk@gmail.com>
|
||||||
|
Maran Hidskes <maran.hidskes@gmail.com>
|
||||||
|
Marek Kotewicz <marek.kotewicz@gmail.com>
|
||||||
|
Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
|
||||||
|
Nick Dodson <silentcicero@outlook.com>
|
||||||
|
Péter Szilágyi <peterke@gmail.com>
|
||||||
|
Taylor Gerring <taylor.gerring@gmail.com>
|
||||||
|
Viktor Trón <viktor.tron@gmail.com>
|
||||||
|
Vitalik Buterin <v@buterin.com>
|
||||||
|
Zsolt Felföldi <zsfelfoldi@gmail.com>
|
619
COPYING
Normal file
@ -0,0 +1,619 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2014 The go-ethereum Authors.
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
@ -1,23 +1,3 @@
|
|||||||
This software is licensed under the LGPLv3, included below.
|
|
||||||
|
|
||||||
As a special exception to the GNU Lesser General Public License version 3
|
|
||||||
("LGPL3"), the copyright holders of this Library give you permission to
|
|
||||||
convey to a third party a Combined Work that links statically or dynamically
|
|
||||||
to this Library without providing any Minimal Corresponding Source or
|
|
||||||
Minimal Application Code as set out in 4d or providing the installation
|
|
||||||
information set out in section 4e, provided that you comply with the other
|
|
||||||
provisions of LGPL3 and provided that you meet, for the Application the
|
|
||||||
terms and conditions of the license(s) which apply to the Application.
|
|
||||||
|
|
||||||
Except as stated in this special exception, the provisions of LGPL3 will
|
|
||||||
continue to comply in full to this Library. If you modify this Library, you
|
|
||||||
may apply this exception to your version of this Library, but you are not
|
|
||||||
obliged to do so. If you do not wish to do so, delete this exception
|
|
||||||
statement from your version. This exception does not (and cannot) modify any
|
|
||||||
license terms which apply to the Application, with which you must still
|
|
||||||
comply.
|
|
||||||
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
43
Godeps/Godeps.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ImportPath": "github.com/ethereum/go-ethereum",
|
"ImportPath": "github.com/ethereum/go-ethereum",
|
||||||
"GoVersion": "go1.4.2",
|
"GoVersion": "go1.4",
|
||||||
"Packages": [
|
"Packages": [
|
||||||
"./..."
|
"./..."
|
||||||
],
|
],
|
||||||
@ -15,10 +15,18 @@
|
|||||||
"Comment": "1.2.0-95-g9b2bd2b",
|
"Comment": "1.2.0-95-g9b2bd2b",
|
||||||
"Rev": "9b2bd2b3489748d4d0a204fa4eb2ee9e89e0ebc6"
|
"Rev": "9b2bd2b3489748d4d0a204fa4eb2ee9e89e0ebc6"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/davecgh/go-spew/spew",
|
||||||
|
"Rev": "3e6e67c4dcea3ac2f25fd4731abc0e1deaf36216"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/ethereum/ethash",
|
"ImportPath": "github.com/ethereum/ethash",
|
||||||
"Comment": "v23.1-206-gf0e6321",
|
"Comment": "v23.1-227-g8f6ccaa",
|
||||||
"Rev": "f0e63218b721dc2f696920a92d5de1f6364e9bf7"
|
"Rev": "8f6ccaaef9b418553807a73a95cb5f49cd3ea39f"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/gizak/termui",
|
||||||
|
"Rev": "bab8dce01c193d82bc04888a0a9a7814d505f532"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/howeyc/fsnotify",
|
"ImportPath": "github.com/howeyc/fsnotify",
|
||||||
@ -27,7 +35,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/huin/goupnp",
|
"ImportPath": "github.com/huin/goupnp",
|
||||||
"Rev": "c57ae84388ab59076fd547f1abeab71c2edb0a21"
|
"Rev": "5cff77a69fb22f5f1774c4451ea2aab63d4d2f20"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/jackpal/go-nat-pmp",
|
"ImportPath": "github.com/jackpal/go-nat-pmp",
|
||||||
@ -46,20 +54,21 @@
|
|||||||
"Rev": "fdbe02a1b44e75977b2690062b83cf507d70c013"
|
"Rev": "fdbe02a1b44e75977b2690062b83cf507d70c013"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/obscuren/qml",
|
"ImportPath": "github.com/mattn/go-runewidth",
|
||||||
"Rev": "c288002b52e905973b131089a8a7c761d4a2c36a"
|
"Comment": "travisish-33-g5890272",
|
||||||
|
"Rev": "5890272cd41c5103531cd7b79e428d99c9e97f76"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/nsf/termbox-go",
|
||||||
|
"Rev": "675ffd907b7401b8a709a5ef2249978af5616bb2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/peterh/liner",
|
"ImportPath": "github.com/peterh/liner",
|
||||||
"Rev": "29f6a646557d83e2b6e9ba05c45fbea9c006dbe8"
|
"Rev": "29f6a646557d83e2b6e9ba05c45fbea9c006dbe8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/rakyll/globalconf",
|
"ImportPath": "github.com/rcrowley/go-metrics",
|
||||||
"Rev": "415abc325023f1a00cd2d9fa512e0e71745791a2"
|
"Rev": "a5cfc242a56ba7fa70b785f678d6214837bf93b9"
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/rakyll/goini",
|
|
||||||
"Rev": "907cca0f578a5316fb864ec6992dc3d9730ec58c"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/robertkrimen/otto",
|
"ImportPath": "github.com/robertkrimen/otto",
|
||||||
@ -112,15 +121,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/karalabe/cookiejar.v2/collections/prque",
|
"ImportPath": "gopkg.in/karalabe/cookiejar.v2/collections/prque",
|
||||||
"Rev": "0b2e270613f5d7ba262a5749b9e32270131497a2"
|
"Rev": "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57"
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "gopkg.in/qml.v1/cdata",
|
|
||||||
"Rev": "1116cb9cd8dee23f8d444ded354eb53122739f99"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "gopkg.in/qml.v1/gl/glbase",
|
|
||||||
"Rev": "1116cb9cd8dee23f8d444ded354eb53122739f99"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
450
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go
generated
vendored
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ptrSize is the size of a pointer on the current arch.
|
||||||
|
ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
|
||||||
|
// internal reflect.Value fields. These values are valid before golang
|
||||||
|
// commit ecccf07e7f9d which changed the format. The are also valid
|
||||||
|
// after commit 82f48826c6c7 which changed the format again to mirror
|
||||||
|
// the original format. Code in the init function updates these offsets
|
||||||
|
// as necessary.
|
||||||
|
offsetPtr = uintptr(ptrSize)
|
||||||
|
offsetScalar = uintptr(0)
|
||||||
|
offsetFlag = uintptr(ptrSize * 2)
|
||||||
|
|
||||||
|
// flagKindWidth and flagKindShift indicate various bits that the
|
||||||
|
// reflect package uses internally to track kind information.
|
||||||
|
//
|
||||||
|
// flagRO indicates whether or not the value field of a reflect.Value is
|
||||||
|
// read-only.
|
||||||
|
//
|
||||||
|
// flagIndir indicates whether the value field of a reflect.Value is
|
||||||
|
// the actual data or a pointer to the data.
|
||||||
|
//
|
||||||
|
// These values are valid before golang commit 90a7c3c86944 which
|
||||||
|
// changed their positions. Code in the init function updates these
|
||||||
|
// flags as necessary.
|
||||||
|
flagKindWidth = uintptr(5)
|
||||||
|
flagKindShift = uintptr(flagKindWidth - 1)
|
||||||
|
flagRO = uintptr(1 << 0)
|
||||||
|
flagIndir = uintptr(1 << 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Older versions of reflect.Value stored small integers directly in the
|
||||||
|
// ptr field (which is named val in the older versions). Versions
|
||||||
|
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
|
||||||
|
// scalar for this purpose which unfortunately came before the flag
|
||||||
|
// field, so the offset of the flag field is different for those
|
||||||
|
// versions.
|
||||||
|
//
|
||||||
|
// This code constructs a new reflect.Value from a known small integer
|
||||||
|
// and checks if the size of the reflect.Value struct indicates it has
|
||||||
|
// the scalar field. When it does, the offsets are updated accordingly.
|
||||||
|
vv := reflect.ValueOf(0xf00)
|
||||||
|
if unsafe.Sizeof(vv) == (ptrSize * 4) {
|
||||||
|
offsetScalar = ptrSize * 2
|
||||||
|
offsetFlag = ptrSize * 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit 90a7c3c86944 changed the flag positions such that the low
|
||||||
|
// order bits are the kind. This code extracts the kind from the flags
|
||||||
|
// field and ensures it's the correct type. When it's not, the flag
|
||||||
|
// order has been changed to the newer format, so the flags are updated
|
||||||
|
// accordingly.
|
||||||
|
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
|
||||||
|
upfv := *(*uintptr)(upf)
|
||||||
|
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
|
||||||
|
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
|
||||||
|
flagKindShift = 0
|
||||||
|
flagRO = 1 << 5
|
||||||
|
flagIndir = 1 << 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
||||||
|
// the typical safety restrictions preventing access to unaddressable and
|
||||||
|
// unexported data. It works by digging the raw pointer to the underlying
|
||||||
|
// value out of the protected value and generating a new unprotected (unsafe)
|
||||||
|
// reflect.Value to it.
|
||||||
|
//
|
||||||
|
// This allows us to check for implementations of the Stringer and error
|
||||||
|
// interfaces to be used for pretty printing ordinarily unaddressable and
|
||||||
|
// inaccessible values such as unexported struct fields.
|
||||||
|
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
|
||||||
|
indirects := 1
|
||||||
|
vt := v.Type()
|
||||||
|
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
|
||||||
|
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
|
||||||
|
if rvf&flagIndir != 0 {
|
||||||
|
vt = reflect.PtrTo(v.Type())
|
||||||
|
indirects++
|
||||||
|
} else if offsetScalar != 0 {
|
||||||
|
// The value is in the scalar field when it's not one of the
|
||||||
|
// reference types.
|
||||||
|
switch vt.Kind() {
|
||||||
|
case reflect.Uintptr:
|
||||||
|
case reflect.Chan:
|
||||||
|
case reflect.Func:
|
||||||
|
case reflect.Map:
|
||||||
|
case reflect.Ptr:
|
||||||
|
case reflect.UnsafePointer:
|
||||||
|
default:
|
||||||
|
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
|
||||||
|
offsetScalar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pv := reflect.NewAt(vt, upv)
|
||||||
|
rv = pv
|
||||||
|
for i := 0; i < indirects; i++ {
|
||||||
|
rv = rv.Elem()
|
||||||
|
}
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some constants in the form of bytes to avoid string overhead. This mirrors
|
||||||
|
// the technique used in the fmt package.
|
||||||
|
var (
|
||||||
|
panicBytes = []byte("(PANIC=")
|
||||||
|
plusBytes = []byte("+")
|
||||||
|
iBytes = []byte("i")
|
||||||
|
trueBytes = []byte("true")
|
||||||
|
falseBytes = []byte("false")
|
||||||
|
interfaceBytes = []byte("(interface {})")
|
||||||
|
commaNewlineBytes = []byte(",\n")
|
||||||
|
newlineBytes = []byte("\n")
|
||||||
|
openBraceBytes = []byte("{")
|
||||||
|
openBraceNewlineBytes = []byte("{\n")
|
||||||
|
closeBraceBytes = []byte("}")
|
||||||
|
asteriskBytes = []byte("*")
|
||||||
|
colonBytes = []byte(":")
|
||||||
|
colonSpaceBytes = []byte(": ")
|
||||||
|
openParenBytes = []byte("(")
|
||||||
|
closeParenBytes = []byte(")")
|
||||||
|
spaceBytes = []byte(" ")
|
||||||
|
pointerChainBytes = []byte("->")
|
||||||
|
nilAngleBytes = []byte("<nil>")
|
||||||
|
maxNewlineBytes = []byte("<max depth reached>\n")
|
||||||
|
maxShortBytes = []byte("<max>")
|
||||||
|
circularBytes = []byte("<already shown>")
|
||||||
|
circularShortBytes = []byte("<shown>")
|
||||||
|
invalidAngleBytes = []byte("<invalid>")
|
||||||
|
openBracketBytes = []byte("[")
|
||||||
|
closeBracketBytes = []byte("]")
|
||||||
|
percentBytes = []byte("%")
|
||||||
|
precisionBytes = []byte(".")
|
||||||
|
openAngleBytes = []byte("<")
|
||||||
|
closeAngleBytes = []byte(">")
|
||||||
|
openMapBytes = []byte("map[")
|
||||||
|
closeMapBytes = []byte("]")
|
||||||
|
lenEqualsBytes = []byte("len=")
|
||||||
|
capEqualsBytes = []byte("cap=")
|
||||||
|
)
|
||||||
|
|
||||||
|
// hexDigits is used to map a decimal value to a hex digit.
|
||||||
|
var hexDigits = "0123456789abcdef"
|
||||||
|
|
||||||
|
// catchPanic handles any panics that might occur during the handleMethods
|
||||||
|
// calls.
|
||||||
|
func catchPanic(w io.Writer, v reflect.Value) {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
w.Write(panicBytes)
|
||||||
|
fmt.Fprintf(w, "%v", err)
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleMethods attempts to call the Error and String methods on the underlying
|
||||||
|
// type the passed reflect.Value represents and outputes the result to Writer w.
|
||||||
|
//
|
||||||
|
// It handles panics in any called methods by catching and displaying the error
|
||||||
|
// as the formatted value.
|
||||||
|
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
|
||||||
|
// We need an interface to check if the type implements the error or
|
||||||
|
// Stringer interface. However, the reflect package won't give us an
|
||||||
|
// interface on certain things like unexported struct fields in order
|
||||||
|
// to enforce visibility rules. We use unsafe to bypass these restrictions
|
||||||
|
// since this package does not mutate the values.
|
||||||
|
if !v.CanInterface() {
|
||||||
|
v = unsafeReflectValue(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose whether or not to do error and Stringer interface lookups against
|
||||||
|
// the base type or a pointer to the base type depending on settings.
|
||||||
|
// Technically calling one of these methods with a pointer receiver can
|
||||||
|
// mutate the value, however, types which choose to satisify an error or
|
||||||
|
// Stringer interface with a pointer receiver should not be mutating their
|
||||||
|
// state inside these interface methods.
|
||||||
|
var viface interface{}
|
||||||
|
if !cs.DisablePointerMethods {
|
||||||
|
if !v.CanAddr() {
|
||||||
|
v = unsafeReflectValue(v)
|
||||||
|
}
|
||||||
|
viface = v.Addr().Interface()
|
||||||
|
} else {
|
||||||
|
if v.CanAddr() {
|
||||||
|
v = v.Addr()
|
||||||
|
}
|
||||||
|
viface = v.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it an error or Stringer?
|
||||||
|
switch iface := viface.(type) {
|
||||||
|
case error:
|
||||||
|
defer catchPanic(w, v)
|
||||||
|
if cs.ContinueOnMethod {
|
||||||
|
w.Write(openParenBytes)
|
||||||
|
w.Write([]byte(iface.Error()))
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
w.Write(spaceBytes)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(iface.Error()))
|
||||||
|
return true
|
||||||
|
|
||||||
|
case fmt.Stringer:
|
||||||
|
defer catchPanic(w, v)
|
||||||
|
if cs.ContinueOnMethod {
|
||||||
|
w.Write(openParenBytes)
|
||||||
|
w.Write([]byte(iface.String()))
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
w.Write(spaceBytes)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
w.Write([]byte(iface.String()))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// printBool outputs a boolean value as true or false to Writer w.
|
||||||
|
func printBool(w io.Writer, val bool) {
|
||||||
|
if val {
|
||||||
|
w.Write(trueBytes)
|
||||||
|
} else {
|
||||||
|
w.Write(falseBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printInt outputs a signed integer value to Writer w.
|
||||||
|
func printInt(w io.Writer, val int64, base int) {
|
||||||
|
w.Write([]byte(strconv.FormatInt(val, base)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printUint outputs an unsigned integer value to Writer w.
|
||||||
|
func printUint(w io.Writer, val uint64, base int) {
|
||||||
|
w.Write([]byte(strconv.FormatUint(val, base)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printFloat outputs a floating point value using the specified precision,
|
||||||
|
// which is expected to be 32 or 64bit, to Writer w.
|
||||||
|
func printFloat(w io.Writer, val float64, precision int) {
|
||||||
|
w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printComplex outputs a complex value using the specified float precision
|
||||||
|
// for the real and imaginary parts to Writer w.
|
||||||
|
func printComplex(w io.Writer, c complex128, floatPrecision int) {
|
||||||
|
r := real(c)
|
||||||
|
w.Write(openParenBytes)
|
||||||
|
w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
|
||||||
|
i := imag(c)
|
||||||
|
if i >= 0 {
|
||||||
|
w.Write(plusBytes)
|
||||||
|
}
|
||||||
|
w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
|
||||||
|
w.Write(iBytes)
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
|
||||||
|
// prefix to Writer w.
|
||||||
|
func printHexPtr(w io.Writer, p uintptr) {
|
||||||
|
// Null pointer.
|
||||||
|
num := uint64(p)
|
||||||
|
if num == 0 {
|
||||||
|
w.Write(nilAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
|
||||||
|
buf := make([]byte, 18)
|
||||||
|
|
||||||
|
// It's simpler to construct the hex string right to left.
|
||||||
|
base := uint64(16)
|
||||||
|
i := len(buf) - 1
|
||||||
|
for num >= base {
|
||||||
|
buf[i] = hexDigits[num%base]
|
||||||
|
num /= base
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
buf[i] = hexDigits[num]
|
||||||
|
|
||||||
|
// Add '0x' prefix.
|
||||||
|
i--
|
||||||
|
buf[i] = 'x'
|
||||||
|
i--
|
||||||
|
buf[i] = '0'
|
||||||
|
|
||||||
|
// Strip unused leading bytes.
|
||||||
|
buf = buf[i:]
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
|
||||||
|
// elements to be sorted.
|
||||||
|
type valuesSorter struct {
|
||||||
|
values []reflect.Value
|
||||||
|
strings []string // either nil or same len and values
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// newValuesSorter initializes a valuesSorter instance, which holds a set of
|
||||||
|
// surrogate keys on which the data should be sorted. It uses flags in
|
||||||
|
// ConfigState to decide if and how to populate those surrogate keys.
|
||||||
|
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
|
||||||
|
vs := &valuesSorter{values: values, cs: cs}
|
||||||
|
if canSortSimply(vs.values[0].Kind()) {
|
||||||
|
return vs
|
||||||
|
}
|
||||||
|
if !cs.DisableMethods {
|
||||||
|
vs.strings = make([]string, len(values))
|
||||||
|
for i := range vs.values {
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
if !handleMethods(cs, &b, vs.values[i]) {
|
||||||
|
vs.strings = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
vs.strings[i] = b.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if vs.strings == nil && cs.SpewKeys {
|
||||||
|
vs.strings = make([]string, len(values))
|
||||||
|
for i := range vs.values {
|
||||||
|
vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vs
|
||||||
|
}
|
||||||
|
|
||||||
|
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
|
||||||
|
// directly, or whether it should be considered for sorting by surrogate keys
|
||||||
|
// (if the ConfigState allows it).
|
||||||
|
func canSortSimply(kind reflect.Kind) bool {
|
||||||
|
// This switch parallels valueSortLess, except for the default case.
|
||||||
|
switch kind {
|
||||||
|
case reflect.Bool:
|
||||||
|
return true
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
return true
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
return true
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return true
|
||||||
|
case reflect.String:
|
||||||
|
return true
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return true
|
||||||
|
case reflect.Array:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of values in the slice. It is part of the
|
||||||
|
// sort.Interface implementation.
|
||||||
|
func (s *valuesSorter) Len() int {
|
||||||
|
return len(s.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap swaps the values at the passed indices. It is part of the
|
||||||
|
// sort.Interface implementation.
|
||||||
|
func (s *valuesSorter) Swap(i, j int) {
|
||||||
|
s.values[i], s.values[j] = s.values[j], s.values[i]
|
||||||
|
if s.strings != nil {
|
||||||
|
s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// valueSortLess returns whether the first value should sort before the second
|
||||||
|
// value. It is used by valueSorter.Less as part of the sort.Interface
|
||||||
|
// implementation.
|
||||||
|
func valueSortLess(a, b reflect.Value) bool {
|
||||||
|
switch a.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return !a.Bool() && b.Bool()
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
return a.Int() < b.Int()
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
return a.Uint() < b.Uint()
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return a.Float() < b.Float()
|
||||||
|
case reflect.String:
|
||||||
|
return a.String() < b.String()
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return a.Uint() < b.Uint()
|
||||||
|
case reflect.Array:
|
||||||
|
// Compare the contents of both arrays.
|
||||||
|
l := a.Len()
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
av := a.Index(i)
|
||||||
|
bv := b.Index(i)
|
||||||
|
if av.Interface() == bv.Interface() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return valueSortLess(av, bv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a.String() < b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less returns whether the value at index i should sort before the
|
||||||
|
// value at index j. It is part of the sort.Interface implementation.
|
||||||
|
func (s *valuesSorter) Less(i, j int) bool {
|
||||||
|
if s.strings == nil {
|
||||||
|
return valueSortLess(s.values[i], s.values[j])
|
||||||
|
}
|
||||||
|
return s.strings[i] < s.strings[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// sortValues is a sort function that handles both native types and any type that
|
||||||
|
// can be converted to error or Stringer. Other inputs are sorted according to
|
||||||
|
// their Value.String() value to ensure display stability.
|
||||||
|
func sortValues(values []reflect.Value, cs *ConfigState) {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sort.Sort(newValuesSorter(values, cs))
|
||||||
|
}
|
298
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go
generated
vendored
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
// custom type to test Stinger interface on non-pointer receiver.
|
||||||
|
type stringer string
|
||||||
|
|
||||||
|
// String implements the Stringer interface for testing invocation of custom
|
||||||
|
// stringers on types with non-pointer receivers.
|
||||||
|
func (s stringer) String() string {
|
||||||
|
return "stringer " + string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom type to test Stinger interface on pointer receiver.
|
||||||
|
type pstringer string
|
||||||
|
|
||||||
|
// String implements the Stringer interface for testing invocation of custom
|
||||||
|
// stringers on types with only pointer receivers.
|
||||||
|
func (s *pstringer) String() string {
|
||||||
|
return "stringer " + string(*s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// xref1 and xref2 are cross referencing structs for testing circular reference
|
||||||
|
// detection.
|
||||||
|
type xref1 struct {
|
||||||
|
ps2 *xref2
|
||||||
|
}
|
||||||
|
type xref2 struct {
|
||||||
|
ps1 *xref1
|
||||||
|
}
|
||||||
|
|
||||||
|
// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
|
||||||
|
// reference for testing detection.
|
||||||
|
type indirCir1 struct {
|
||||||
|
ps2 *indirCir2
|
||||||
|
}
|
||||||
|
type indirCir2 struct {
|
||||||
|
ps3 *indirCir3
|
||||||
|
}
|
||||||
|
type indirCir3 struct {
|
||||||
|
ps1 *indirCir1
|
||||||
|
}
|
||||||
|
|
||||||
|
// embed is used to test embedded structures.
|
||||||
|
type embed struct {
|
||||||
|
a string
|
||||||
|
}
|
||||||
|
|
||||||
|
// embedwrap is used to test embedded structures.
|
||||||
|
type embedwrap struct {
|
||||||
|
*embed
|
||||||
|
e *embed
|
||||||
|
}
|
||||||
|
|
||||||
|
// panicer is used to intentionally cause a panic for testing spew properly
|
||||||
|
// handles them
|
||||||
|
type panicer int
|
||||||
|
|
||||||
|
func (p panicer) String() string {
|
||||||
|
panic("test panic")
|
||||||
|
}
|
||||||
|
|
||||||
|
// customError is used to test custom error interface invocation.
|
||||||
|
type customError int
|
||||||
|
|
||||||
|
func (e customError) Error() string {
|
||||||
|
return fmt.Sprintf("error: %d", int(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
// stringizeWants converts a slice of wanted test output into a format suitable
|
||||||
|
// for a test error message.
|
||||||
|
func stringizeWants(wants []string) string {
|
||||||
|
s := ""
|
||||||
|
for i, want := range wants {
|
||||||
|
if i > 0 {
|
||||||
|
s += fmt.Sprintf("want%d: %s", i+1, want)
|
||||||
|
} else {
|
||||||
|
s += "want: " + want
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// testFailed returns whether or not a test failed by checking if the result
|
||||||
|
// of the test is in the slice of wanted strings.
|
||||||
|
func testFailed(result string, wants []string) bool {
|
||||||
|
for _, want := range wants {
|
||||||
|
if result == want {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type sortableStruct struct {
|
||||||
|
x int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss sortableStruct) String() string {
|
||||||
|
return fmt.Sprintf("ss.%d", ss.x)
|
||||||
|
}
|
||||||
|
|
||||||
|
type unsortableStruct struct {
|
||||||
|
x int
|
||||||
|
}
|
||||||
|
|
||||||
|
type sortTestCase struct {
|
||||||
|
input []reflect.Value
|
||||||
|
expected []reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
|
||||||
|
getInterfaces := func(values []reflect.Value) []interface{} {
|
||||||
|
interfaces := []interface{}{}
|
||||||
|
for _, v := range values {
|
||||||
|
interfaces = append(interfaces, v.Interface())
|
||||||
|
}
|
||||||
|
return interfaces
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
spew.SortValues(test.input, cs)
|
||||||
|
// reflect.DeepEqual cannot really make sense of reflect.Value,
|
||||||
|
// probably because of all the pointer tricks. For instance,
|
||||||
|
// v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
|
||||||
|
// instead.
|
||||||
|
input := getInterfaces(test.input)
|
||||||
|
expected := getInterfaces(test.expected)
|
||||||
|
if !reflect.DeepEqual(input, expected) {
|
||||||
|
t.Errorf("Sort mismatch:\n %v != %v", input, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSortValues ensures the sort functionality for relect.Value based sorting
|
||||||
|
// works as intended.
|
||||||
|
func TestSortValues(t *testing.T) {
|
||||||
|
v := reflect.ValueOf
|
||||||
|
|
||||||
|
a := v("a")
|
||||||
|
b := v("b")
|
||||||
|
c := v("c")
|
||||||
|
embedA := v(embed{"a"})
|
||||||
|
embedB := v(embed{"b"})
|
||||||
|
embedC := v(embed{"c"})
|
||||||
|
tests := []sortTestCase{
|
||||||
|
// No values.
|
||||||
|
{
|
||||||
|
[]reflect.Value{},
|
||||||
|
[]reflect.Value{},
|
||||||
|
},
|
||||||
|
// Bools.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(false), v(true), v(false)},
|
||||||
|
[]reflect.Value{v(false), v(false), v(true)},
|
||||||
|
},
|
||||||
|
// Ints.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(2), v(1), v(3)},
|
||||||
|
[]reflect.Value{v(1), v(2), v(3)},
|
||||||
|
},
|
||||||
|
// Uints.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
|
||||||
|
[]reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
|
||||||
|
},
|
||||||
|
// Floats.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(2.0), v(1.0), v(3.0)},
|
||||||
|
[]reflect.Value{v(1.0), v(2.0), v(3.0)},
|
||||||
|
},
|
||||||
|
// Strings.
|
||||||
|
{
|
||||||
|
[]reflect.Value{b, a, c},
|
||||||
|
[]reflect.Value{a, b, c},
|
||||||
|
},
|
||||||
|
// Array
|
||||||
|
{
|
||||||
|
[]reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
|
||||||
|
[]reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
|
||||||
|
},
|
||||||
|
// Uintptrs.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
|
||||||
|
[]reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
|
||||||
|
},
|
||||||
|
// SortableStructs.
|
||||||
|
{
|
||||||
|
// Note: not sorted - DisableMethods is set.
|
||||||
|
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
|
||||||
|
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
|
||||||
|
},
|
||||||
|
// UnsortableStructs.
|
||||||
|
{
|
||||||
|
// Note: not sorted - SpewKeys is false.
|
||||||
|
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
||||||
|
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
||||||
|
},
|
||||||
|
// Invalid.
|
||||||
|
{
|
||||||
|
[]reflect.Value{embedB, embedA, embedC},
|
||||||
|
[]reflect.Value{embedB, embedA, embedC},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
|
||||||
|
helpTestSortValues(tests, &cs, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSortValuesWithMethods ensures the sort functionality for relect.Value
|
||||||
|
// based sorting works as intended when using string methods.
|
||||||
|
func TestSortValuesWithMethods(t *testing.T) {
|
||||||
|
v := reflect.ValueOf
|
||||||
|
|
||||||
|
a := v("a")
|
||||||
|
b := v("b")
|
||||||
|
c := v("c")
|
||||||
|
tests := []sortTestCase{
|
||||||
|
// Ints.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(2), v(1), v(3)},
|
||||||
|
[]reflect.Value{v(1), v(2), v(3)},
|
||||||
|
},
|
||||||
|
// Strings.
|
||||||
|
{
|
||||||
|
[]reflect.Value{b, a, c},
|
||||||
|
[]reflect.Value{a, b, c},
|
||||||
|
},
|
||||||
|
// SortableStructs.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
|
||||||
|
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
|
||||||
|
},
|
||||||
|
// UnsortableStructs.
|
||||||
|
{
|
||||||
|
// Note: not sorted - SpewKeys is false.
|
||||||
|
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
||||||
|
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
|
||||||
|
helpTestSortValues(tests, &cs, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSortValuesWithSpew ensures the sort functionality for relect.Value
|
||||||
|
// based sorting works as intended when using spew to stringify keys.
|
||||||
|
func TestSortValuesWithSpew(t *testing.T) {
|
||||||
|
v := reflect.ValueOf
|
||||||
|
|
||||||
|
a := v("a")
|
||||||
|
b := v("b")
|
||||||
|
c := v("c")
|
||||||
|
tests := []sortTestCase{
|
||||||
|
// Ints.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(2), v(1), v(3)},
|
||||||
|
[]reflect.Value{v(1), v(2), v(3)},
|
||||||
|
},
|
||||||
|
// Strings.
|
||||||
|
{
|
||||||
|
[]reflect.Value{b, a, c},
|
||||||
|
[]reflect.Value{a, b, c},
|
||||||
|
},
|
||||||
|
// SortableStructs.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
|
||||||
|
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
|
||||||
|
},
|
||||||
|
// UnsortableStructs.
|
||||||
|
{
|
||||||
|
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
||||||
|
[]reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
|
||||||
|
helpTestSortValues(tests, &cs, t)
|
||||||
|
}
|
294
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go
generated
vendored
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConfigState houses the configuration options used by spew to format and
|
||||||
|
// display values. There is a global instance, Config, that is used to control
|
||||||
|
// all top-level Formatter and Dump functionality. Each ConfigState instance
|
||||||
|
// provides methods equivalent to the top-level functions.
|
||||||
|
//
|
||||||
|
// The zero value for ConfigState provides no indentation. You would typically
|
||||||
|
// want to set it to a space or a tab.
|
||||||
|
//
|
||||||
|
// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
|
||||||
|
// with default settings. See the documentation of NewDefaultConfig for default
|
||||||
|
// values.
|
||||||
|
type ConfigState struct {
|
||||||
|
// Indent specifies the string to use for each indentation level. The
|
||||||
|
// global config instance that all top-level functions use set this to a
|
||||||
|
// single space by default. If you would like more indentation, you might
|
||||||
|
// set this to a tab with "\t" or perhaps two spaces with " ".
|
||||||
|
Indent string
|
||||||
|
|
||||||
|
// MaxDepth controls the maximum number of levels to descend into nested
|
||||||
|
// data structures. The default, 0, means there is no limit.
|
||||||
|
//
|
||||||
|
// NOTE: Circular data structures are properly detected, so it is not
|
||||||
|
// necessary to set this value unless you specifically want to limit deeply
|
||||||
|
// nested data structures.
|
||||||
|
MaxDepth int
|
||||||
|
|
||||||
|
// DisableMethods specifies whether or not error and Stringer interfaces are
|
||||||
|
// invoked for types that implement them.
|
||||||
|
DisableMethods bool
|
||||||
|
|
||||||
|
// DisablePointerMethods specifies whether or not to check for and invoke
|
||||||
|
// error and Stringer interfaces on types which only accept a pointer
|
||||||
|
// receiver when the current type is not a pointer.
|
||||||
|
//
|
||||||
|
// NOTE: This might be an unsafe action since calling one of these methods
|
||||||
|
// with a pointer receiver could technically mutate the value, however,
|
||||||
|
// in practice, types which choose to satisify an error or Stringer
|
||||||
|
// interface with a pointer receiver should not be mutating their state
|
||||||
|
// inside these interface methods.
|
||||||
|
DisablePointerMethods bool
|
||||||
|
|
||||||
|
// ContinueOnMethod specifies whether or not recursion should continue once
|
||||||
|
// a custom error or Stringer interface is invoked. The default, false,
|
||||||
|
// means it will print the results of invoking the custom error or Stringer
|
||||||
|
// interface and return immediately instead of continuing to recurse into
|
||||||
|
// the internals of the data type.
|
||||||
|
//
|
||||||
|
// NOTE: This flag does not have any effect if method invocation is disabled
|
||||||
|
// via the DisableMethods or DisablePointerMethods options.
|
||||||
|
ContinueOnMethod bool
|
||||||
|
|
||||||
|
// SortKeys specifies map keys should be sorted before being printed. Use
|
||||||
|
// this to have a more deterministic, diffable output. Note that only
|
||||||
|
// native types (bool, int, uint, floats, uintptr and string) and types
|
||||||
|
// that support the error or Stringer interfaces (if methods are
|
||||||
|
// enabled) are supported, with other types sorted according to the
|
||||||
|
// reflect.Value.String() output which guarantees display stability.
|
||||||
|
SortKeys bool
|
||||||
|
|
||||||
|
// SpewKeys specifies that, as a last resort attempt, map keys should
|
||||||
|
// be spewed to strings and sorted by those strings. This is only
|
||||||
|
// considered if SortKeys is true.
|
||||||
|
SpewKeys bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is the active configuration of the top-level functions.
|
||||||
|
// The configuration can be changed by modifying the contents of spew.Config.
|
||||||
|
var Config = ConfigState{Indent: " "}
|
||||||
|
|
||||||
|
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the formatted string as a value that satisfies error. See NewFormatter
|
||||||
|
// for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
|
||||||
|
return fmt.Errorf(format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprint(w, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintf(w, format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintln(w, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print is a wrapper for fmt.Print that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Print(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Printf(format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println is a wrapper for fmt.Println that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Println(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Sprint(a ...interface{}) string {
|
||||||
|
return fmt.Sprint(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
|
||||||
|
return fmt.Sprintf(format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
|
||||||
|
// were passed with a Formatter interface returned by c.NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Sprintln(a ...interface{}) string {
|
||||||
|
return fmt.Sprintln(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
||||||
|
interface. As a result, it integrates cleanly with standard fmt package
|
||||||
|
printing functions. The formatter is useful for inline printing of smaller data
|
||||||
|
types similar to the standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
||||||
|
addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
|
||||||
|
combinations. Any other verbs such as %x and %q will be sent to the the
|
||||||
|
standard fmt package for formatting. In addition, the custom formatter ignores
|
||||||
|
the width and precision arguments (however they will still work on the format
|
||||||
|
specifiers not handled by the custom formatter).
|
||||||
|
|
||||||
|
Typically this function shouldn't be called directly. It is much easier to make
|
||||||
|
use of the custom formatter by calling one of the convenience functions such as
|
||||||
|
c.Printf, c.Println, or c.Printf.
|
||||||
|
*/
|
||||||
|
func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
|
||||||
|
return newFormatter(c, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
||||||
|
// exactly the same as Dump.
|
||||||
|
func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
|
||||||
|
fdump(c, w, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dump displays the passed parameters to standard out with newlines, customizable
|
||||||
|
indentation, and additional debug information such as complete types and all
|
||||||
|
pointer addresses used to indirect to the final value. It provides the
|
||||||
|
following features over the built-in printing facilities provided by the fmt
|
||||||
|
package:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
|
includes offsets, byte values in hex, and ASCII output
|
||||||
|
|
||||||
|
The configuration options are controlled by modifying the public members
|
||||||
|
of c. See ConfigState for options documentation.
|
||||||
|
|
||||||
|
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
|
||||||
|
get the formatted result as a string.
|
||||||
|
*/
|
||||||
|
func (c *ConfigState) Dump(a ...interface{}) {
|
||||||
|
fdump(c, os.Stdout, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sdump returns a string with the passed arguments formatted exactly the same
|
||||||
|
// as Dump.
|
||||||
|
func (c *ConfigState) Sdump(a ...interface{}) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fdump(c, &buf, a...)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertArgs accepts a slice of arguments and returns a slice of the same
|
||||||
|
// length with each argument converted to a spew Formatter interface using
|
||||||
|
// the ConfigState associated with s.
|
||||||
|
func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
|
||||||
|
formatters = make([]interface{}, len(args))
|
||||||
|
for index, arg := range args {
|
||||||
|
formatters[index] = newFormatter(c, arg)
|
||||||
|
}
|
||||||
|
return formatters
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultConfig returns a ConfigState with the following default settings.
|
||||||
|
//
|
||||||
|
// Indent: " "
|
||||||
|
// MaxDepth: 0
|
||||||
|
// DisableMethods: false
|
||||||
|
// DisablePointerMethods: false
|
||||||
|
// ContinueOnMethod: false
|
||||||
|
// SortKeys: false
|
||||||
|
func NewDefaultConfig() *ConfigState {
|
||||||
|
return &ConfigState{Indent: " "}
|
||||||
|
}
|
202
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/doc.go
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package spew implements a deep pretty printer for Go data structures to aid in
|
||||||
|
debugging.
|
||||||
|
|
||||||
|
A quick overview of the additional features spew provides over the built-in
|
||||||
|
printing facilities for Go data types are as follows:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
|
includes offsets, byte values in hex, and ASCII output (only when using
|
||||||
|
Dump style)
|
||||||
|
|
||||||
|
There are two different approaches spew allows for dumping Go data structures:
|
||||||
|
|
||||||
|
* Dump style which prints with newlines, customizable indentation,
|
||||||
|
and additional debug information such as types and all pointer addresses
|
||||||
|
used to indirect to the final value
|
||||||
|
* A custom Formatter interface that integrates cleanly with the standard fmt
|
||||||
|
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
|
||||||
|
similar to the default %v while providing the additional functionality
|
||||||
|
outlined above and passing unsupported format verbs such as %x and %q
|
||||||
|
along to fmt
|
||||||
|
|
||||||
|
Quick Start
|
||||||
|
|
||||||
|
This section demonstrates how to quickly get started with spew. See the
|
||||||
|
sections below for further details on formatting and configuration options.
|
||||||
|
|
||||||
|
To dump a variable with full newlines, indentation, type, and pointer
|
||||||
|
information use Dump, Fdump, or Sdump:
|
||||||
|
spew.Dump(myVar1, myVar2, ...)
|
||||||
|
spew.Fdump(someWriter, myVar1, myVar2, ...)
|
||||||
|
str := spew.Sdump(myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
Alternatively, if you would prefer to use format strings with a compacted inline
|
||||||
|
printing style, use the convenience wrappers Printf, Fprintf, etc with
|
||||||
|
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
|
||||||
|
%#+v (adds types and pointer addresses):
|
||||||
|
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
|
||||||
|
Configuration Options
|
||||||
|
|
||||||
|
Configuration of spew is handled by fields in the ConfigState type. For
|
||||||
|
convenience, all of the top-level functions use a global state available
|
||||||
|
via the spew.Config global.
|
||||||
|
|
||||||
|
It is also possible to create a ConfigState instance that provides methods
|
||||||
|
equivalent to the top-level functions. This allows concurrent configuration
|
||||||
|
options. See the ConfigState documentation for more details.
|
||||||
|
|
||||||
|
The following configuration options are available:
|
||||||
|
* Indent
|
||||||
|
String to use for each indentation level for Dump functions.
|
||||||
|
It is a single space by default. A popular alternative is "\t".
|
||||||
|
|
||||||
|
* MaxDepth
|
||||||
|
Maximum number of levels to descend into nested data structures.
|
||||||
|
There is no limit by default.
|
||||||
|
|
||||||
|
* DisableMethods
|
||||||
|
Disables invocation of error and Stringer interface methods.
|
||||||
|
Method invocation is enabled by default.
|
||||||
|
|
||||||
|
* DisablePointerMethods
|
||||||
|
Disables invocation of error and Stringer interface methods on types
|
||||||
|
which only accept pointer receivers from non-pointer variables.
|
||||||
|
Pointer method invocation is enabled by default.
|
||||||
|
|
||||||
|
* ContinueOnMethod
|
||||||
|
Enables recursion into types after invoking error and Stringer interface
|
||||||
|
methods. Recursion after method invocation is disabled by default.
|
||||||
|
|
||||||
|
* SortKeys
|
||||||
|
Specifies map keys should be sorted before being printed. Use
|
||||||
|
this to have a more deterministic, diffable output. Note that
|
||||||
|
only native types (bool, int, uint, floats, uintptr and string)
|
||||||
|
and types which implement error or Stringer interfaces are
|
||||||
|
supported with other types sorted according to the
|
||||||
|
reflect.Value.String() output which guarantees display
|
||||||
|
stability. Natural map order is used by default.
|
||||||
|
|
||||||
|
* SpewKeys
|
||||||
|
Specifies that, as a last resort attempt, map keys should be
|
||||||
|
spewed to strings and sorted by those strings. This is only
|
||||||
|
considered if SortKeys is true.
|
||||||
|
|
||||||
|
Dump Usage
|
||||||
|
|
||||||
|
Simply call spew.Dump with a list of variables you want to dump:
|
||||||
|
|
||||||
|
spew.Dump(myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
You may also call spew.Fdump if you would prefer to output to an arbitrary
|
||||||
|
io.Writer. For example, to dump to standard error:
|
||||||
|
|
||||||
|
spew.Fdump(os.Stderr, myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
A third option is to call spew.Sdump to get the formatted output as a string:
|
||||||
|
|
||||||
|
str := spew.Sdump(myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
Sample Dump Output
|
||||||
|
|
||||||
|
See the Dump example for details on the setup of the types and variables being
|
||||||
|
shown here.
|
||||||
|
|
||||||
|
(main.Foo) {
|
||||||
|
unexportedField: (*main.Bar)(0xf84002e210)({
|
||||||
|
flag: (main.Flag) flagTwo,
|
||||||
|
data: (uintptr) <nil>
|
||||||
|
}),
|
||||||
|
ExportedField: (map[interface {}]interface {}) (len=1) {
|
||||||
|
(string) (len=3) "one": (bool) true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
|
||||||
|
command as shown.
|
||||||
|
([]uint8) (len=32 cap=32) {
|
||||||
|
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
|
||||||
|
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
|
||||||
|
00000020 31 32 |12|
|
||||||
|
}
|
||||||
|
|
||||||
|
Custom Formatter
|
||||||
|
|
||||||
|
Spew provides a custom formatter that implements the fmt.Formatter interface
|
||||||
|
so that it integrates cleanly with standard fmt package printing functions. The
|
||||||
|
formatter is useful for inline printing of smaller data types similar to the
|
||||||
|
standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
||||||
|
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
|
||||||
|
combinations. Any other verbs such as %x and %q will be sent to the the
|
||||||
|
standard fmt package for formatting. In addition, the custom formatter ignores
|
||||||
|
the width and precision arguments (however they will still work on the format
|
||||||
|
specifiers not handled by the custom formatter).
|
||||||
|
|
||||||
|
Custom Formatter Usage
|
||||||
|
|
||||||
|
The simplest way to make use of the spew custom formatter is to call one of the
|
||||||
|
convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
|
||||||
|
functions have syntax you are most likely already familiar with:
|
||||||
|
|
||||||
|
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
spew.Println(myVar, myVar2)
|
||||||
|
spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
|
||||||
|
See the Index for the full list convenience functions.
|
||||||
|
|
||||||
|
Sample Formatter Output
|
||||||
|
|
||||||
|
Double pointer to a uint8:
|
||||||
|
%v: <**>5
|
||||||
|
%+v: <**>(0xf8400420d0->0xf8400420c8)5
|
||||||
|
%#v: (**uint8)5
|
||||||
|
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
|
||||||
|
|
||||||
|
Pointer to circular struct with a uint8 field and a pointer to itself:
|
||||||
|
%v: <*>{1 <*><shown>}
|
||||||
|
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
|
||||||
|
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
|
||||||
|
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
|
||||||
|
|
||||||
|
See the Printf example for details on the setup of variables being shown
|
||||||
|
here.
|
||||||
|
|
||||||
|
Errors
|
||||||
|
|
||||||
|
Since it is possible for custom Stringer/error interfaces to panic, spew
|
||||||
|
detects them and handles them internally by printing the panic information
|
||||||
|
inline with the output. Since spew is intended to provide deep pretty printing
|
||||||
|
capabilities on structures, it intentionally does not return any errors.
|
||||||
|
*/
|
||||||
|
package spew
|
506
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
Normal file
@ -0,0 +1,506 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// uint8Type is a reflect.Type representing a uint8. It is used to
|
||||||
|
// convert cgo types to uint8 slices for hexdumping.
|
||||||
|
uint8Type = reflect.TypeOf(uint8(0))
|
||||||
|
|
||||||
|
// cCharRE is a regular expression that matches a cgo char.
|
||||||
|
// It is used to detect character arrays to hexdump them.
|
||||||
|
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
|
||||||
|
|
||||||
|
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
|
||||||
|
// char. It is used to detect unsigned character arrays to hexdump
|
||||||
|
// them.
|
||||||
|
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
|
||||||
|
|
||||||
|
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
|
||||||
|
// It is used to detect uint8_t arrays to hexdump them.
|
||||||
|
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
|
||||||
|
)
|
||||||
|
|
||||||
|
// dumpState contains information about the state of a dump operation.
|
||||||
|
type dumpState struct {
|
||||||
|
w io.Writer
|
||||||
|
depth int
|
||||||
|
pointers map[uintptr]int
|
||||||
|
ignoreNextType bool
|
||||||
|
ignoreNextIndent bool
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// indent performs indentation according to the depth level and cs.Indent
|
||||||
|
// option.
|
||||||
|
func (d *dumpState) indent() {
|
||||||
|
if d.ignoreNextIndent {
|
||||||
|
d.ignoreNextIndent = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
|
||||||
|
}
|
||||||
|
|
||||||
|
// unpackValue returns values inside of non-nil interfaces when possible.
|
||||||
|
// This is useful for data types like structs, arrays, slices, and maps which
|
||||||
|
// can contain varying types packed inside an interface.
|
||||||
|
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
|
||||||
|
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// dumpPtr handles formatting of pointers by indirecting them as necessary.
|
||||||
|
func (d *dumpState) dumpPtr(v reflect.Value) {
|
||||||
|
// Remove pointers at or below the current depth from map used to detect
|
||||||
|
// circular refs.
|
||||||
|
for k, depth := range d.pointers {
|
||||||
|
if depth >= d.depth {
|
||||||
|
delete(d.pointers, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep list of all dereferenced pointers to show later.
|
||||||
|
pointerChain := make([]uintptr, 0)
|
||||||
|
|
||||||
|
// Figure out how many levels of indirection there are by dereferencing
|
||||||
|
// pointers and unpacking interfaces down the chain while detecting circular
|
||||||
|
// references.
|
||||||
|
nilFound := false
|
||||||
|
cycleFound := false
|
||||||
|
indirects := 0
|
||||||
|
ve := v
|
||||||
|
for ve.Kind() == reflect.Ptr {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
indirects++
|
||||||
|
addr := ve.Pointer()
|
||||||
|
pointerChain = append(pointerChain, addr)
|
||||||
|
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
|
||||||
|
cycleFound = true
|
||||||
|
indirects--
|
||||||
|
break
|
||||||
|
}
|
||||||
|
d.pointers[addr] = d.depth
|
||||||
|
|
||||||
|
ve = ve.Elem()
|
||||||
|
if ve.Kind() == reflect.Interface {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ve = ve.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display type information.
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
d.w.Write(bytes.Repeat(asteriskBytes, indirects))
|
||||||
|
d.w.Write([]byte(ve.Type().String()))
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
|
||||||
|
// Display pointer information.
|
||||||
|
if len(pointerChain) > 0 {
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
for i, addr := range pointerChain {
|
||||||
|
if i > 0 {
|
||||||
|
d.w.Write(pointerChainBytes)
|
||||||
|
}
|
||||||
|
printHexPtr(d.w, addr)
|
||||||
|
}
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display dereferenced value.
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
switch {
|
||||||
|
case nilFound == true:
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
|
||||||
|
case cycleFound == true:
|
||||||
|
d.w.Write(circularBytes)
|
||||||
|
|
||||||
|
default:
|
||||||
|
d.ignoreNextType = true
|
||||||
|
d.dump(ve)
|
||||||
|
}
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
|
||||||
|
// reflection) arrays and slices are dumped in hexdump -C fashion.
|
||||||
|
func (d *dumpState) dumpSlice(v reflect.Value) {
|
||||||
|
// Determine whether this type should be hex dumped or not. Also,
|
||||||
|
// for types which should be hexdumped, try to use the underlying data
|
||||||
|
// first, then fall back to trying to convert them to a uint8 slice.
|
||||||
|
var buf []uint8
|
||||||
|
doConvert := false
|
||||||
|
doHexDump := false
|
||||||
|
numEntries := v.Len()
|
||||||
|
if numEntries > 0 {
|
||||||
|
vt := v.Index(0).Type()
|
||||||
|
vts := vt.String()
|
||||||
|
switch {
|
||||||
|
// C types that need to be converted.
|
||||||
|
case cCharRE.MatchString(vts):
|
||||||
|
fallthrough
|
||||||
|
case cUnsignedCharRE.MatchString(vts):
|
||||||
|
fallthrough
|
||||||
|
case cUint8tCharRE.MatchString(vts):
|
||||||
|
doConvert = true
|
||||||
|
|
||||||
|
// Try to use existing uint8 slices and fall back to converting
|
||||||
|
// and copying if that fails.
|
||||||
|
case vt.Kind() == reflect.Uint8:
|
||||||
|
// We need an addressable interface to convert the type back
|
||||||
|
// into a byte slice. However, the reflect package won't give
|
||||||
|
// us an interface on certain things like unexported struct
|
||||||
|
// fields in order to enforce visibility rules. We use unsafe
|
||||||
|
// to bypass these restrictions since this package does not
|
||||||
|
// mutate the values.
|
||||||
|
vs := v
|
||||||
|
if !vs.CanInterface() || !vs.CanAddr() {
|
||||||
|
vs = unsafeReflectValue(vs)
|
||||||
|
}
|
||||||
|
vs = vs.Slice(0, numEntries)
|
||||||
|
|
||||||
|
// Use the existing uint8 slice if it can be type
|
||||||
|
// asserted.
|
||||||
|
iface := vs.Interface()
|
||||||
|
if slice, ok := iface.([]uint8); ok {
|
||||||
|
buf = slice
|
||||||
|
doHexDump = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// The underlying data needs to be converted if it can't
|
||||||
|
// be type asserted to a uint8 slice.
|
||||||
|
doConvert = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy and convert the underlying type if needed.
|
||||||
|
if doConvert && vt.ConvertibleTo(uint8Type) {
|
||||||
|
// Convert and copy each element into a uint8 byte
|
||||||
|
// slice.
|
||||||
|
buf = make([]uint8, numEntries)
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
vv := v.Index(i)
|
||||||
|
buf[i] = uint8(vv.Convert(uint8Type).Uint())
|
||||||
|
}
|
||||||
|
doHexDump = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hexdump the entire slice as needed.
|
||||||
|
if doHexDump {
|
||||||
|
indent := strings.Repeat(d.cs.Indent, d.depth)
|
||||||
|
str := indent + hex.Dump(buf)
|
||||||
|
str = strings.Replace(str, "\n", "\n"+indent, -1)
|
||||||
|
str = strings.TrimRight(str, d.cs.Indent)
|
||||||
|
d.w.Write([]byte(str))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively call dump for each item.
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
d.dump(d.unpackValue(v.Index(i)))
|
||||||
|
if i < (numEntries - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump is the main workhorse for dumping a value. It uses the passed reflect
|
||||||
|
// value to figure out what kind of object we are dealing with and formats it
|
||||||
|
// appropriately. It is a recursive function, however circular data structures
|
||||||
|
// are detected and handled properly.
|
||||||
|
func (d *dumpState) dump(v reflect.Value) {
|
||||||
|
// Handle invalid reflect values immediately.
|
||||||
|
kind := v.Kind()
|
||||||
|
if kind == reflect.Invalid {
|
||||||
|
d.w.Write(invalidAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle pointers specially.
|
||||||
|
if kind == reflect.Ptr {
|
||||||
|
d.indent()
|
||||||
|
d.dumpPtr(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print type information unless already handled elsewhere.
|
||||||
|
if !d.ignoreNextType {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
d.w.Write([]byte(v.Type().String()))
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
d.w.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
d.ignoreNextType = false
|
||||||
|
|
||||||
|
// Display length and capacity if the built-in len and cap functions
|
||||||
|
// work with the value's kind and the len/cap itself is non-zero.
|
||||||
|
valueLen, valueCap := 0, 0
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Array, reflect.Slice, reflect.Chan:
|
||||||
|
valueLen, valueCap = v.Len(), v.Cap()
|
||||||
|
case reflect.Map, reflect.String:
|
||||||
|
valueLen = v.Len()
|
||||||
|
}
|
||||||
|
if valueLen != 0 || valueCap != 0 {
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
if valueLen != 0 {
|
||||||
|
d.w.Write(lenEqualsBytes)
|
||||||
|
printInt(d.w, int64(valueLen), 10)
|
||||||
|
}
|
||||||
|
if valueCap != 0 {
|
||||||
|
if valueLen != 0 {
|
||||||
|
d.w.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
d.w.Write(capEqualsBytes)
|
||||||
|
printInt(d.w, int64(valueCap), 10)
|
||||||
|
}
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
d.w.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call Stringer/error interfaces if they exist and the handle methods flag
|
||||||
|
// is enabled
|
||||||
|
if !d.cs.DisableMethods {
|
||||||
|
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
||||||
|
if handled := handleMethods(d.cs, d.w, v); handled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Invalid:
|
||||||
|
// Do nothing. We should never get here since invalid has already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
printBool(d.w, v.Bool())
|
||||||
|
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
printInt(d.w, v.Int(), 10)
|
||||||
|
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
printUint(d.w, v.Uint(), 10)
|
||||||
|
|
||||||
|
case reflect.Float32:
|
||||||
|
printFloat(d.w, v.Float(), 32)
|
||||||
|
|
||||||
|
case reflect.Float64:
|
||||||
|
printFloat(d.w, v.Float(), 64)
|
||||||
|
|
||||||
|
case reflect.Complex64:
|
||||||
|
printComplex(d.w, v.Complex(), 32)
|
||||||
|
|
||||||
|
case reflect.Complex128:
|
||||||
|
printComplex(d.w, v.Complex(), 64)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
if v.IsNil() {
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case reflect.Array:
|
||||||
|
d.w.Write(openBraceNewlineBytes)
|
||||||
|
d.depth++
|
||||||
|
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(maxNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.dumpSlice(v)
|
||||||
|
}
|
||||||
|
d.depth--
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.String:
|
||||||
|
d.w.Write([]byte(strconv.Quote(v.String())))
|
||||||
|
|
||||||
|
case reflect.Interface:
|
||||||
|
// The only time we should get here is for nil interfaces due to
|
||||||
|
// unpackValue calls.
|
||||||
|
if v.IsNil() {
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
// Do nothing. We should never get here since pointers have already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
// nil maps should be indicated as different than empty maps
|
||||||
|
if v.IsNil() {
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
d.w.Write(openBraceNewlineBytes)
|
||||||
|
d.depth++
|
||||||
|
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(maxNewlineBytes)
|
||||||
|
} else {
|
||||||
|
numEntries := v.Len()
|
||||||
|
keys := v.MapKeys()
|
||||||
|
if d.cs.SortKeys {
|
||||||
|
sortValues(keys, d.cs)
|
||||||
|
}
|
||||||
|
for i, key := range keys {
|
||||||
|
d.dump(d.unpackValue(key))
|
||||||
|
d.w.Write(colonSpaceBytes)
|
||||||
|
d.ignoreNextIndent = true
|
||||||
|
d.dump(d.unpackValue(v.MapIndex(key)))
|
||||||
|
if i < (numEntries - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.depth--
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
d.w.Write(openBraceNewlineBytes)
|
||||||
|
d.depth++
|
||||||
|
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(maxNewlineBytes)
|
||||||
|
} else {
|
||||||
|
vt := v.Type()
|
||||||
|
numFields := v.NumField()
|
||||||
|
for i := 0; i < numFields; i++ {
|
||||||
|
d.indent()
|
||||||
|
vtf := vt.Field(i)
|
||||||
|
d.w.Write([]byte(vtf.Name))
|
||||||
|
d.w.Write(colonSpaceBytes)
|
||||||
|
d.ignoreNextIndent = true
|
||||||
|
d.dump(d.unpackValue(v.Field(i)))
|
||||||
|
if i < (numFields - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.depth--
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.Uintptr:
|
||||||
|
printHexPtr(d.w, uintptr(v.Uint()))
|
||||||
|
|
||||||
|
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
||||||
|
printHexPtr(d.w, v.Pointer())
|
||||||
|
|
||||||
|
// There were not any other types at the time this code was written, but
|
||||||
|
// fall back to letting the default fmt package handle it in case any new
|
||||||
|
// types are added.
|
||||||
|
default:
|
||||||
|
if v.CanInterface() {
|
||||||
|
fmt.Fprintf(d.w, "%v", v.Interface())
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(d.w, "%v", v.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fdump is a helper function to consolidate the logic from the various public
|
||||||
|
// methods which take varying writers and config states.
|
||||||
|
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
|
||||||
|
for _, arg := range a {
|
||||||
|
if arg == nil {
|
||||||
|
w.Write(interfaceBytes)
|
||||||
|
w.Write(spaceBytes)
|
||||||
|
w.Write(nilAngleBytes)
|
||||||
|
w.Write(newlineBytes)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
d := dumpState{w: w, cs: cs}
|
||||||
|
d.pointers = make(map[uintptr]int)
|
||||||
|
d.dump(reflect.ValueOf(arg))
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
||||||
|
// exactly the same as Dump.
|
||||||
|
func Fdump(w io.Writer, a ...interface{}) {
|
||||||
|
fdump(&Config, w, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sdump returns a string with the passed arguments formatted exactly the same
|
||||||
|
// as Dump.
|
||||||
|
func Sdump(a ...interface{}) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fdump(&Config, &buf, a...)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dump displays the passed parameters to standard out with newlines, customizable
|
||||||
|
indentation, and additional debug information such as complete types and all
|
||||||
|
pointer addresses used to indirect to the final value. It provides the
|
||||||
|
following features over the built-in printing facilities provided by the fmt
|
||||||
|
package:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
|
includes offsets, byte values in hex, and ASCII output
|
||||||
|
|
||||||
|
The configuration options are controlled by an exported package global,
|
||||||
|
spew.Config. See ConfigState for options documentation.
|
||||||
|
|
||||||
|
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
|
||||||
|
get the formatted result as a string.
|
||||||
|
*/
|
||||||
|
func Dump(a ...interface{}) {
|
||||||
|
fdump(&Config, os.Stdout, a...)
|
||||||
|
}
|
1021
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go
generated
vendored
Normal file
97
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||||
|
// when both cgo is supported and "-tags testcgo" is added to the go test
|
||||||
|
// command line. This means the cgo tests are only added (and hence run) when
|
||||||
|
// specifially requested. This configuration is used because spew itself
|
||||||
|
// does not require cgo to run even though it does handle certain cgo types
|
||||||
|
// specially. Rather than forcing all clients to require cgo and an external
|
||||||
|
// C compiler just to run the tests, this scheme makes them optional.
|
||||||
|
// +build cgo,testcgo
|
||||||
|
|
||||||
|
package spew_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/davecgh/go-spew/spew/testdata"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addCgoDumpTests() {
|
||||||
|
// C char pointer.
|
||||||
|
v := testdata.GetCgoCharPointer()
|
||||||
|
nv := testdata.GetCgoNullCharPointer()
|
||||||
|
pv := &v
|
||||||
|
vcAddr := fmt.Sprintf("%p", v)
|
||||||
|
vAddr := fmt.Sprintf("%p", pv)
|
||||||
|
pvAddr := fmt.Sprintf("%p", &pv)
|
||||||
|
vt := "*testdata._Ctype_char"
|
||||||
|
vs := "116"
|
||||||
|
addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
|
||||||
|
addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
|
||||||
|
addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
|
||||||
|
addDumpTest(nv, "("+vt+")(<nil>)\n")
|
||||||
|
|
||||||
|
// C char array.
|
||||||
|
v2, v2l, v2c := testdata.GetCgoCharArray()
|
||||||
|
v2Len := fmt.Sprintf("%d", v2l)
|
||||||
|
v2Cap := fmt.Sprintf("%d", v2c)
|
||||||
|
v2t := "[6]testdata._Ctype_char"
|
||||||
|
v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
|
||||||
|
"{\n 00000000 74 65 73 74 32 00 " +
|
||||||
|
" |test2.|\n}"
|
||||||
|
addDumpTest(v2, "("+v2t+") "+v2s+"\n")
|
||||||
|
|
||||||
|
// C unsigned char array.
|
||||||
|
v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
|
||||||
|
v3Len := fmt.Sprintf("%d", v3l)
|
||||||
|
v3Cap := fmt.Sprintf("%d", v3c)
|
||||||
|
v3t := "[6]testdata._Ctype_unsignedchar"
|
||||||
|
v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
|
||||||
|
"{\n 00000000 74 65 73 74 33 00 " +
|
||||||
|
" |test3.|\n}"
|
||||||
|
addDumpTest(v3, "("+v3t+") "+v3s+"\n")
|
||||||
|
|
||||||
|
// C signed char array.
|
||||||
|
v4, v4l, v4c := testdata.GetCgoSignedCharArray()
|
||||||
|
v4Len := fmt.Sprintf("%d", v4l)
|
||||||
|
v4Cap := fmt.Sprintf("%d", v4c)
|
||||||
|
v4t := "[6]testdata._Ctype_schar"
|
||||||
|
v4t2 := "testdata._Ctype_schar"
|
||||||
|
v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
|
||||||
|
"{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
|
||||||
|
") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
|
||||||
|
") 0\n}"
|
||||||
|
addDumpTest(v4, "("+v4t+") "+v4s+"\n")
|
||||||
|
|
||||||
|
// C uint8_t array.
|
||||||
|
v5, v5l, v5c := testdata.GetCgoUint8tArray()
|
||||||
|
v5Len := fmt.Sprintf("%d", v5l)
|
||||||
|
v5Cap := fmt.Sprintf("%d", v5c)
|
||||||
|
v5t := "[6]testdata._Ctype_uint8_t"
|
||||||
|
v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
|
||||||
|
"{\n 00000000 74 65 73 74 35 00 " +
|
||||||
|
" |test5.|\n}"
|
||||||
|
addDumpTest(v5, "("+v5t+") "+v5s+"\n")
|
||||||
|
|
||||||
|
// C typedefed unsigned char array.
|
||||||
|
v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
|
||||||
|
v6Len := fmt.Sprintf("%d", v6l)
|
||||||
|
v6Cap := fmt.Sprintf("%d", v6c)
|
||||||
|
v6t := "[6]testdata._Ctype_custom_uchar_t"
|
||||||
|
v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
|
||||||
|
"{\n 00000000 74 65 73 74 36 00 " +
|
||||||
|
" |test6.|\n}"
|
||||||
|
addDumpTest(v6, "("+v6t+") "+v6s+"\n")
|
||||||
|
}
|
26
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||||
|
// when either cgo is not supported or "-tags testcgo" is not added to the go
|
||||||
|
// test command line. This file intentionally does not setup any cgo tests in
|
||||||
|
// this scenario.
|
||||||
|
// +build !cgo !testcgo
|
||||||
|
|
||||||
|
package spew_test
|
||||||
|
|
||||||
|
func addCgoDumpTests() {
|
||||||
|
// Don't add any tests for cgo since this file is only compiled when
|
||||||
|
// there should not be any cgo tests.
|
||||||
|
}
|
230
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go
generated
vendored
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Flag int
|
||||||
|
|
||||||
|
const (
|
||||||
|
flagOne Flag = iota
|
||||||
|
flagTwo
|
||||||
|
)
|
||||||
|
|
||||||
|
var flagStrings = map[Flag]string{
|
||||||
|
flagOne: "flagOne",
|
||||||
|
flagTwo: "flagTwo",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Flag) String() string {
|
||||||
|
if s, ok := flagStrings[f]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Unknown flag (%d)", int(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Bar struct {
|
||||||
|
flag Flag
|
||||||
|
data uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type Foo struct {
|
||||||
|
unexportedField Bar
|
||||||
|
ExportedField map[interface{}]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example demonstrates how to use Dump to dump variables to stdout.
|
||||||
|
func ExampleDump() {
|
||||||
|
// The following package level declarations are assumed for this example:
|
||||||
|
/*
|
||||||
|
type Flag int
|
||||||
|
|
||||||
|
const (
|
||||||
|
flagOne Flag = iota
|
||||||
|
flagTwo
|
||||||
|
)
|
||||||
|
|
||||||
|
var flagStrings = map[Flag]string{
|
||||||
|
flagOne: "flagOne",
|
||||||
|
flagTwo: "flagTwo",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Flag) String() string {
|
||||||
|
if s, ok := flagStrings[f]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Unknown flag (%d)", int(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Bar struct {
|
||||||
|
flag Flag
|
||||||
|
data uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type Foo struct {
|
||||||
|
unexportedField Bar
|
||||||
|
ExportedField map[interface{}]interface{}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Setup some sample data structures for the example.
|
||||||
|
bar := Bar{Flag(flagTwo), uintptr(0)}
|
||||||
|
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
|
||||||
|
f := Flag(5)
|
||||||
|
b := []byte{
|
||||||
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||||
|
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
||||||
|
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||||
|
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||||
|
0x31, 0x32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump!
|
||||||
|
spew.Dump(s1, f, b)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// (spew_test.Foo) {
|
||||||
|
// unexportedField: (spew_test.Bar) {
|
||||||
|
// flag: (spew_test.Flag) flagTwo,
|
||||||
|
// data: (uintptr) <nil>
|
||||||
|
// },
|
||||||
|
// ExportedField: (map[interface {}]interface {}) (len=1) {
|
||||||
|
// (string) (len=3) "one": (bool) true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// (spew_test.Flag) Unknown flag (5)
|
||||||
|
// ([]uint8) (len=34 cap=34) {
|
||||||
|
// 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
|
||||||
|
// 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
|
||||||
|
// 00000020 31 32 |12|
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example demonstrates how to use Printf to display a variable with a
|
||||||
|
// format string and inline formatting.
|
||||||
|
func ExamplePrintf() {
|
||||||
|
// Create a double pointer to a uint 8.
|
||||||
|
ui8 := uint8(5)
|
||||||
|
pui8 := &ui8
|
||||||
|
ppui8 := &pui8
|
||||||
|
|
||||||
|
// Create a circular data type.
|
||||||
|
type circular struct {
|
||||||
|
ui8 uint8
|
||||||
|
c *circular
|
||||||
|
}
|
||||||
|
c := circular{ui8: 1}
|
||||||
|
c.c = &c
|
||||||
|
|
||||||
|
// Print!
|
||||||
|
spew.Printf("ppui8: %v\n", ppui8)
|
||||||
|
spew.Printf("circular: %v\n", c)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ppui8: <**>5
|
||||||
|
// circular: {1 <*>{1 <*><shown>}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example demonstrates how to use a ConfigState.
|
||||||
|
func ExampleConfigState() {
|
||||||
|
// Modify the indent level of the ConfigState only. The global
|
||||||
|
// configuration is not modified.
|
||||||
|
scs := spew.ConfigState{Indent: "\t"}
|
||||||
|
|
||||||
|
// Output using the ConfigState instance.
|
||||||
|
v := map[string]int{"one": 1}
|
||||||
|
scs.Printf("v: %v\n", v)
|
||||||
|
scs.Dump(v)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// v: map[one:1]
|
||||||
|
// (map[string]int) (len=1) {
|
||||||
|
// (string) (len=3) "one": (int) 1
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example demonstrates how to use ConfigState.Dump to dump variables to
|
||||||
|
// stdout
|
||||||
|
func ExampleConfigState_Dump() {
|
||||||
|
// See the top-level Dump example for details on the types used in this
|
||||||
|
// example.
|
||||||
|
|
||||||
|
// Create two ConfigState instances with different indentation.
|
||||||
|
scs := spew.ConfigState{Indent: "\t"}
|
||||||
|
scs2 := spew.ConfigState{Indent: " "}
|
||||||
|
|
||||||
|
// Setup some sample data structures for the example.
|
||||||
|
bar := Bar{Flag(flagTwo), uintptr(0)}
|
||||||
|
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
|
||||||
|
|
||||||
|
// Dump using the ConfigState instances.
|
||||||
|
scs.Dump(s1)
|
||||||
|
scs2.Dump(s1)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// (spew_test.Foo) {
|
||||||
|
// unexportedField: (spew_test.Bar) {
|
||||||
|
// flag: (spew_test.Flag) flagTwo,
|
||||||
|
// data: (uintptr) <nil>
|
||||||
|
// },
|
||||||
|
// ExportedField: (map[interface {}]interface {}) (len=1) {
|
||||||
|
// (string) (len=3) "one": (bool) true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// (spew_test.Foo) {
|
||||||
|
// unexportedField: (spew_test.Bar) {
|
||||||
|
// flag: (spew_test.Flag) flagTwo,
|
||||||
|
// data: (uintptr) <nil>
|
||||||
|
// },
|
||||||
|
// ExportedField: (map[interface {}]interface {}) (len=1) {
|
||||||
|
// (string) (len=3) "one": (bool) true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example demonstrates how to use ConfigState.Printf to display a variable
|
||||||
|
// with a format string and inline formatting.
|
||||||
|
func ExampleConfigState_Printf() {
|
||||||
|
// See the top-level Dump example for details on the types used in this
|
||||||
|
// example.
|
||||||
|
|
||||||
|
// Create two ConfigState instances and modify the method handling of the
|
||||||
|
// first ConfigState only.
|
||||||
|
scs := spew.NewDefaultConfig()
|
||||||
|
scs2 := spew.NewDefaultConfig()
|
||||||
|
scs.DisableMethods = true
|
||||||
|
|
||||||
|
// Alternatively
|
||||||
|
// scs := spew.ConfigState{Indent: " ", DisableMethods: true}
|
||||||
|
// scs2 := spew.ConfigState{Indent: " "}
|
||||||
|
|
||||||
|
// This is of type Flag which implements a Stringer and has raw value 1.
|
||||||
|
f := flagTwo
|
||||||
|
|
||||||
|
// Dump using the ConfigState instances.
|
||||||
|
scs.Printf("f: %v\n", f)
|
||||||
|
scs2.Printf("f: %v\n", f)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// f: 1
|
||||||
|
// f: flagTwo
|
||||||
|
}
|
419
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format.go
generated
vendored
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// supportedFlags is a list of all the character flags supported by fmt package.
|
||||||
|
const supportedFlags = "0-+# "
|
||||||
|
|
||||||
|
// formatState implements the fmt.Formatter interface and contains information
|
||||||
|
// about the state of a formatting operation. The NewFormatter function can
|
||||||
|
// be used to get a new Formatter which can be used directly as arguments
|
||||||
|
// in standard fmt package printing calls.
|
||||||
|
type formatState struct {
|
||||||
|
value interface{}
|
||||||
|
fs fmt.State
|
||||||
|
depth int
|
||||||
|
pointers map[uintptr]int
|
||||||
|
ignoreNextType bool
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildDefaultFormat recreates the original format string without precision
|
||||||
|
// and width information to pass in to fmt.Sprintf in the case of an
|
||||||
|
// unrecognized type. Unless new types are added to the language, this
|
||||||
|
// function won't ever be called.
|
||||||
|
func (f *formatState) buildDefaultFormat() (format string) {
|
||||||
|
buf := bytes.NewBuffer(percentBytes)
|
||||||
|
|
||||||
|
for _, flag := range supportedFlags {
|
||||||
|
if f.fs.Flag(int(flag)) {
|
||||||
|
buf.WriteRune(flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteRune('v')
|
||||||
|
|
||||||
|
format = buf.String()
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructOrigFormat recreates the original format string including precision
|
||||||
|
// and width information to pass along to the standard fmt package. This allows
|
||||||
|
// automatic deferral of all format strings this package doesn't support.
|
||||||
|
func (f *formatState) constructOrigFormat(verb rune) (format string) {
|
||||||
|
buf := bytes.NewBuffer(percentBytes)
|
||||||
|
|
||||||
|
for _, flag := range supportedFlags {
|
||||||
|
if f.fs.Flag(int(flag)) {
|
||||||
|
buf.WriteRune(flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if width, ok := f.fs.Width(); ok {
|
||||||
|
buf.WriteString(strconv.Itoa(width))
|
||||||
|
}
|
||||||
|
|
||||||
|
if precision, ok := f.fs.Precision(); ok {
|
||||||
|
buf.Write(precisionBytes)
|
||||||
|
buf.WriteString(strconv.Itoa(precision))
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteRune(verb)
|
||||||
|
|
||||||
|
format = buf.String()
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
// unpackValue returns values inside of non-nil interfaces when possible and
|
||||||
|
// ensures that types for values which have been unpacked from an interface
|
||||||
|
// are displayed when the show types flag is also set.
|
||||||
|
// This is useful for data types like structs, arrays, slices, and maps which
|
||||||
|
// can contain varying types packed inside an interface.
|
||||||
|
func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
|
||||||
|
if v.Kind() == reflect.Interface {
|
||||||
|
f.ignoreNextType = false
|
||||||
|
if !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatPtr handles formatting of pointers by indirecting them as necessary.
|
||||||
|
func (f *formatState) formatPtr(v reflect.Value) {
|
||||||
|
// Display nil if top level pointer is nil.
|
||||||
|
showTypes := f.fs.Flag('#')
|
||||||
|
if v.IsNil() && (!showTypes || f.ignoreNextType) {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove pointers at or below the current depth from map used to detect
|
||||||
|
// circular refs.
|
||||||
|
for k, depth := range f.pointers {
|
||||||
|
if depth >= f.depth {
|
||||||
|
delete(f.pointers, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep list of all dereferenced pointers to possibly show later.
|
||||||
|
pointerChain := make([]uintptr, 0)
|
||||||
|
|
||||||
|
// Figure out how many levels of indirection there are by derferencing
|
||||||
|
// pointers and unpacking interfaces down the chain while detecting circular
|
||||||
|
// references.
|
||||||
|
nilFound := false
|
||||||
|
cycleFound := false
|
||||||
|
indirects := 0
|
||||||
|
ve := v
|
||||||
|
for ve.Kind() == reflect.Ptr {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
indirects++
|
||||||
|
addr := ve.Pointer()
|
||||||
|
pointerChain = append(pointerChain, addr)
|
||||||
|
if pd, ok := f.pointers[addr]; ok && pd < f.depth {
|
||||||
|
cycleFound = true
|
||||||
|
indirects--
|
||||||
|
break
|
||||||
|
}
|
||||||
|
f.pointers[addr] = f.depth
|
||||||
|
|
||||||
|
ve = ve.Elem()
|
||||||
|
if ve.Kind() == reflect.Interface {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ve = ve.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display type or indirection level depending on flags.
|
||||||
|
if showTypes && !f.ignoreNextType {
|
||||||
|
f.fs.Write(openParenBytes)
|
||||||
|
f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
|
||||||
|
f.fs.Write([]byte(ve.Type().String()))
|
||||||
|
f.fs.Write(closeParenBytes)
|
||||||
|
} else {
|
||||||
|
if nilFound || cycleFound {
|
||||||
|
indirects += strings.Count(ve.Type().String(), "*")
|
||||||
|
}
|
||||||
|
f.fs.Write(openAngleBytes)
|
||||||
|
f.fs.Write([]byte(strings.Repeat("*", indirects)))
|
||||||
|
f.fs.Write(closeAngleBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display pointer information depending on flags.
|
||||||
|
if f.fs.Flag('+') && (len(pointerChain) > 0) {
|
||||||
|
f.fs.Write(openParenBytes)
|
||||||
|
for i, addr := range pointerChain {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(pointerChainBytes)
|
||||||
|
}
|
||||||
|
printHexPtr(f.fs, addr)
|
||||||
|
}
|
||||||
|
f.fs.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display dereferenced value.
|
||||||
|
switch {
|
||||||
|
case nilFound == true:
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
|
||||||
|
case cycleFound == true:
|
||||||
|
f.fs.Write(circularShortBytes)
|
||||||
|
|
||||||
|
default:
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(ve)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// format is the main workhorse for providing the Formatter interface. It
|
||||||
|
// uses the passed reflect value to figure out what kind of object we are
|
||||||
|
// dealing with and formats it appropriately. It is a recursive function,
|
||||||
|
// however circular data structures are detected and handled properly.
|
||||||
|
func (f *formatState) format(v reflect.Value) {
|
||||||
|
// Handle invalid reflect values immediately.
|
||||||
|
kind := v.Kind()
|
||||||
|
if kind == reflect.Invalid {
|
||||||
|
f.fs.Write(invalidAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle pointers specially.
|
||||||
|
if kind == reflect.Ptr {
|
||||||
|
f.formatPtr(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print type information unless already handled elsewhere.
|
||||||
|
if !f.ignoreNextType && f.fs.Flag('#') {
|
||||||
|
f.fs.Write(openParenBytes)
|
||||||
|
f.fs.Write([]byte(v.Type().String()))
|
||||||
|
f.fs.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
f.ignoreNextType = false
|
||||||
|
|
||||||
|
// Call Stringer/error interfaces if they exist and the handle methods
|
||||||
|
// flag is enabled.
|
||||||
|
if !f.cs.DisableMethods {
|
||||||
|
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
||||||
|
if handled := handleMethods(f.cs, f.fs, v); handled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Invalid:
|
||||||
|
// Do nothing. We should never get here since invalid has already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
printBool(f.fs, v.Bool())
|
||||||
|
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
printInt(f.fs, v.Int(), 10)
|
||||||
|
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
printUint(f.fs, v.Uint(), 10)
|
||||||
|
|
||||||
|
case reflect.Float32:
|
||||||
|
printFloat(f.fs, v.Float(), 32)
|
||||||
|
|
||||||
|
case reflect.Float64:
|
||||||
|
printFloat(f.fs, v.Float(), 64)
|
||||||
|
|
||||||
|
case reflect.Complex64:
|
||||||
|
printComplex(f.fs, v.Complex(), 32)
|
||||||
|
|
||||||
|
case reflect.Complex128:
|
||||||
|
printComplex(f.fs, v.Complex(), 64)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
if v.IsNil() {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case reflect.Array:
|
||||||
|
f.fs.Write(openBracketBytes)
|
||||||
|
f.depth++
|
||||||
|
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
||||||
|
f.fs.Write(maxShortBytes)
|
||||||
|
} else {
|
||||||
|
numEntries := v.Len()
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(f.unpackValue(v.Index(i)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.depth--
|
||||||
|
f.fs.Write(closeBracketBytes)
|
||||||
|
|
||||||
|
case reflect.String:
|
||||||
|
f.fs.Write([]byte(v.String()))
|
||||||
|
|
||||||
|
case reflect.Interface:
|
||||||
|
// The only time we should get here is for nil interfaces due to
|
||||||
|
// unpackValue calls.
|
||||||
|
if v.IsNil() {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
// Do nothing. We should never get here since pointers have already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
// nil maps should be indicated as different than empty maps
|
||||||
|
if v.IsNil() {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
f.fs.Write(openMapBytes)
|
||||||
|
f.depth++
|
||||||
|
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
||||||
|
f.fs.Write(maxShortBytes)
|
||||||
|
} else {
|
||||||
|
keys := v.MapKeys()
|
||||||
|
if f.cs.SortKeys {
|
||||||
|
sortValues(keys, f.cs)
|
||||||
|
}
|
||||||
|
for i, key := range keys {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(f.unpackValue(key))
|
||||||
|
f.fs.Write(colonBytes)
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(f.unpackValue(v.MapIndex(key)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.depth--
|
||||||
|
f.fs.Write(closeMapBytes)
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
numFields := v.NumField()
|
||||||
|
f.fs.Write(openBraceBytes)
|
||||||
|
f.depth++
|
||||||
|
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
||||||
|
f.fs.Write(maxShortBytes)
|
||||||
|
} else {
|
||||||
|
vt := v.Type()
|
||||||
|
for i := 0; i < numFields; i++ {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
vtf := vt.Field(i)
|
||||||
|
if f.fs.Flag('+') || f.fs.Flag('#') {
|
||||||
|
f.fs.Write([]byte(vtf.Name))
|
||||||
|
f.fs.Write(colonBytes)
|
||||||
|
}
|
||||||
|
f.format(f.unpackValue(v.Field(i)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.depth--
|
||||||
|
f.fs.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.Uintptr:
|
||||||
|
printHexPtr(f.fs, uintptr(v.Uint()))
|
||||||
|
|
||||||
|
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
||||||
|
printHexPtr(f.fs, v.Pointer())
|
||||||
|
|
||||||
|
// There were not any other types at the time this code was written, but
|
||||||
|
// fall back to letting the default fmt package handle it if any get added.
|
||||||
|
default:
|
||||||
|
format := f.buildDefaultFormat()
|
||||||
|
if v.CanInterface() {
|
||||||
|
fmt.Fprintf(f.fs, format, v.Interface())
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(f.fs, format, v.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
|
||||||
|
// details.
|
||||||
|
func (f *formatState) Format(fs fmt.State, verb rune) {
|
||||||
|
f.fs = fs
|
||||||
|
|
||||||
|
// Use standard formatting for verbs that are not v.
|
||||||
|
if verb != 'v' {
|
||||||
|
format := f.constructOrigFormat(verb)
|
||||||
|
fmt.Fprintf(fs, format, f.value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.value == nil {
|
||||||
|
if fs.Flag('#') {
|
||||||
|
fs.Write(interfaceBytes)
|
||||||
|
}
|
||||||
|
fs.Write(nilAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.format(reflect.ValueOf(f.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// newFormatter is a helper function to consolidate the logic from the various
|
||||||
|
// public methods which take varying config states.
|
||||||
|
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
|
||||||
|
fs := &formatState{value: v, cs: cs}
|
||||||
|
fs.pointers = make(map[uintptr]int)
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
||||||
|
interface. As a result, it integrates cleanly with standard fmt package
|
||||||
|
printing functions. The formatter is useful for inline printing of smaller data
|
||||||
|
types similar to the standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
||||||
|
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
|
||||||
|
combinations. Any other verbs such as %x and %q will be sent to the the
|
||||||
|
standard fmt package for formatting. In addition, the custom formatter ignores
|
||||||
|
the width and precision arguments (however they will still work on the format
|
||||||
|
specifiers not handled by the custom formatter).
|
||||||
|
|
||||||
|
Typically this function shouldn't be called directly. It is much easier to make
|
||||||
|
use of the custom formatter by calling one of the convenience functions such as
|
||||||
|
Printf, Println, or Fprintf.
|
||||||
|
*/
|
||||||
|
func NewFormatter(v interface{}) fmt.Formatter {
|
||||||
|
return newFormatter(&Config, v)
|
||||||
|
}
|
1535
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go
generated
vendored
Normal file
156
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This test file is part of the spew package rather than than the spew_test
|
||||||
|
package because it needs access to internals to properly test certain cases
|
||||||
|
which are not possible via the public interface since they should never happen.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// dummyFmtState implements a fake fmt.State to use for testing invalid
|
||||||
|
// reflect.Value handling. This is necessary because the fmt package catches
|
||||||
|
// invalid values before invoking the formatter on them.
|
||||||
|
type dummyFmtState struct {
|
||||||
|
bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dfs *dummyFmtState) Flag(f int) bool {
|
||||||
|
if f == int('+') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dfs *dummyFmtState) Precision() (int, bool) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dfs *dummyFmtState) Width() (int, bool) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInvalidReflectValue ensures the dump and formatter code handles an
|
||||||
|
// invalid reflect value properly. This needs access to internal state since it
|
||||||
|
// should never happen in real code and therefore can't be tested via the public
|
||||||
|
// API.
|
||||||
|
func TestInvalidReflectValue(t *testing.T) {
|
||||||
|
i := 1
|
||||||
|
|
||||||
|
// Dump invalid reflect value.
|
||||||
|
v := new(reflect.Value)
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
d := dumpState{w: buf, cs: &Config}
|
||||||
|
d.dump(*v)
|
||||||
|
s := buf.String()
|
||||||
|
want := "<invalid>"
|
||||||
|
if s != want {
|
||||||
|
t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
|
||||||
|
// Formatter invalid reflect value.
|
||||||
|
buf2 := new(dummyFmtState)
|
||||||
|
f := formatState{value: *v, cs: &Config, fs: buf2}
|
||||||
|
f.format(*v)
|
||||||
|
s = buf2.String()
|
||||||
|
want = "<invalid>"
|
||||||
|
if s != want {
|
||||||
|
t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// changeKind uses unsafe to intentionally change the kind of a reflect.Value to
|
||||||
|
// the maximum kind value which does not exist. This is needed to test the
|
||||||
|
// fallback code which punts to the standard fmt library for new types that
|
||||||
|
// might get added to the language.
|
||||||
|
func changeKind(v *reflect.Value, readOnly bool) {
|
||||||
|
rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
|
||||||
|
*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
|
||||||
|
if readOnly {
|
||||||
|
*rvf |= flagRO
|
||||||
|
} else {
|
||||||
|
*rvf &= ^uintptr(flagRO)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestAddedReflectValue tests functionaly of the dump and formatter code which
|
||||||
|
// falls back to the standard fmt library for new types that might get added to
|
||||||
|
// the language.
|
||||||
|
func TestAddedReflectValue(t *testing.T) {
|
||||||
|
i := 1
|
||||||
|
|
||||||
|
// Dump using a reflect.Value that is exported.
|
||||||
|
v := reflect.ValueOf(int8(5))
|
||||||
|
changeKind(&v, false)
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
d := dumpState{w: buf, cs: &Config}
|
||||||
|
d.dump(v)
|
||||||
|
s := buf.String()
|
||||||
|
want := "(int8) 5"
|
||||||
|
if s != want {
|
||||||
|
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
|
||||||
|
// Dump using a reflect.Value that is not exported.
|
||||||
|
changeKind(&v, true)
|
||||||
|
buf.Reset()
|
||||||
|
d.dump(v)
|
||||||
|
s = buf.String()
|
||||||
|
want = "(int8) <int8 Value>"
|
||||||
|
if s != want {
|
||||||
|
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
|
||||||
|
// Formatter using a reflect.Value that is exported.
|
||||||
|
changeKind(&v, false)
|
||||||
|
buf2 := new(dummyFmtState)
|
||||||
|
f := formatState{value: v, cs: &Config, fs: buf2}
|
||||||
|
f.format(v)
|
||||||
|
s = buf2.String()
|
||||||
|
want = "5"
|
||||||
|
if s != want {
|
||||||
|
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
|
||||||
|
// Formatter using a reflect.Value that is not exported.
|
||||||
|
changeKind(&v, true)
|
||||||
|
buf2.Reset()
|
||||||
|
f = formatState{value: v, cs: &Config, fs: buf2}
|
||||||
|
f.format(v)
|
||||||
|
s = buf2.String()
|
||||||
|
want = "<int8 Value>"
|
||||||
|
if s != want {
|
||||||
|
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SortValues makes the internal sortValues function available to the test
|
||||||
|
// package.
|
||||||
|
func SortValues(values []reflect.Value, cs *ConfigState) {
|
||||||
|
sortValues(values, cs)
|
||||||
|
}
|
148
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew.go
generated
vendored
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the formatted string as a value that satisfies error. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Errorf(format string, a ...interface{}) (err error) {
|
||||||
|
return fmt.Errorf(format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprint(w, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintf(w, format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintln(w, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print is a wrapper for fmt.Print that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Print(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Print(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Printf(format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Printf(format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println is a wrapper for fmt.Println that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Println(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Println(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Sprint(a ...interface{}) string {
|
||||||
|
return fmt.Sprint(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Sprintf(format string, a ...interface{}) string {
|
||||||
|
return fmt.Sprintf(format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
|
||||||
|
// were passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Sprintln(a ...interface{}) string {
|
||||||
|
return fmt.Sprintln(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertArgs accepts a slice of arguments and returns a slice of the same
|
||||||
|
// length with each argument converted to a default spew Formatter interface.
|
||||||
|
func convertArgs(args []interface{}) (formatters []interface{}) {
|
||||||
|
formatters = make([]interface{}, len(args))
|
||||||
|
for index, arg := range args {
|
||||||
|
formatters[index] = NewFormatter(arg)
|
||||||
|
}
|
||||||
|
return formatters
|
||||||
|
}
|
308
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go
generated
vendored
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// spewFunc is used to identify which public function of the spew package or
|
||||||
|
// ConfigState a test applies to.
|
||||||
|
type spewFunc int
|
||||||
|
|
||||||
|
const (
|
||||||
|
fCSFdump spewFunc = iota
|
||||||
|
fCSFprint
|
||||||
|
fCSFprintf
|
||||||
|
fCSFprintln
|
||||||
|
fCSPrint
|
||||||
|
fCSPrintln
|
||||||
|
fCSSdump
|
||||||
|
fCSSprint
|
||||||
|
fCSSprintf
|
||||||
|
fCSSprintln
|
||||||
|
fCSErrorf
|
||||||
|
fCSNewFormatter
|
||||||
|
fErrorf
|
||||||
|
fFprint
|
||||||
|
fFprintln
|
||||||
|
fPrint
|
||||||
|
fPrintln
|
||||||
|
fSdump
|
||||||
|
fSprint
|
||||||
|
fSprintf
|
||||||
|
fSprintln
|
||||||
|
)
|
||||||
|
|
||||||
|
// Map of spewFunc values to names for pretty printing.
|
||||||
|
var spewFuncStrings = map[spewFunc]string{
|
||||||
|
fCSFdump: "ConfigState.Fdump",
|
||||||
|
fCSFprint: "ConfigState.Fprint",
|
||||||
|
fCSFprintf: "ConfigState.Fprintf",
|
||||||
|
fCSFprintln: "ConfigState.Fprintln",
|
||||||
|
fCSSdump: "ConfigState.Sdump",
|
||||||
|
fCSPrint: "ConfigState.Print",
|
||||||
|
fCSPrintln: "ConfigState.Println",
|
||||||
|
fCSSprint: "ConfigState.Sprint",
|
||||||
|
fCSSprintf: "ConfigState.Sprintf",
|
||||||
|
fCSSprintln: "ConfigState.Sprintln",
|
||||||
|
fCSErrorf: "ConfigState.Errorf",
|
||||||
|
fCSNewFormatter: "ConfigState.NewFormatter",
|
||||||
|
fErrorf: "spew.Errorf",
|
||||||
|
fFprint: "spew.Fprint",
|
||||||
|
fFprintln: "spew.Fprintln",
|
||||||
|
fPrint: "spew.Print",
|
||||||
|
fPrintln: "spew.Println",
|
||||||
|
fSdump: "spew.Sdump",
|
||||||
|
fSprint: "spew.Sprint",
|
||||||
|
fSprintf: "spew.Sprintf",
|
||||||
|
fSprintln: "spew.Sprintln",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f spewFunc) String() string {
|
||||||
|
if s, ok := spewFuncStrings[f]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
// spewTest is used to describe a test to be performed against the public
|
||||||
|
// functions of the spew package or ConfigState.
|
||||||
|
type spewTest struct {
|
||||||
|
cs *spew.ConfigState
|
||||||
|
f spewFunc
|
||||||
|
format string
|
||||||
|
in interface{}
|
||||||
|
want string
|
||||||
|
}
|
||||||
|
|
||||||
|
// spewTests houses the tests to be performed against the public functions of
|
||||||
|
// the spew package and ConfigState.
|
||||||
|
//
|
||||||
|
// These tests are only intended to ensure the public functions are exercised
|
||||||
|
// and are intentionally not exhaustive of types. The exhaustive type
|
||||||
|
// tests are handled in the dump and format tests.
|
||||||
|
var spewTests []spewTest
|
||||||
|
|
||||||
|
// redirStdout is a helper function to return the standard output from f as a
|
||||||
|
// byte slice.
|
||||||
|
func redirStdout(f func()) ([]byte, error) {
|
||||||
|
tempFile, err := ioutil.TempFile("", "ss-test")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fileName := tempFile.Name()
|
||||||
|
defer os.Remove(fileName) // Ignore error
|
||||||
|
|
||||||
|
origStdout := os.Stdout
|
||||||
|
os.Stdout = tempFile
|
||||||
|
f()
|
||||||
|
os.Stdout = origStdout
|
||||||
|
tempFile.Close()
|
||||||
|
|
||||||
|
return ioutil.ReadFile(fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initSpewTests() {
|
||||||
|
// Config states with various settings.
|
||||||
|
scsDefault := spew.NewDefaultConfig()
|
||||||
|
scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
|
||||||
|
scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
|
||||||
|
scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
|
||||||
|
scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
|
||||||
|
|
||||||
|
// Variables for tests on types which implement Stringer interface with and
|
||||||
|
// without a pointer receiver.
|
||||||
|
ts := stringer("test")
|
||||||
|
tps := pstringer("test")
|
||||||
|
|
||||||
|
// depthTester is used to test max depth handling for structs, array, slices
|
||||||
|
// and maps.
|
||||||
|
type depthTester struct {
|
||||||
|
ic indirCir1
|
||||||
|
arr [1]string
|
||||||
|
slice []string
|
||||||
|
m map[string]int
|
||||||
|
}
|
||||||
|
dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
|
||||||
|
map[string]int{"one": 1}}
|
||||||
|
|
||||||
|
// Variable for tests on types which implement error interface.
|
||||||
|
te := customError(10)
|
||||||
|
|
||||||
|
spewTests = []spewTest{
|
||||||
|
{scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
|
||||||
|
{scsDefault, fCSFprint, "", int16(32767), "32767"},
|
||||||
|
{scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
|
||||||
|
{scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
|
||||||
|
{scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
|
||||||
|
{scsDefault, fCSPrintln, "", uint8(255), "255\n"},
|
||||||
|
{scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
|
||||||
|
{scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
|
||||||
|
{scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
|
||||||
|
{scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
|
||||||
|
{scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
|
||||||
|
{scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
|
||||||
|
{scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
|
||||||
|
{scsDefault, fFprint, "", float32(3.14), "3.14"},
|
||||||
|
{scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
|
||||||
|
{scsDefault, fPrint, "", true, "true"},
|
||||||
|
{scsDefault, fPrintln, "", false, "false\n"},
|
||||||
|
{scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
|
||||||
|
{scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
|
||||||
|
{scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
|
||||||
|
{scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
|
||||||
|
{scsNoMethods, fCSFprint, "", ts, "test"},
|
||||||
|
{scsNoMethods, fCSFprint, "", &ts, "<*>test"},
|
||||||
|
{scsNoMethods, fCSFprint, "", tps, "test"},
|
||||||
|
{scsNoMethods, fCSFprint, "", &tps, "<*>test"},
|
||||||
|
{scsNoPmethods, fCSFprint, "", ts, "stringer test"},
|
||||||
|
{scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
|
||||||
|
{scsNoPmethods, fCSFprint, "", tps, "test"},
|
||||||
|
{scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
|
||||||
|
{scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
|
||||||
|
{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
|
||||||
|
" ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
|
||||||
|
" arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
|
||||||
|
" slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
|
||||||
|
" m: (map[string]int) (len=1) {\n <max depth reached>\n }\n}\n"},
|
||||||
|
{scsContinue, fCSFprint, "", ts, "(stringer test) test"},
|
||||||
|
{scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
|
||||||
|
"(len=4) (stringer test) \"test\"\n"},
|
||||||
|
{scsContinue, fCSFprint, "", te, "(error: 10) 10"},
|
||||||
|
{scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
|
||||||
|
"(error: 10) 10\n"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSpew executes all of the tests described by spewTests.
|
||||||
|
func TestSpew(t *testing.T) {
|
||||||
|
initSpewTests()
|
||||||
|
|
||||||
|
t.Logf("Running %d tests", len(spewTests))
|
||||||
|
for i, test := range spewTests {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
switch test.f {
|
||||||
|
case fCSFdump:
|
||||||
|
test.cs.Fdump(buf, test.in)
|
||||||
|
|
||||||
|
case fCSFprint:
|
||||||
|
test.cs.Fprint(buf, test.in)
|
||||||
|
|
||||||
|
case fCSFprintf:
|
||||||
|
test.cs.Fprintf(buf, test.format, test.in)
|
||||||
|
|
||||||
|
case fCSFprintln:
|
||||||
|
test.cs.Fprintln(buf, test.in)
|
||||||
|
|
||||||
|
case fCSPrint:
|
||||||
|
b, err := redirStdout(func() { test.cs.Print(test.in) })
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v #%d %v", test.f, i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf.Write(b)
|
||||||
|
|
||||||
|
case fCSPrintln:
|
||||||
|
b, err := redirStdout(func() { test.cs.Println(test.in) })
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v #%d %v", test.f, i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf.Write(b)
|
||||||
|
|
||||||
|
case fCSSdump:
|
||||||
|
str := test.cs.Sdump(test.in)
|
||||||
|
buf.WriteString(str)
|
||||||
|
|
||||||
|
case fCSSprint:
|
||||||
|
str := test.cs.Sprint(test.in)
|
||||||
|
buf.WriteString(str)
|
||||||
|
|
||||||
|
case fCSSprintf:
|
||||||
|
str := test.cs.Sprintf(test.format, test.in)
|
||||||
|
buf.WriteString(str)
|
||||||
|
|
||||||
|
case fCSSprintln:
|
||||||
|
str := test.cs.Sprintln(test.in)
|
||||||
|
buf.WriteString(str)
|
||||||
|
|
||||||
|
case fCSErrorf:
|
||||||
|
err := test.cs.Errorf(test.format, test.in)
|
||||||
|
buf.WriteString(err.Error())
|
||||||
|
|
||||||
|
case fCSNewFormatter:
|
||||||
|
fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
|
||||||
|
|
||||||
|
case fErrorf:
|
||||||
|
err := spew.Errorf(test.format, test.in)
|
||||||
|
buf.WriteString(err.Error())
|
||||||
|
|
||||||
|
case fFprint:
|
||||||
|
spew.Fprint(buf, test.in)
|
||||||
|
|
||||||
|
case fFprintln:
|
||||||
|
spew.Fprintln(buf, test.in)
|
||||||
|
|
||||||
|
case fPrint:
|
||||||
|
b, err := redirStdout(func() { spew.Print(test.in) })
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v #%d %v", test.f, i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf.Write(b)
|
||||||
|
|
||||||
|
case fPrintln:
|
||||||
|
b, err := redirStdout(func() { spew.Println(test.in) })
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v #%d %v", test.f, i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf.Write(b)
|
||||||
|
|
||||||
|
case fSdump:
|
||||||
|
str := spew.Sdump(test.in)
|
||||||
|
buf.WriteString(str)
|
||||||
|
|
||||||
|
case fSprint:
|
||||||
|
str := spew.Sprint(test.in)
|
||||||
|
buf.WriteString(str)
|
||||||
|
|
||||||
|
case fSprintf:
|
||||||
|
str := spew.Sprintf(test.format, test.in)
|
||||||
|
buf.WriteString(str)
|
||||||
|
|
||||||
|
case fSprintln:
|
||||||
|
str := spew.Sprintln(test.in)
|
||||||
|
buf.WriteString(str)
|
||||||
|
|
||||||
|
default:
|
||||||
|
t.Errorf("%v #%d unrecognized function", test.f, i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s := buf.String()
|
||||||
|
if test.want != s {
|
||||||
|
t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||||
|
// when both cgo is supported and "-tags testcgo" is added to the go test
|
||||||
|
// command line. This code should really only be in the dumpcgo_test.go file,
|
||||||
|
// but unfortunately Go will not allow cgo in test files, so this is a
|
||||||
|
// workaround to allow cgo types to be tested. This configuration is used
|
||||||
|
// because spew itself does not require cgo to run even though it does handle
|
||||||
|
// certain cgo types specially. Rather than forcing all clients to require cgo
|
||||||
|
// and an external C compiler just to run the tests, this scheme makes them
|
||||||
|
// optional.
|
||||||
|
// +build cgo,testcgo
|
||||||
|
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef unsigned char custom_uchar_t;
|
||||||
|
|
||||||
|
char *ncp = 0;
|
||||||
|
char *cp = "test";
|
||||||
|
char ca[6] = {'t', 'e', 's', 't', '2', '\0'};
|
||||||
|
unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'};
|
||||||
|
signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'};
|
||||||
|
uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'};
|
||||||
|
custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'};
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// GetCgoNullCharPointer returns a null char pointer via cgo. This is only
|
||||||
|
// used for tests.
|
||||||
|
func GetCgoNullCharPointer() interface{} {
|
||||||
|
return C.ncp
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCgoCharPointer returns a char pointer via cgo. This is only used for
|
||||||
|
// tests.
|
||||||
|
func GetCgoCharPointer() interface{} {
|
||||||
|
return C.cp
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCgoCharArray returns a char array via cgo and the array's len and cap.
|
||||||
|
// This is only used for tests.
|
||||||
|
func GetCgoCharArray() (interface{}, int, int) {
|
||||||
|
return C.ca, len(C.ca), cap(C.ca)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
|
||||||
|
// array's len and cap. This is only used for tests.
|
||||||
|
func GetCgoUnsignedCharArray() (interface{}, int, int) {
|
||||||
|
return C.uca, len(C.uca), cap(C.uca)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
|
||||||
|
// and cap. This is only used for tests.
|
||||||
|
func GetCgoSignedCharArray() (interface{}, int, int) {
|
||||||
|
return C.sca, len(C.sca), cap(C.sca)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
|
||||||
|
// cap. This is only used for tests.
|
||||||
|
func GetCgoUint8tArray() (interface{}, int, int) {
|
||||||
|
return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
|
||||||
|
// cgo and the array's len and cap. This is only used for tests.
|
||||||
|
func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
|
||||||
|
return C.tuca, len(C.tuca), cap(C.tuca)
|
||||||
|
}
|
7
Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt
generated
vendored
@ -9,13 +9,6 @@ if (WIN32 AND WANT_CRYPTOPP)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(src/libethash)
|
add_subdirectory(src/libethash)
|
||||||
# bin2h.cmake doesn't work
|
|
||||||
if (NOT OpenCL_FOUND)
|
|
||||||
find_package(OpenCL)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (OpenCL_FOUND)
|
|
||||||
add_subdirectory(src/libethash-cl)
|
|
||||||
endif()
|
|
||||||
add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
|
add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(test/c)
|
add_subdirectory(test/c)
|
||||||
|
34
Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
generated
vendored
@ -100,25 +100,41 @@ type Light struct {
|
|||||||
func (l *Light) Verify(block pow.Block) bool {
|
func (l *Light) Verify(block pow.Block) bool {
|
||||||
// TODO: do ethash_quick_verify before getCache in order
|
// TODO: do ethash_quick_verify before getCache in order
|
||||||
// to prevent DOS attacks.
|
// to prevent DOS attacks.
|
||||||
var (
|
blockNum := block.NumberU64()
|
||||||
blockNum = block.NumberU64()
|
|
||||||
difficulty = block.Difficulty()
|
|
||||||
cache = l.getCache(blockNum)
|
|
||||||
dagSize = C.ethash_get_datasize(C.uint64_t(blockNum))
|
|
||||||
)
|
|
||||||
if l.test {
|
|
||||||
dagSize = dagSizeForTesting
|
|
||||||
}
|
|
||||||
if blockNum >= epochLength*2048 {
|
if blockNum >= epochLength*2048 {
|
||||||
glog.V(logger.Debug).Infof("block number %d too high, limit is %d", epochLength*2048)
|
glog.V(logger.Debug).Infof("block number %d too high, limit is %d", epochLength*2048)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
difficulty := block.Difficulty()
|
||||||
|
/* Cannot happen if block header diff is validated prior to PoW, but can
|
||||||
|
happen if PoW is checked first due to parallel PoW checking.
|
||||||
|
We could check the minimum valid difficulty but for SoC we avoid (duplicating)
|
||||||
|
Ethereum protocol consensus rules here which are not in scope of Ethash
|
||||||
|
*/
|
||||||
|
if difficulty.Cmp(common.Big0) == 0 {
|
||||||
|
glog.V(logger.Debug).Infof("invalid block difficulty")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
cache := l.getCache(blockNum)
|
||||||
|
dagSize := C.ethash_get_datasize(C.uint64_t(blockNum))
|
||||||
|
|
||||||
|
if l.test {
|
||||||
|
dagSize = dagSizeForTesting
|
||||||
|
}
|
||||||
// Recompute the hash using the cache.
|
// Recompute the hash using the cache.
|
||||||
hash := hashToH256(block.HashNoNonce())
|
hash := hashToH256(block.HashNoNonce())
|
||||||
ret := C.ethash_light_compute_internal(cache.ptr, dagSize, hash, C.uint64_t(block.Nonce()))
|
ret := C.ethash_light_compute_internal(cache.ptr, dagSize, hash, C.uint64_t(block.Nonce()))
|
||||||
if !ret.success {
|
if !ret.success {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// avoid mixdigest malleability as it's not included in a block's "hashNononce"
|
||||||
|
if block.MixDigest() != h256ToHash(ret.mix_hash) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure cache is live until after the C call.
|
// Make sure cache is live until after the C call.
|
||||||
// This is important because a GC might happen and execute
|
// This is important because a GC might happen and execute
|
||||||
// the finalizer before the call completes.
|
// the finalizer before the call completes.
|
||||||
|
44
Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go
generated
vendored
@ -11,6 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -39,6 +40,7 @@ var validBlocks = []*testBlock{
|
|||||||
hashNoNonce: common.HexToHash("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d"),
|
hashNoNonce: common.HexToHash("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d"),
|
||||||
difficulty: big.NewInt(132416),
|
difficulty: big.NewInt(132416),
|
||||||
nonce: 0x495732e0ed7a801c,
|
nonce: 0x495732e0ed7a801c,
|
||||||
|
mixDigest: common.HexToHash("2f74cdeb198af0b9abe65d22d372e22fb2d474371774a9583c1cc427a07939f5"),
|
||||||
},
|
},
|
||||||
// from proof of concept nine testnet, epoch 1
|
// from proof of concept nine testnet, epoch 1
|
||||||
{
|
{
|
||||||
@ -46,6 +48,7 @@ var validBlocks = []*testBlock{
|
|||||||
hashNoNonce: common.HexToHash("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34"),
|
hashNoNonce: common.HexToHash("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34"),
|
||||||
difficulty: big.NewInt(1532671),
|
difficulty: big.NewInt(1532671),
|
||||||
nonce: 0x318df1c8adef7e5e,
|
nonce: 0x318df1c8adef7e5e,
|
||||||
|
mixDigest: common.HexToHash("144b180aad09ae3c81fb07be92c8e6351b5646dda80e6844ae1b697e55ddde84"),
|
||||||
},
|
},
|
||||||
// from proof of concept nine testnet, epoch 2
|
// from proof of concept nine testnet, epoch 2
|
||||||
{
|
{
|
||||||
@ -53,9 +56,18 @@ var validBlocks = []*testBlock{
|
|||||||
hashNoNonce: common.HexToHash("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0"),
|
hashNoNonce: common.HexToHash("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0"),
|
||||||
difficulty: big.NewInt(2467358),
|
difficulty: big.NewInt(2467358),
|
||||||
nonce: 0x50377003e5d830ca,
|
nonce: 0x50377003e5d830ca,
|
||||||
|
mixDigest: common.HexToHash("ab546a5b73c452ae86dadd36f0ed83a6745226717d3798832d1b20b489e82063"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var invalidZeroDiffBlock = testBlock{
|
||||||
|
number: 61440000,
|
||||||
|
hashNoNonce: crypto.Sha3Hash([]byte("foo")),
|
||||||
|
difficulty: big.NewInt(0),
|
||||||
|
nonce: 0xcafebabec00000fe,
|
||||||
|
mixDigest: crypto.Sha3Hash([]byte("bar")),
|
||||||
|
}
|
||||||
|
|
||||||
func TestEthashVerifyValid(t *testing.T) {
|
func TestEthashVerifyValid(t *testing.T) {
|
||||||
eth := New()
|
eth := New()
|
||||||
for i, block := range validBlocks {
|
for i, block := range validBlocks {
|
||||||
@ -65,6 +77,13 @@ func TestEthashVerifyValid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEthashVerifyInvalid(t *testing.T) {
|
||||||
|
eth := New()
|
||||||
|
if eth.Verify(&invalidZeroDiffBlock) {
|
||||||
|
t.Errorf("should not validate - we just ensure it does not panic on this block")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEthashConcurrentVerify(t *testing.T) {
|
func TestEthashConcurrentVerify(t *testing.T) {
|
||||||
eth, err := NewForTesting()
|
eth, err := NewForTesting()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -73,8 +92,9 @@ func TestEthashConcurrentVerify(t *testing.T) {
|
|||||||
defer os.RemoveAll(eth.Full.Dir)
|
defer os.RemoveAll(eth.Full.Dir)
|
||||||
|
|
||||||
block := &testBlock{difficulty: big.NewInt(10)}
|
block := &testBlock{difficulty: big.NewInt(10)}
|
||||||
nonce, _ := eth.Search(block, nil)
|
nonce, md := eth.Search(block, nil)
|
||||||
block.nonce = nonce
|
block.nonce = nonce
|
||||||
|
block.mixDigest = common.BytesToHash(md)
|
||||||
|
|
||||||
// Verify the block concurrently to check for data races.
|
// Verify the block concurrently to check for data races.
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
@ -98,21 +118,26 @@ func TestEthashConcurrentSearch(t *testing.T) {
|
|||||||
eth.Turbo(true)
|
eth.Turbo(true)
|
||||||
defer os.RemoveAll(eth.Full.Dir)
|
defer os.RemoveAll(eth.Full.Dir)
|
||||||
|
|
||||||
// launch n searches concurrently.
|
type searchRes struct {
|
||||||
|
n uint64
|
||||||
|
md []byte
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
block = &testBlock{difficulty: big.NewInt(35000)}
|
block = &testBlock{difficulty: big.NewInt(35000)}
|
||||||
nsearch = 10
|
nsearch = 10
|
||||||
wg = new(sync.WaitGroup)
|
wg = new(sync.WaitGroup)
|
||||||
found = make(chan uint64)
|
found = make(chan searchRes)
|
||||||
stop = make(chan struct{})
|
stop = make(chan struct{})
|
||||||
)
|
)
|
||||||
rand.Read(block.hashNoNonce[:])
|
rand.Read(block.hashNoNonce[:])
|
||||||
wg.Add(nsearch)
|
wg.Add(nsearch)
|
||||||
|
// launch n searches concurrently.
|
||||||
for i := 0; i < nsearch; i++ {
|
for i := 0; i < nsearch; i++ {
|
||||||
go func() {
|
go func() {
|
||||||
nonce, _ := eth.Search(block, stop)
|
nonce, md := eth.Search(block, stop)
|
||||||
select {
|
select {
|
||||||
case found <- nonce:
|
case found <- searchRes{n: nonce, md: md}:
|
||||||
case <-stop:
|
case <-stop:
|
||||||
}
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
@ -120,12 +145,14 @@ func TestEthashConcurrentSearch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait for one of them to find the nonce
|
// wait for one of them to find the nonce
|
||||||
nonce := <-found
|
res := <-found
|
||||||
// stop the others
|
// stop the others
|
||||||
close(stop)
|
close(stop)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
if block.nonce = nonce; !eth.Verify(block) {
|
block.nonce = res.n
|
||||||
|
block.mixDigest = common.BytesToHash(res.md)
|
||||||
|
if !eth.Verify(block) {
|
||||||
t.Error("Block could not be verified")
|
t.Error("Block could not be verified")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,8 +167,9 @@ func TestEthashSearchAcrossEpoch(t *testing.T) {
|
|||||||
for i := epochLength - 40; i < epochLength+40; i++ {
|
for i := epochLength - 40; i < epochLength+40; i++ {
|
||||||
block := &testBlock{number: i, difficulty: big.NewInt(90)}
|
block := &testBlock{number: i, difficulty: big.NewInt(90)}
|
||||||
rand.Read(block.hashNoNonce[:])
|
rand.Read(block.hashNoNonce[:])
|
||||||
nonce, _ := eth.Search(block, nil)
|
nonce, md := eth.Search(block, nil)
|
||||||
block.nonce = nonce
|
block.nonce = nonce
|
||||||
|
block.mixDigest = common.BytesToHash(md)
|
||||||
if !eth.Verify(block) {
|
if !eth.Verify(block) {
|
||||||
t.Fatalf("Block could not be verified")
|
t.Fatalf("Block could not be verified")
|
||||||
}
|
}
|
||||||
|
47
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/CMakeLists.txt
generated
vendored
@ -1,47 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8)
|
|
||||||
|
|
||||||
set(LIBRARY ethash-cl)
|
|
||||||
set(CMAKE_BUILD_TYPE Release)
|
|
||||||
|
|
||||||
include(bin2h.cmake)
|
|
||||||
bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl
|
|
||||||
VARIABLE_NAME ethash_cl_miner_kernel
|
|
||||||
HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
|
|
||||||
|
|
||||||
if (NOT MSVC)
|
|
||||||
# Initialize CXXFLAGS for c++11
|
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -std=c++11")
|
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
|
|
||||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
|
|
||||||
|
|
||||||
# Compiler-specific C++11 activation.
|
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
|
||||||
if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
|
|
||||||
message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
|
|
||||||
endif ()
|
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
|
||||||
else ()
|
|
||||||
message(FATAL_ERROR "Your C++ compiler does not support C++11.")
|
|
||||||
endif ()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(OpenCL_FOUND TRUE)
|
|
||||||
set(OpenCL_INCLUDE_DIRS /usr/include/CL)
|
|
||||||
set(OpenCL_LIBRARIES -lOpenCL)
|
|
||||||
|
|
||||||
if (NOT OpenCL_FOUND)
|
|
||||||
find_package(OpenCL)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (OpenCL_FOUND)
|
|
||||||
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -pedantic -fPIC ${CMAKE_CXX_FLAGS}")
|
|
||||||
include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
include_directories(..)
|
|
||||||
add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp)
|
|
||||||
TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash)
|
|
||||||
endif()
|
|
86
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/bin2h.cmake
generated
vendored
@ -1,86 +0,0 @@
|
|||||||
# https://gist.github.com/sivachandran/3a0de157dccef822a230
|
|
||||||
include(CMakeParseArguments)
|
|
||||||
|
|
||||||
# Function to wrap a given string into multiple lines at the given column position.
|
|
||||||
# Parameters:
|
|
||||||
# VARIABLE - The name of the CMake variable holding the string.
|
|
||||||
# AT_COLUMN - The column position at which string will be wrapped.
|
|
||||||
function(WRAP_STRING)
|
|
||||||
set(oneValueArgs VARIABLE AT_COLUMN)
|
|
||||||
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
|
|
||||||
|
|
||||||
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
|
|
||||||
math(EXPR offset "0")
|
|
||||||
|
|
||||||
while(stringLength GREATER 0)
|
|
||||||
|
|
||||||
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
|
|
||||||
math(EXPR length "${WRAP_STRING_AT_COLUMN}")
|
|
||||||
else()
|
|
||||||
math(EXPR length "${stringLength}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
|
|
||||||
set(lines "${lines}\n${line}")
|
|
||||||
|
|
||||||
math(EXPR stringLength "${stringLength} - ${length}")
|
|
||||||
math(EXPR offset "${offset} + ${length}")
|
|
||||||
endwhile()
|
|
||||||
|
|
||||||
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file
|
|
||||||
# will contain a byte array and integer variable holding the size of the array.
|
|
||||||
# Parameters
|
|
||||||
# SOURCE_FILE - The path of source file whose contents will be embedded in the header file.
|
|
||||||
# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append
|
|
||||||
# to this name and will be used a variable name for size variable.
|
|
||||||
# HEADER_FILE - The path of header file.
|
|
||||||
# APPEND - If specified appends to the header file instead of overwriting it
|
|
||||||
# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be
|
|
||||||
# useful if the source file is a text file and we want to use the file contents
|
|
||||||
# as string. But the size variable holds size of the byte array without this
|
|
||||||
# null byte.
|
|
||||||
# Usage:
|
|
||||||
# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG")
|
|
||||||
function(BIN2H)
|
|
||||||
set(options APPEND NULL_TERMINATE)
|
|
||||||
set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
|
|
||||||
cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
|
|
||||||
|
|
||||||
# reads source file contents as hex string
|
|
||||||
file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
|
|
||||||
string(LENGTH ${hexString} hexStringLength)
|
|
||||||
|
|
||||||
# appends null byte if asked
|
|
||||||
if(BIN2H_NULL_TERMINATE)
|
|
||||||
set(hexString "${hexString}00")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
|
|
||||||
wrap_string(VARIABLE hexString AT_COLUMN 32)
|
|
||||||
math(EXPR arraySize "${hexStringLength} / 2")
|
|
||||||
|
|
||||||
# adds '0x' prefix and comma suffix before and after every byte respectively
|
|
||||||
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
|
|
||||||
# removes trailing comma
|
|
||||||
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
|
|
||||||
|
|
||||||
# converts the variable name into proper C identifier
|
|
||||||
IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
|
|
||||||
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
|
|
||||||
ENDIF()
|
|
||||||
string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
|
|
||||||
|
|
||||||
# declares byte array and the length variables
|
|
||||||
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
|
|
||||||
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
|
|
||||||
|
|
||||||
set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
|
|
||||||
if(BIN2H_APPEND)
|
|
||||||
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
|
|
||||||
else()
|
|
||||||
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
12906
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/cl.hpp
generated
vendored
384
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.cpp
generated
vendored
@ -1,384 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of c-ethash.
|
|
||||||
|
|
||||||
c-ethash is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
c-ethash is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/** @file ethash_cl_miner.cpp
|
|
||||||
* @author Tim Hughes <tim@twistedfury.com>
|
|
||||||
* @date 2015
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <queue>
|
|
||||||
#include <vector>
|
|
||||||
#include <libethash/util.h>
|
|
||||||
#include <libethash/ethash.h>
|
|
||||||
#include <libethash/internal.h>
|
|
||||||
#include "ethash_cl_miner.h"
|
|
||||||
#include "ethash_cl_miner_kernel.h"
|
|
||||||
|
|
||||||
#define ETHASH_BYTES 32
|
|
||||||
|
|
||||||
// workaround lame platforms
|
|
||||||
#if !CL_VERSION_1_2
|
|
||||||
#define CL_MAP_WRITE_INVALIDATE_REGION CL_MAP_WRITE
|
|
||||||
#define CL_MEM_HOST_READ_ONLY 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef min
|
|
||||||
#undef max
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
static void add_definition(std::string& source, char const* id, unsigned value)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
sprintf(buf, "#define %s %uu\n", id, value);
|
|
||||||
source.insert(source.begin(), buf, buf + strlen(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
ethash_cl_miner::search_hook::~search_hook() {}
|
|
||||||
|
|
||||||
ethash_cl_miner::ethash_cl_miner()
|
|
||||||
: m_opencl_1_1()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId)
|
|
||||||
{
|
|
||||||
std::vector<cl::Platform> platforms;
|
|
||||||
cl::Platform::get(&platforms);
|
|
||||||
if (platforms.empty())
|
|
||||||
{
|
|
||||||
cout << "No OpenCL platforms found." << endl;
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get GPU device of the selected platform
|
|
||||||
std::vector<cl::Device> devices;
|
|
||||||
unsigned platform_num = std::min<unsigned>(_platformId, platforms.size() - 1);
|
|
||||||
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
|
|
||||||
if (devices.empty())
|
|
||||||
{
|
|
||||||
cout << "No OpenCL devices found." << endl;
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
// use selected default device
|
|
||||||
unsigned device_num = std::min<unsigned>(_deviceId, devices.size() - 1);
|
|
||||||
cl::Device& device = devices[device_num];
|
|
||||||
std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
|
|
||||||
|
|
||||||
return "{ \"platform\": \"" + platforms[platform_num].getInfo<CL_PLATFORM_NAME>() + "\", \"device\": \"" + device.getInfo<CL_DEVICE_NAME>() + "\", \"version\": \"" + device_version + "\" }";
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
|
|
||||||
{
|
|
||||||
std::vector<cl::Platform> platforms;
|
|
||||||
cl::Platform::get(&platforms);
|
|
||||||
if (platforms.empty())
|
|
||||||
{
|
|
||||||
cout << "No OpenCL platforms found." << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<cl::Device> devices;
|
|
||||||
unsigned platform_num = std::min<unsigned>(_platformId, platforms.size() - 1);
|
|
||||||
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
|
|
||||||
if (devices.empty())
|
|
||||||
{
|
|
||||||
cout << "No OpenCL devices found." << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return devices.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ethash_cl_miner::finish()
|
|
||||||
{
|
|
||||||
if (m_queue())
|
|
||||||
m_queue.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ethash_cl_miner::init(uint64_t block_number, std::function<void(void*)> _fillDAG, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId)
|
|
||||||
{
|
|
||||||
// store params
|
|
||||||
m_fullSize = ethash_get_datasize(block_number);
|
|
||||||
|
|
||||||
// get all platforms
|
|
||||||
std::vector<cl::Platform> platforms;
|
|
||||||
cl::Platform::get(&platforms);
|
|
||||||
if (platforms.empty())
|
|
||||||
{
|
|
||||||
cout << "No OpenCL platforms found." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use selected platform
|
|
||||||
_platformId = std::min<unsigned>(_platformId, platforms.size() - 1);
|
|
||||||
|
|
||||||
cout << "Using platform: " << platforms[_platformId].getInfo<CL_PLATFORM_NAME>().c_str() << endl;
|
|
||||||
|
|
||||||
// get GPU device of the default platform
|
|
||||||
std::vector<cl::Device> devices;
|
|
||||||
platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices);
|
|
||||||
if (devices.empty())
|
|
||||||
{
|
|
||||||
cout << "No OpenCL devices found." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use selected device
|
|
||||||
cl::Device& device = devices[std::min<unsigned>(_deviceId, devices.size() - 1)];
|
|
||||||
std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
|
|
||||||
cout << "Using device: " << device.getInfo<CL_DEVICE_NAME>().c_str() << "(" << device_version.c_str() << ")" << endl;
|
|
||||||
|
|
||||||
if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0)
|
|
||||||
{
|
|
||||||
cout << "OpenCL 1.0 is not supported." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
|
|
||||||
m_opencl_1_1 = true;
|
|
||||||
|
|
||||||
// create context
|
|
||||||
m_context = cl::Context(std::vector<cl::Device>(&device, &device + 1));
|
|
||||||
m_queue = cl::CommandQueue(m_context, device);
|
|
||||||
|
|
||||||
// use requested workgroup size, but we require multiple of 8
|
|
||||||
m_workgroup_size = ((workgroup_size + 7) / 8) * 8;
|
|
||||||
|
|
||||||
// patch source code
|
|
||||||
std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE);
|
|
||||||
add_definition(code, "GROUP_SIZE", m_workgroup_size);
|
|
||||||
add_definition(code, "DAG_SIZE", (unsigned)(m_fullSize / ETHASH_MIX_BYTES));
|
|
||||||
add_definition(code, "ACCESSES", ETHASH_ACCESSES);
|
|
||||||
add_definition(code, "MAX_OUTPUTS", c_max_search_results);
|
|
||||||
//debugf("%s", code.c_str());
|
|
||||||
|
|
||||||
// create miner OpenCL program
|
|
||||||
cl::Program::Sources sources;
|
|
||||||
sources.push_back({code.c_str(), code.size()});
|
|
||||||
|
|
||||||
cl::Program program(m_context, sources);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
program.build({device});
|
|
||||||
}
|
|
||||||
catch (cl::Error err)
|
|
||||||
{
|
|
||||||
cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_hash_kernel = cl::Kernel(program, "ethash_hash");
|
|
||||||
m_search_kernel = cl::Kernel(program, "ethash_search");
|
|
||||||
|
|
||||||
// create buffer for dag
|
|
||||||
m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, m_fullSize);
|
|
||||||
|
|
||||||
// create buffer for header
|
|
||||||
m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32);
|
|
||||||
|
|
||||||
// compute dag on CPU
|
|
||||||
{
|
|
||||||
// if this throws then it's because we probably need to subdivide the dag uploads for compatibility
|
|
||||||
void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, m_fullSize);
|
|
||||||
// memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap.
|
|
||||||
_fillDAG(dag_ptr);
|
|
||||||
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create mining buffers
|
|
||||||
for (unsigned i = 0; i != c_num_buffers; ++i)
|
|
||||||
{
|
|
||||||
m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32*c_hash_batch_size);
|
|
||||||
m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count)
|
|
||||||
{
|
|
||||||
struct pending_batch
|
|
||||||
{
|
|
||||||
unsigned base;
|
|
||||||
unsigned count;
|
|
||||||
unsigned buf;
|
|
||||||
};
|
|
||||||
std::queue<pending_batch> pending;
|
|
||||||
|
|
||||||
// update header constant buffer
|
|
||||||
m_queue.enqueueWriteBuffer(m_header, true, 0, 32, header);
|
|
||||||
|
|
||||||
/*
|
|
||||||
__kernel void ethash_combined_hash(
|
|
||||||
__global hash32_t* g_hashes,
|
|
||||||
__constant hash32_t const* g_header,
|
|
||||||
__global hash128_t const* g_dag,
|
|
||||||
ulong start_nonce,
|
|
||||||
uint isolate
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
m_hash_kernel.setArg(1, m_header);
|
|
||||||
m_hash_kernel.setArg(2, m_dag);
|
|
||||||
m_hash_kernel.setArg(3, nonce);
|
|
||||||
m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop
|
|
||||||
|
|
||||||
unsigned buf = 0;
|
|
||||||
for (unsigned i = 0; i < count || !pending.empty(); )
|
|
||||||
{
|
|
||||||
// how many this batch
|
|
||||||
if (i < count)
|
|
||||||
{
|
|
||||||
unsigned const this_count = std::min<unsigned>(count - i, c_hash_batch_size);
|
|
||||||
unsigned const batch_count = std::max<unsigned>(this_count, m_workgroup_size);
|
|
||||||
|
|
||||||
// supply output hash buffer to kernel
|
|
||||||
m_hash_kernel.setArg(0, m_hash_buf[buf]);
|
|
||||||
|
|
||||||
// execute it!
|
|
||||||
m_queue.enqueueNDRangeKernel(
|
|
||||||
m_hash_kernel,
|
|
||||||
cl::NullRange,
|
|
||||||
cl::NDRange(batch_count),
|
|
||||||
cl::NDRange(m_workgroup_size)
|
|
||||||
);
|
|
||||||
m_queue.flush();
|
|
||||||
|
|
||||||
pending.push({i, this_count, buf});
|
|
||||||
i += this_count;
|
|
||||||
buf = (buf + 1) % c_num_buffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read results
|
|
||||||
if (i == count || pending.size() == c_num_buffers)
|
|
||||||
{
|
|
||||||
pending_batch const& batch = pending.front();
|
|
||||||
|
|
||||||
// could use pinned host pointer instead, but this path isn't that important.
|
|
||||||
uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * ETHASH_BYTES);
|
|
||||||
memcpy(ret + batch.base*ETHASH_BYTES, hashes, batch.count*ETHASH_BYTES);
|
|
||||||
m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes);
|
|
||||||
|
|
||||||
pending.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook)
|
|
||||||
{
|
|
||||||
struct pending_batch
|
|
||||||
{
|
|
||||||
uint64_t start_nonce;
|
|
||||||
unsigned buf;
|
|
||||||
};
|
|
||||||
std::queue<pending_batch> pending;
|
|
||||||
|
|
||||||
static uint32_t const c_zero = 0;
|
|
||||||
|
|
||||||
// update header constant buffer
|
|
||||||
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
|
|
||||||
for (unsigned i = 0; i != c_num_buffers; ++i)
|
|
||||||
{
|
|
||||||
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CL_VERSION_1_2 && 0
|
|
||||||
cl::Event pre_return_event;
|
|
||||||
if (!m_opencl_1_1)
|
|
||||||
{
|
|
||||||
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
m_queue.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
__kernel void ethash_combined_search(
|
|
||||||
__global hash32_t* g_hashes, // 0
|
|
||||||
__constant hash32_t const* g_header, // 1
|
|
||||||
__global hash128_t const* g_dag, // 2
|
|
||||||
ulong start_nonce, // 3
|
|
||||||
ulong target, // 4
|
|
||||||
uint isolate // 5
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
m_search_kernel.setArg(1, m_header);
|
|
||||||
m_search_kernel.setArg(2, m_dag);
|
|
||||||
|
|
||||||
// pass these to stop the compiler unrolling the loops
|
|
||||||
m_search_kernel.setArg(4, target);
|
|
||||||
m_search_kernel.setArg(5, ~0u);
|
|
||||||
|
|
||||||
|
|
||||||
unsigned buf = 0;
|
|
||||||
for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size)
|
|
||||||
{
|
|
||||||
// supply output buffer to kernel
|
|
||||||
m_search_kernel.setArg(0, m_search_buf[buf]);
|
|
||||||
m_search_kernel.setArg(3, start_nonce);
|
|
||||||
|
|
||||||
// execute it!
|
|
||||||
m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size);
|
|
||||||
|
|
||||||
pending.push({start_nonce, buf});
|
|
||||||
buf = (buf + 1) % c_num_buffers;
|
|
||||||
|
|
||||||
// read results
|
|
||||||
if (pending.size() == c_num_buffers)
|
|
||||||
{
|
|
||||||
pending_batch const& batch = pending.front();
|
|
||||||
|
|
||||||
// could use pinned host pointer instead
|
|
||||||
uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1+c_max_search_results) * sizeof(uint32_t));
|
|
||||||
unsigned num_found = std::min<unsigned>(results[0], c_max_search_results);
|
|
||||||
|
|
||||||
uint64_t nonces[c_max_search_results];
|
|
||||||
for (unsigned i = 0; i != num_found; ++i)
|
|
||||||
{
|
|
||||||
nonces[i] = batch.start_nonce + results[i+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results);
|
|
||||||
|
|
||||||
bool exit = num_found && hook.found(nonces, num_found);
|
|
||||||
exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit
|
|
||||||
if (exit)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// reset search buffer if we're still going
|
|
||||||
if (num_found)
|
|
||||||
m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero);
|
|
||||||
|
|
||||||
pending.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// not safe to return until this is ready
|
|
||||||
#if CL_VERSION_1_2 && 0
|
|
||||||
if (!m_opencl_1_1)
|
|
||||||
{
|
|
||||||
pre_return_event.wait();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
57
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.h
generated
vendored
@ -1,57 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define __CL_ENABLE_EXCEPTIONS
|
|
||||||
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
|
||||||
#include "cl.hpp"
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#else
|
|
||||||
#include "cl.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <functional>
|
|
||||||
#include <libethash/ethash.h>
|
|
||||||
|
|
||||||
class ethash_cl_miner
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct search_hook
|
|
||||||
{
|
|
||||||
virtual ~search_hook(); // always a virtual destructor for a class with virtuals.
|
|
||||||
|
|
||||||
// reports progress, return true to abort
|
|
||||||
virtual bool found(uint64_t const* nonces, uint32_t count) = 0;
|
|
||||||
virtual bool searched(uint64_t start_nonce, uint32_t count) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
ethash_cl_miner();
|
|
||||||
|
|
||||||
bool init(uint64_t block_number, std::function<void(void*)> _fillDAG, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0);
|
|
||||||
static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0);
|
|
||||||
static unsigned get_num_devices(unsigned _platformId = 0);
|
|
||||||
|
|
||||||
|
|
||||||
void finish();
|
|
||||||
void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count);
|
|
||||||
void search(uint8_t const* header, uint64_t target, search_hook& hook);
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 };
|
|
||||||
|
|
||||||
uint64_t m_fullSize;
|
|
||||||
cl::Context m_context;
|
|
||||||
cl::CommandQueue m_queue;
|
|
||||||
cl::Kernel m_hash_kernel;
|
|
||||||
cl::Kernel m_search_kernel;
|
|
||||||
cl::Buffer m_dag;
|
|
||||||
cl::Buffer m_header;
|
|
||||||
cl::Buffer m_hash_buf[c_num_buffers];
|
|
||||||
cl::Buffer m_search_buf[c_num_buffers];
|
|
||||||
unsigned m_workgroup_size;
|
|
||||||
bool m_opencl_1_1;
|
|
||||||
};
|
|
460
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner_kernel.cl
generated
vendored
@ -1,460 +0,0 @@
|
|||||||
// author Tim Hughes <tim@twistedfury.com>
|
|
||||||
// Tested on Radeon HD 7850
|
|
||||||
// Hashrate: 15940347 hashes/s
|
|
||||||
// Bandwidth: 124533 MB/s
|
|
||||||
// search kernel should fit in <= 84 VGPRS (3 wavefronts)
|
|
||||||
|
|
||||||
#define THREADS_PER_HASH (128 / 16)
|
|
||||||
#define HASHES_PER_LOOP (GROUP_SIZE / THREADS_PER_HASH)
|
|
||||||
|
|
||||||
#define FNV_PRIME 0x01000193
|
|
||||||
|
|
||||||
__constant uint2 const Keccak_f1600_RC[24] = {
|
|
||||||
(uint2)(0x00000001, 0x00000000),
|
|
||||||
(uint2)(0x00008082, 0x00000000),
|
|
||||||
(uint2)(0x0000808a, 0x80000000),
|
|
||||||
(uint2)(0x80008000, 0x80000000),
|
|
||||||
(uint2)(0x0000808b, 0x00000000),
|
|
||||||
(uint2)(0x80000001, 0x00000000),
|
|
||||||
(uint2)(0x80008081, 0x80000000),
|
|
||||||
(uint2)(0x00008009, 0x80000000),
|
|
||||||
(uint2)(0x0000008a, 0x00000000),
|
|
||||||
(uint2)(0x00000088, 0x00000000),
|
|
||||||
(uint2)(0x80008009, 0x00000000),
|
|
||||||
(uint2)(0x8000000a, 0x00000000),
|
|
||||||
(uint2)(0x8000808b, 0x00000000),
|
|
||||||
(uint2)(0x0000008b, 0x80000000),
|
|
||||||
(uint2)(0x00008089, 0x80000000),
|
|
||||||
(uint2)(0x00008003, 0x80000000),
|
|
||||||
(uint2)(0x00008002, 0x80000000),
|
|
||||||
(uint2)(0x00000080, 0x80000000),
|
|
||||||
(uint2)(0x0000800a, 0x00000000),
|
|
||||||
(uint2)(0x8000000a, 0x80000000),
|
|
||||||
(uint2)(0x80008081, 0x80000000),
|
|
||||||
(uint2)(0x00008080, 0x80000000),
|
|
||||||
(uint2)(0x80000001, 0x00000000),
|
|
||||||
(uint2)(0x80008008, 0x80000000),
|
|
||||||
};
|
|
||||||
|
|
||||||
void keccak_f1600_round(uint2* a, uint r, uint out_size)
|
|
||||||
{
|
|
||||||
#if !__ENDIAN_LITTLE__
|
|
||||||
for (uint i = 0; i != 25; ++i)
|
|
||||||
a[i] = a[i].yx;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint2 b[25];
|
|
||||||
uint2 t;
|
|
||||||
|
|
||||||
// Theta
|
|
||||||
b[0] = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20];
|
|
||||||
b[1] = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21];
|
|
||||||
b[2] = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22];
|
|
||||||
b[3] = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23];
|
|
||||||
b[4] = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24];
|
|
||||||
t = b[4] ^ (uint2)(b[1].x << 1 | b[1].y >> 31, b[1].y << 1 | b[1].x >> 31);
|
|
||||||
a[0] ^= t;
|
|
||||||
a[5] ^= t;
|
|
||||||
a[10] ^= t;
|
|
||||||
a[15] ^= t;
|
|
||||||
a[20] ^= t;
|
|
||||||
t = b[0] ^ (uint2)(b[2].x << 1 | b[2].y >> 31, b[2].y << 1 | b[2].x >> 31);
|
|
||||||
a[1] ^= t;
|
|
||||||
a[6] ^= t;
|
|
||||||
a[11] ^= t;
|
|
||||||
a[16] ^= t;
|
|
||||||
a[21] ^= t;
|
|
||||||
t = b[1] ^ (uint2)(b[3].x << 1 | b[3].y >> 31, b[3].y << 1 | b[3].x >> 31);
|
|
||||||
a[2] ^= t;
|
|
||||||
a[7] ^= t;
|
|
||||||
a[12] ^= t;
|
|
||||||
a[17] ^= t;
|
|
||||||
a[22] ^= t;
|
|
||||||
t = b[2] ^ (uint2)(b[4].x << 1 | b[4].y >> 31, b[4].y << 1 | b[4].x >> 31);
|
|
||||||
a[3] ^= t;
|
|
||||||
a[8] ^= t;
|
|
||||||
a[13] ^= t;
|
|
||||||
a[18] ^= t;
|
|
||||||
a[23] ^= t;
|
|
||||||
t = b[3] ^ (uint2)(b[0].x << 1 | b[0].y >> 31, b[0].y << 1 | b[0].x >> 31);
|
|
||||||
a[4] ^= t;
|
|
||||||
a[9] ^= t;
|
|
||||||
a[14] ^= t;
|
|
||||||
a[19] ^= t;
|
|
||||||
a[24] ^= t;
|
|
||||||
|
|
||||||
// Rho Pi
|
|
||||||
b[0] = a[0];
|
|
||||||
b[10] = (uint2)(a[1].x << 1 | a[1].y >> 31, a[1].y << 1 | a[1].x >> 31);
|
|
||||||
b[7] = (uint2)(a[10].x << 3 | a[10].y >> 29, a[10].y << 3 | a[10].x >> 29);
|
|
||||||
b[11] = (uint2)(a[7].x << 6 | a[7].y >> 26, a[7].y << 6 | a[7].x >> 26);
|
|
||||||
b[17] = (uint2)(a[11].x << 10 | a[11].y >> 22, a[11].y << 10 | a[11].x >> 22);
|
|
||||||
b[18] = (uint2)(a[17].x << 15 | a[17].y >> 17, a[17].y << 15 | a[17].x >> 17);
|
|
||||||
b[3] = (uint2)(a[18].x << 21 | a[18].y >> 11, a[18].y << 21 | a[18].x >> 11);
|
|
||||||
b[5] = (uint2)(a[3].x << 28 | a[3].y >> 4, a[3].y << 28 | a[3].x >> 4);
|
|
||||||
b[16] = (uint2)(a[5].y << 4 | a[5].x >> 28, a[5].x << 4 | a[5].y >> 28);
|
|
||||||
b[8] = (uint2)(a[16].y << 13 | a[16].x >> 19, a[16].x << 13 | a[16].y >> 19);
|
|
||||||
b[21] = (uint2)(a[8].y << 23 | a[8].x >> 9, a[8].x << 23 | a[8].y >> 9);
|
|
||||||
b[24] = (uint2)(a[21].x << 2 | a[21].y >> 30, a[21].y << 2 | a[21].x >> 30);
|
|
||||||
b[4] = (uint2)(a[24].x << 14 | a[24].y >> 18, a[24].y << 14 | a[24].x >> 18);
|
|
||||||
b[15] = (uint2)(a[4].x << 27 | a[4].y >> 5, a[4].y << 27 | a[4].x >> 5);
|
|
||||||
b[23] = (uint2)(a[15].y << 9 | a[15].x >> 23, a[15].x << 9 | a[15].y >> 23);
|
|
||||||
b[19] = (uint2)(a[23].y << 24 | a[23].x >> 8, a[23].x << 24 | a[23].y >> 8);
|
|
||||||
b[13] = (uint2)(a[19].x << 8 | a[19].y >> 24, a[19].y << 8 | a[19].x >> 24);
|
|
||||||
b[12] = (uint2)(a[13].x << 25 | a[13].y >> 7, a[13].y << 25 | a[13].x >> 7);
|
|
||||||
b[2] = (uint2)(a[12].y << 11 | a[12].x >> 21, a[12].x << 11 | a[12].y >> 21);
|
|
||||||
b[20] = (uint2)(a[2].y << 30 | a[2].x >> 2, a[2].x << 30 | a[2].y >> 2);
|
|
||||||
b[14] = (uint2)(a[20].x << 18 | a[20].y >> 14, a[20].y << 18 | a[20].x >> 14);
|
|
||||||
b[22] = (uint2)(a[14].y << 7 | a[14].x >> 25, a[14].x << 7 | a[14].y >> 25);
|
|
||||||
b[9] = (uint2)(a[22].y << 29 | a[22].x >> 3, a[22].x << 29 | a[22].y >> 3);
|
|
||||||
b[6] = (uint2)(a[9].x << 20 | a[9].y >> 12, a[9].y << 20 | a[9].x >> 12);
|
|
||||||
b[1] = (uint2)(a[6].y << 12 | a[6].x >> 20, a[6].x << 12 | a[6].y >> 20);
|
|
||||||
|
|
||||||
// Chi
|
|
||||||
a[0] = bitselect(b[0] ^ b[2], b[0], b[1]);
|
|
||||||
a[1] = bitselect(b[1] ^ b[3], b[1], b[2]);
|
|
||||||
a[2] = bitselect(b[2] ^ b[4], b[2], b[3]);
|
|
||||||
a[3] = bitselect(b[3] ^ b[0], b[3], b[4]);
|
|
||||||
if (out_size >= 4)
|
|
||||||
{
|
|
||||||
a[4] = bitselect(b[4] ^ b[1], b[4], b[0]);
|
|
||||||
a[5] = bitselect(b[5] ^ b[7], b[5], b[6]);
|
|
||||||
a[6] = bitselect(b[6] ^ b[8], b[6], b[7]);
|
|
||||||
a[7] = bitselect(b[7] ^ b[9], b[7], b[8]);
|
|
||||||
a[8] = bitselect(b[8] ^ b[5], b[8], b[9]);
|
|
||||||
if (out_size >= 8)
|
|
||||||
{
|
|
||||||
a[9] = bitselect(b[9] ^ b[6], b[9], b[5]);
|
|
||||||
a[10] = bitselect(b[10] ^ b[12], b[10], b[11]);
|
|
||||||
a[11] = bitselect(b[11] ^ b[13], b[11], b[12]);
|
|
||||||
a[12] = bitselect(b[12] ^ b[14], b[12], b[13]);
|
|
||||||
a[13] = bitselect(b[13] ^ b[10], b[13], b[14]);
|
|
||||||
a[14] = bitselect(b[14] ^ b[11], b[14], b[10]);
|
|
||||||
a[15] = bitselect(b[15] ^ b[17], b[15], b[16]);
|
|
||||||
a[16] = bitselect(b[16] ^ b[18], b[16], b[17]);
|
|
||||||
a[17] = bitselect(b[17] ^ b[19], b[17], b[18]);
|
|
||||||
a[18] = bitselect(b[18] ^ b[15], b[18], b[19]);
|
|
||||||
a[19] = bitselect(b[19] ^ b[16], b[19], b[15]);
|
|
||||||
a[20] = bitselect(b[20] ^ b[22], b[20], b[21]);
|
|
||||||
a[21] = bitselect(b[21] ^ b[23], b[21], b[22]);
|
|
||||||
a[22] = bitselect(b[22] ^ b[24], b[22], b[23]);
|
|
||||||
a[23] = bitselect(b[23] ^ b[20], b[23], b[24]);
|
|
||||||
a[24] = bitselect(b[24] ^ b[21], b[24], b[20]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iota
|
|
||||||
a[0] ^= Keccak_f1600_RC[r];
|
|
||||||
|
|
||||||
#if !__ENDIAN_LITTLE__
|
|
||||||
for (uint i = 0; i != 25; ++i)
|
|
||||||
a[i] = a[i].yx;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
|
|
||||||
{
|
|
||||||
for (uint i = in_size; i != 25; ++i)
|
|
||||||
{
|
|
||||||
a[i] = 0;
|
|
||||||
}
|
|
||||||
#if __ENDIAN_LITTLE__
|
|
||||||
a[in_size] ^= 0x0000000000000001;
|
|
||||||
a[24-out_size*2] ^= 0x8000000000000000;
|
|
||||||
#else
|
|
||||||
a[in_size] ^= 0x0100000000000000;
|
|
||||||
a[24-out_size*2] ^= 0x0000000000000080;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Originally I unrolled the first and last rounds to interface
|
|
||||||
// better with surrounding code, however I haven't done this
|
|
||||||
// without causing the AMD compiler to blow up the VGPR usage.
|
|
||||||
uint r = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// This dynamic branch stops the AMD compiler unrolling the loop
|
|
||||||
// and additionally saves about 33% of the VGPRs, enough to gain another
|
|
||||||
// wavefront. Ideally we'd get 4 in flight, but 3 is the best I can
|
|
||||||
// massage out of the compiler. It doesn't really seem to matter how
|
|
||||||
// much we try and help the compiler save VGPRs because it seems to throw
|
|
||||||
// that information away, hence the implementation of keccak here
|
|
||||||
// doesn't bother.
|
|
||||||
if (isolate)
|
|
||||||
{
|
|
||||||
keccak_f1600_round((uint2*)a, r++, 25);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (r < 23);
|
|
||||||
|
|
||||||
// final round optimised for digest size
|
|
||||||
keccak_f1600_round((uint2*)a, r++, out_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define copy(dst, src, count) for (uint i = 0; i != count; ++i) { (dst)[i] = (src)[i]; }
|
|
||||||
|
|
||||||
#define countof(x) (sizeof(x) / sizeof(x[0]))
|
|
||||||
|
|
||||||
uint fnv(uint x, uint y)
|
|
||||||
{
|
|
||||||
return x * FNV_PRIME ^ y;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint4 fnv4(uint4 x, uint4 y)
|
|
||||||
{
|
|
||||||
return x * FNV_PRIME ^ y;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint fnv_reduce(uint4 v)
|
|
||||||
{
|
|
||||||
return fnv(fnv(fnv(v.x, v.y), v.z), v.w);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
ulong ulongs[32 / sizeof(ulong)];
|
|
||||||
uint uints[32 / sizeof(uint)];
|
|
||||||
} hash32_t;
|
|
||||||
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
ulong ulongs[64 / sizeof(ulong)];
|
|
||||||
uint4 uint4s[64 / sizeof(uint4)];
|
|
||||||
} hash64_t;
|
|
||||||
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
uint uints[128 / sizeof(uint)];
|
|
||||||
uint4 uint4s[128 / sizeof(uint4)];
|
|
||||||
} hash128_t;
|
|
||||||
|
|
||||||
hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
|
|
||||||
{
|
|
||||||
hash64_t init;
|
|
||||||
uint const init_size = countof(init.ulongs);
|
|
||||||
uint const hash_size = countof(header->ulongs);
|
|
||||||
|
|
||||||
// sha3_512(header .. nonce)
|
|
||||||
ulong state[25];
|
|
||||||
copy(state, header->ulongs, hash_size);
|
|
||||||
state[hash_size] = nonce;
|
|
||||||
keccak_f1600_no_absorb(state, hash_size + 1, init_size, isolate);
|
|
||||||
|
|
||||||
copy(init.ulongs, state, init_size);
|
|
||||||
return init;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
|
|
||||||
{
|
|
||||||
uint4 mix = init;
|
|
||||||
|
|
||||||
// share init0
|
|
||||||
if (thread_id == 0)
|
|
||||||
*share = mix.x;
|
|
||||||
barrier(CLK_LOCAL_MEM_FENCE);
|
|
||||||
uint init0 = *share;
|
|
||||||
|
|
||||||
uint a = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
bool update_share = thread_id == (a/4) % THREADS_PER_HASH;
|
|
||||||
|
|
||||||
#pragma unroll
|
|
||||||
for (uint i = 0; i != 4; ++i)
|
|
||||||
{
|
|
||||||
if (update_share)
|
|
||||||
{
|
|
||||||
uint m[4] = { mix.x, mix.y, mix.z, mix.w };
|
|
||||||
*share = fnv(init0 ^ (a+i), m[i]) % DAG_SIZE;
|
|
||||||
}
|
|
||||||
barrier(CLK_LOCAL_MEM_FENCE);
|
|
||||||
|
|
||||||
mix = fnv4(mix, g_dag[*share].uint4s[thread_id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ((a += 4) != (ACCESSES & isolate));
|
|
||||||
|
|
||||||
return fnv_reduce(mix);
|
|
||||||
}
|
|
||||||
|
|
||||||
hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
|
|
||||||
{
|
|
||||||
ulong state[25];
|
|
||||||
|
|
||||||
hash32_t hash;
|
|
||||||
uint const hash_size = countof(hash.ulongs);
|
|
||||||
uint const init_size = countof(init->ulongs);
|
|
||||||
uint const mix_size = countof(mix->ulongs);
|
|
||||||
|
|
||||||
// keccak_256(keccak_512(header..nonce) .. mix);
|
|
||||||
copy(state, init->ulongs, init_size);
|
|
||||||
copy(state + init_size, mix->ulongs, mix_size);
|
|
||||||
keccak_f1600_no_absorb(state, init_size+mix_size, hash_size, isolate);
|
|
||||||
|
|
||||||
// copy out
|
|
||||||
copy(hash.ulongs, state, hash_size);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
hash32_t compute_hash_simple(
|
|
||||||
__constant hash32_t const* g_header,
|
|
||||||
__global hash128_t const* g_dag,
|
|
||||||
ulong nonce,
|
|
||||||
uint isolate
|
|
||||||
)
|
|
||||||
{
|
|
||||||
hash64_t init = init_hash(g_header, nonce, isolate);
|
|
||||||
|
|
||||||
hash128_t mix;
|
|
||||||
for (uint i = 0; i != countof(mix.uint4s); ++i)
|
|
||||||
{
|
|
||||||
mix.uint4s[i] = init.uint4s[i % countof(init.uint4s)];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint mix_val = mix.uints[0];
|
|
||||||
uint init0 = mix.uints[0];
|
|
||||||
uint a = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint pi = fnv(init0 ^ a, mix_val) % DAG_SIZE;
|
|
||||||
uint n = (a+1) % countof(mix.uints);
|
|
||||||
|
|
||||||
#pragma unroll
|
|
||||||
for (uint i = 0; i != countof(mix.uints); ++i)
|
|
||||||
{
|
|
||||||
mix.uints[i] = fnv(mix.uints[i], g_dag[pi].uints[i]);
|
|
||||||
mix_val = i == n ? mix.uints[i] : mix_val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (++a != (ACCESSES & isolate));
|
|
||||||
|
|
||||||
// reduce to output
|
|
||||||
hash32_t fnv_mix;
|
|
||||||
for (uint i = 0; i != countof(fnv_mix.uints); ++i)
|
|
||||||
{
|
|
||||||
fnv_mix.uints[i] = fnv_reduce(mix.uint4s[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return final_hash(&init, &fnv_mix, isolate);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
hash64_t init;
|
|
||||||
uint pad; // avoid lds bank conflicts
|
|
||||||
};
|
|
||||||
hash32_t mix;
|
|
||||||
} compute_hash_share;
|
|
||||||
|
|
||||||
hash32_t compute_hash(
|
|
||||||
__local compute_hash_share* share,
|
|
||||||
__constant hash32_t const* g_header,
|
|
||||||
__global hash128_t const* g_dag,
|
|
||||||
ulong nonce,
|
|
||||||
uint isolate
|
|
||||||
)
|
|
||||||
{
|
|
||||||
uint const gid = get_global_id(0);
|
|
||||||
|
|
||||||
// Compute one init hash per work item.
|
|
||||||
hash64_t init = init_hash(g_header, nonce, isolate);
|
|
||||||
|
|
||||||
// Threads work together in this phase in groups of 8.
|
|
||||||
uint const thread_id = gid % THREADS_PER_HASH;
|
|
||||||
uint const hash_id = (gid % GROUP_SIZE) / THREADS_PER_HASH;
|
|
||||||
|
|
||||||
hash32_t mix;
|
|
||||||
uint i = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// share init with other threads
|
|
||||||
if (i == thread_id)
|
|
||||||
share[hash_id].init = init;
|
|
||||||
barrier(CLK_LOCAL_MEM_FENCE);
|
|
||||||
|
|
||||||
uint4 thread_init = share[hash_id].init.uint4s[thread_id % (64 / sizeof(uint4))];
|
|
||||||
barrier(CLK_LOCAL_MEM_FENCE);
|
|
||||||
|
|
||||||
uint thread_mix = inner_loop(thread_init, thread_id, share[hash_id].mix.uints, g_dag, isolate);
|
|
||||||
|
|
||||||
share[hash_id].mix.uints[thread_id] = thread_mix;
|
|
||||||
barrier(CLK_LOCAL_MEM_FENCE);
|
|
||||||
|
|
||||||
if (i == thread_id)
|
|
||||||
mix = share[hash_id].mix;
|
|
||||||
barrier(CLK_LOCAL_MEM_FENCE);
|
|
||||||
}
|
|
||||||
while (++i != (THREADS_PER_HASH & isolate));
|
|
||||||
|
|
||||||
return final_hash(&init, &mix, isolate);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
|
|
||||||
__kernel void ethash_hash_simple(
|
|
||||||
__global hash32_t* g_hashes,
|
|
||||||
__constant hash32_t const* g_header,
|
|
||||||
__global hash128_t const* g_dag,
|
|
||||||
ulong start_nonce,
|
|
||||||
uint isolate
|
|
||||||
)
|
|
||||||
{
|
|
||||||
uint const gid = get_global_id(0);
|
|
||||||
g_hashes[gid] = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
|
|
||||||
__kernel void ethash_search_simple(
|
|
||||||
__global volatile uint* restrict g_output,
|
|
||||||
__constant hash32_t const* g_header,
|
|
||||||
__global hash128_t const* g_dag,
|
|
||||||
ulong start_nonce,
|
|
||||||
ulong target,
|
|
||||||
uint isolate
|
|
||||||
)
|
|
||||||
{
|
|
||||||
uint const gid = get_global_id(0);
|
|
||||||
hash32_t hash = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate);
|
|
||||||
if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target)
|
|
||||||
{
|
|
||||||
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
|
|
||||||
g_output[slot] = gid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
|
|
||||||
__kernel void ethash_hash(
|
|
||||||
__global hash32_t* g_hashes,
|
|
||||||
__constant hash32_t const* g_header,
|
|
||||||
__global hash128_t const* g_dag,
|
|
||||||
ulong start_nonce,
|
|
||||||
uint isolate
|
|
||||||
)
|
|
||||||
{
|
|
||||||
__local compute_hash_share share[HASHES_PER_LOOP];
|
|
||||||
|
|
||||||
uint const gid = get_global_id(0);
|
|
||||||
g_hashes[gid] = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
|
|
||||||
__kernel void ethash_search(
|
|
||||||
__global volatile uint* restrict g_output,
|
|
||||||
__constant hash32_t const* g_header,
|
|
||||||
__global hash128_t const* g_dag,
|
|
||||||
ulong start_nonce,
|
|
||||||
ulong target,
|
|
||||||
uint isolate
|
|
||||||
)
|
|
||||||
{
|
|
||||||
__local compute_hash_share share[HASHES_PER_LOOP];
|
|
||||||
|
|
||||||
uint const gid = get_global_id(0);
|
|
||||||
hash32_t hash = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate);
|
|
||||||
|
|
||||||
if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target)
|
|
||||||
{
|
|
||||||
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
|
|
||||||
g_output[slot] = gid;
|
|
||||||
}
|
|
||||||
}
|
|
3
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/endian.h
generated
vendored
@ -32,6 +32,9 @@
|
|||||||
#include <libkern/OSByteOrder.h>
|
#include <libkern/OSByteOrder.h>
|
||||||
#define ethash_swap_u32(input_) OSSwapInt32(input_)
|
#define ethash_swap_u32(input_) OSSwapInt32(input_)
|
||||||
#define ethash_swap_u64(input_) OSSwapInt64(input_)
|
#define ethash_swap_u64(input_) OSSwapInt64(input_)
|
||||||
|
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||||
|
#define ethash_swap_u32(input_) bswap32(input_)
|
||||||
|
#define ethash_swap_u64(input_) bswap64(input_)
|
||||||
#else // posix
|
#else // posix
|
||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
#define ethash_swap_u32(input_) __bswap_32(input_)
|
#define ethash_swap_u32(input_) __bswap_32(input_)
|
||||||
|
17
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c
generated
vendored
@ -284,13 +284,13 @@ bool ethash_quick_check_difficulty(
|
|||||||
ethash_h256_t const* header_hash,
|
ethash_h256_t const* header_hash,
|
||||||
uint64_t const nonce,
|
uint64_t const nonce,
|
||||||
ethash_h256_t const* mix_hash,
|
ethash_h256_t const* mix_hash,
|
||||||
ethash_h256_t const* difficulty
|
ethash_h256_t const* boundary
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
ethash_h256_t return_hash;
|
ethash_h256_t return_hash;
|
||||||
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
|
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
|
||||||
return ethash_check_difficulty(&return_hash, difficulty);
|
return ethash_check_difficulty(&return_hash, boundary);
|
||||||
}
|
}
|
||||||
|
|
||||||
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
|
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
|
||||||
@ -364,6 +364,7 @@ static bool ethash_mmap(struct ethash_full* ret, FILE* f)
|
|||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
char* mmapped_data;
|
char* mmapped_data;
|
||||||
|
errno = 0;
|
||||||
ret->file = f;
|
ret->file = f;
|
||||||
if ((fd = ethash_fileno(ret->file)) == -1) {
|
if ((fd = ethash_fileno(ret->file)) == -1) {
|
||||||
return false;
|
return false;
|
||||||
@ -400,38 +401,48 @@ ethash_full_t ethash_full_new_internal(
|
|||||||
ret->file_size = (size_t)full_size;
|
ret->file_size = (size_t)full_size;
|
||||||
switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
|
switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
|
||||||
case ETHASH_IO_FAIL:
|
case ETHASH_IO_FAIL:
|
||||||
|
// ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case
|
||||||
goto fail_free_full;
|
goto fail_free_full;
|
||||||
case ETHASH_IO_MEMO_MATCH:
|
case ETHASH_IO_MEMO_MATCH:
|
||||||
if (!ethash_mmap(ret, f)) {
|
if (!ethash_mmap(ret, f)) {
|
||||||
|
ETHASH_CRITICAL("mmap failure()");
|
||||||
goto fail_close_file;
|
goto fail_close_file;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
case ETHASH_IO_MEMO_SIZE_MISMATCH:
|
case ETHASH_IO_MEMO_SIZE_MISMATCH:
|
||||||
// if a DAG of same filename but unexpected size is found, silently force new file creation
|
// if a DAG of same filename but unexpected size is found, silently force new file creation
|
||||||
if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
|
if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
|
||||||
|
ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size.");
|
||||||
goto fail_free_full;
|
goto fail_free_full;
|
||||||
}
|
}
|
||||||
// fallthrough to the mismatch case here, DO NOT go through match
|
// fallthrough to the mismatch case here, DO NOT go through match
|
||||||
case ETHASH_IO_MEMO_MISMATCH:
|
case ETHASH_IO_MEMO_MISMATCH:
|
||||||
if (!ethash_mmap(ret, f)) {
|
if (!ethash_mmap(ret, f)) {
|
||||||
|
ETHASH_CRITICAL("mmap failure()");
|
||||||
goto fail_close_file;
|
goto fail_close_file;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ethash_compute_full_data(ret->data, full_size, light, callback)) {
|
if (!ethash_compute_full_data(ret->data, full_size, light, callback)) {
|
||||||
|
ETHASH_CRITICAL("Failure at computing DAG data.");
|
||||||
goto fail_free_full_data;
|
goto fail_free_full_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// after the DAG has been filled then we finalize it by writting the magic number at the beginning
|
// after the DAG has been filled then we finalize it by writting the magic number at the beginning
|
||||||
if (fseek(f, 0, SEEK_SET) != 0) {
|
if (fseek(f, 0, SEEK_SET) != 0) {
|
||||||
|
ETHASH_CRITICAL("Could not seek to DAG file start to write magic number.");
|
||||||
goto fail_free_full_data;
|
goto fail_free_full_data;
|
||||||
}
|
}
|
||||||
uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM;
|
uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM;
|
||||||
if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
|
if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
|
||||||
|
ETHASH_CRITICAL("Could not write magic number to DAG's beginning.");
|
||||||
|
goto fail_free_full_data;
|
||||||
|
}
|
||||||
|
if (fflush(f) != 0) {// make sure the magic number IS there
|
||||||
|
ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?");
|
||||||
goto fail_free_full_data;
|
goto fail_free_full_data;
|
||||||
}
|
}
|
||||||
fflush(f); // make sure the magic number IS there
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fail_free_full_data:
|
fail_free_full_data:
|
||||||
|
21
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h
generated
vendored
@ -46,27 +46,36 @@ static inline void ethash_h256_reset(ethash_h256_t* hash)
|
|||||||
memset(hash, 0, 32);
|
memset(hash, 0, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns if hash is less than or equal to difficulty
|
// Returns if hash is less than or equal to boundary (2^256/difficulty)
|
||||||
static inline bool ethash_check_difficulty(
|
static inline bool ethash_check_difficulty(
|
||||||
ethash_h256_t const* hash,
|
ethash_h256_t const* hash,
|
||||||
ethash_h256_t const* difficulty
|
ethash_h256_t const* boundary
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Difficulty is big endian
|
// Boundary is big endian
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) {
|
if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i);
|
return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Difficulty quick check for POW preverification
|
||||||
|
*
|
||||||
|
* @param header_hash The hash of the header
|
||||||
|
* @param nonce The block's nonce
|
||||||
|
* @param mix_hash The mix digest hash
|
||||||
|
* @param boundary The boundary is defined as (2^256 / difficulty)
|
||||||
|
* @return true for succesful pre-verification and false otherwise
|
||||||
|
*/
|
||||||
bool ethash_quick_check_difficulty(
|
bool ethash_quick_check_difficulty(
|
||||||
ethash_h256_t const* header_hash,
|
ethash_h256_t const* header_hash,
|
||||||
uint64_t const nonce,
|
uint64_t const nonce,
|
||||||
ethash_h256_t const* mix_hash,
|
ethash_h256_t const* mix_hash,
|
||||||
ethash_h256_t const* difficulty
|
ethash_h256_t const* boundary
|
||||||
);
|
);
|
||||||
|
|
||||||
struct ethash_light {
|
struct ethash_light {
|
||||||
|
21
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.c
generated
vendored
@ -21,6 +21,7 @@
|
|||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
enum ethash_io_rc ethash_io_prepare(
|
enum ethash_io_rc ethash_io_prepare(
|
||||||
char const* dirname,
|
char const* dirname,
|
||||||
@ -32,15 +33,19 @@ enum ethash_io_rc ethash_io_prepare(
|
|||||||
{
|
{
|
||||||
char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
|
char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
|
||||||
enum ethash_io_rc ret = ETHASH_IO_FAIL;
|
enum ethash_io_rc ret = ETHASH_IO_FAIL;
|
||||||
|
// reset errno before io calls
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
// assert directory exists
|
// assert directory exists
|
||||||
if (!ethash_mkdir(dirname)) {
|
if (!ethash_mkdir(dirname)) {
|
||||||
|
ETHASH_CRITICAL("Could not create the ethash directory");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name);
|
ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name);
|
||||||
char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
|
char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
|
||||||
if (!tmpfile) {
|
if (!tmpfile) {
|
||||||
|
ETHASH_CRITICAL("Could not create the full DAG pathname");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +57,7 @@ enum ethash_io_rc ethash_io_prepare(
|
|||||||
size_t found_size;
|
size_t found_size;
|
||||||
if (!ethash_file_size(f, &found_size)) {
|
if (!ethash_file_size(f, &found_size)) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile);
|
||||||
goto free_memo;
|
goto free_memo;
|
||||||
}
|
}
|
||||||
if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) {
|
if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) {
|
||||||
@ -64,6 +70,7 @@ enum ethash_io_rc ethash_io_prepare(
|
|||||||
if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
|
if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
|
||||||
// I/O error
|
// I/O error
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile);
|
||||||
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
|
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
|
||||||
goto free_memo;
|
goto free_memo;
|
||||||
}
|
}
|
||||||
@ -80,15 +87,25 @@ enum ethash_io_rc ethash_io_prepare(
|
|||||||
// file does not exist, will need to be created
|
// file does not exist, will need to be created
|
||||||
f = ethash_fopen(tmpfile, "wb+");
|
f = ethash_fopen(tmpfile, "wb+");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
|
ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile);
|
||||||
goto free_memo;
|
goto free_memo;
|
||||||
}
|
}
|
||||||
// make sure it's of the proper size
|
// make sure it's of the proper size
|
||||||
if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) {
|
if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile);
|
||||||
|
goto free_memo;
|
||||||
|
}
|
||||||
|
if (fputc('\n', f) == EOF) {
|
||||||
|
fclose(f);
|
||||||
|
ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile);
|
||||||
|
goto free_memo;
|
||||||
|
}
|
||||||
|
if (fflush(f) != 0) {
|
||||||
|
fclose(f);
|
||||||
|
ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile);
|
||||||
goto free_memo;
|
goto free_memo;
|
||||||
}
|
}
|
||||||
fputc('\n', f);
|
|
||||||
fflush(f);
|
|
||||||
ret = ETHASH_IO_MEMO_MISMATCH;
|
ret = ETHASH_IO_MEMO_MISMATCH;
|
||||||
goto set_file;
|
goto set_file;
|
||||||
|
|
||||||
|
17
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.h
generated
vendored
@ -54,6 +54,23 @@ enum ethash_io_rc {
|
|||||||
#define snprintf(...) sprintf_s(__VA_ARGS__)
|
#define snprintf(...) sprintf_s(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a critical error in important parts of ethash. Should mostly help
|
||||||
|
* figure out what kind of problem (I/O, memory e.t.c.) causes a NULL
|
||||||
|
* ethash_full_t
|
||||||
|
*/
|
||||||
|
#ifdef ETHASH_PRINT_CRITICAL_OUTPUT
|
||||||
|
#define ETHASH_CRITICAL(...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \
|
||||||
|
printf("\n"); \
|
||||||
|
fflush(stdout); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define ETHASH_CRITICAL(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares io for ethash
|
* Prepares io for ethash
|
||||||
*
|
*
|
||||||
|
9
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_posix.c
generated
vendored
@ -26,6 +26,8 @@
|
|||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
FILE* ethash_fopen(char const* file_name, char const* mode)
|
FILE* ethash_fopen(char const* file_name, char const* mode)
|
||||||
{
|
{
|
||||||
@ -89,6 +91,13 @@ bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
|
|||||||
static const char dir_suffix[] = ".ethash/";
|
static const char dir_suffix[] = ".ethash/";
|
||||||
strbuf[0] = '\0';
|
strbuf[0] = '\0';
|
||||||
char* home_dir = getenv("HOME");
|
char* home_dir = getenv("HOME");
|
||||||
|
if (!home_dir || strlen(home_dir) == 0)
|
||||||
|
{
|
||||||
|
struct passwd* pwd = getpwuid(getuid());
|
||||||
|
if (pwd)
|
||||||
|
home_dir = pwd->pw_dir;
|
||||||
|
}
|
||||||
|
|
||||||
size_t len = strlen(home_dir);
|
size_t len = strlen(home_dir);
|
||||||
if (!ethash_strncat(strbuf, buffsize, home_dir, len)) {
|
if (!ethash_strncat(strbuf, buffsize, home_dir, len)) {
|
||||||
return false;
|
return false;
|
||||||
|
4
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_win32.c
generated
vendored
@ -87,9 +87,9 @@ bool ethash_file_size(FILE* f, size_t* ret_size)
|
|||||||
|
|
||||||
bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
|
bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
|
||||||
{
|
{
|
||||||
static const char dir_suffix[] = "Appdata\\Ethash\\";
|
static const char dir_suffix[] = "Ethash\\";
|
||||||
strbuf[0] = '\0';
|
strbuf[0] = '\0';
|
||||||
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, (WCHAR*)strbuf))) {
|
if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (CHAR*)strbuf))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ethash_strncat(strbuf, buffsize, "\\", 1)) {
|
if (!ethash_strncat(strbuf, buffsize, "\\", 1)) {
|
||||||
|
7
Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp
generated
vendored
@ -292,12 +292,13 @@ BOOST_AUTO_TEST_CASE(test_ethash_io_memo_file_size_mismatch) {
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_ethash_get_default_dirname) {
|
BOOST_AUTO_TEST_CASE(test_ethash_get_default_dirname) {
|
||||||
char result[256];
|
char result[256];
|
||||||
// this is really not an easy thing to test for in a unit test, so yeah it does look ugly
|
// this is really not an easy thing to test for in a unit test
|
||||||
|
// TODO: Improve this test ...
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
char homedir[256];
|
char homedir[256];
|
||||||
BOOST_REQUIRE(SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, (WCHAR*)homedir)));
|
BOOST_REQUIRE(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, (CHAR*)homedir)));
|
||||||
BOOST_REQUIRE(ethash_get_default_dirname(result, 256));
|
BOOST_REQUIRE(ethash_get_default_dirname(result, 256));
|
||||||
std::string res = std::string(homedir) + std::string("\\Appdata\\Ethash\\");
|
std::string res = std::string(homedir) + std::string("\\AppData\\Local\\Ethash\\");
|
||||||
#else
|
#else
|
||||||
char* homedir = getenv("HOME");
|
char* homedir = getenv("HOME");
|
||||||
BOOST_REQUIRE(ethash_get_default_dirname(result, 256));
|
BOOST_REQUIRE(ethash_get_default_dirname(result, 256));
|
||||||
|
24
Godeps/_workspace/src/github.com/gizak/termui/.gitignore
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
6
Godeps/_workspace/src/github.com/gizak/termui/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- tip
|
||||||
|
|
||||||
|
script: go test -v ./
|
22
Godeps/_workspace/src/github.com/gizak/termui/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Zack Guo
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
159
Godeps/_workspace/src/github.com/gizak/termui/README.md
generated
vendored
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
# termui [](https://travis-ci.org/gizak/termui) [](https://godoc.org/github.com/gizak/termui)
|
||||||
|
|
||||||
|
## Update 23/06/2015
|
||||||
|
Pull requests and master branch are freezing, waiting for merging from `refactoring` branch.
|
||||||
|
|
||||||
|
## Notice
|
||||||
|
termui comes with ABSOLUTELY NO WARRANTY, and there is a breaking change coming up (see refactoring branch) which will change the `Bufferer` interface and many others. These changes reduce calculation overhead and introduce a new drawing buffer with better capacibilities. We will step into the next stage (call it beta) after merging these changes.
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
Go terminal dashboard. Inspired by [blessed-contrib](https://github.com/yaronn/blessed-contrib), but purely in Go.
|
||||||
|
|
||||||
|
Cross-platform, easy to compile, and fully-customizable.
|
||||||
|
|
||||||
|
__Demo:__ (cast under osx 10.10; Terminal.app; Menlo Regular 12pt.)
|
||||||
|
|
||||||
|
<img src="./example/dashboard.gif" alt="demo" width="600">
|
||||||
|
|
||||||
|
__Grid layout:__
|
||||||
|
|
||||||
|
Expressive syntax, using [12 columns grid system](http://www.w3schools.com/bootstrap/bootstrap_grid_system.asp)
|
||||||
|
```go
|
||||||
|
import ui "github.com/gizak/termui"
|
||||||
|
// init and create widgets...
|
||||||
|
|
||||||
|
// build
|
||||||
|
ui.Body.AddRows(
|
||||||
|
ui.NewRow(
|
||||||
|
ui.NewCol(6, 0, widget0),
|
||||||
|
ui.NewCol(6, 0, widget1)),
|
||||||
|
ui.NewRow(
|
||||||
|
ui.NewCol(3, 0, widget2),
|
||||||
|
ui.NewCol(3, 0, widget30, widget31, widget32),
|
||||||
|
ui.NewCol(6, 0, widget4)))
|
||||||
|
|
||||||
|
// calculate layout
|
||||||
|
ui.Body.Align()
|
||||||
|
|
||||||
|
ui.Render(ui.Body)
|
||||||
|
```
|
||||||
|
[demo code:](https://github.com/gizak/termui/blob/master/example/grid.go)
|
||||||
|
|
||||||
|
<img src="./example/grid.gif" alt="grid" width="500">
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
go get github.com/gizak/termui
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Each component's layout is a bit like HTML block (box model), which has border and padding.
|
||||||
|
|
||||||
|
The `Border` property can be chosen to hide or display (with its border label), when it comes to display, the label takes 1 padding space (i.e. in css: `padding: 1;`, innerHeight and innerWidth therefore shrunk by 1).
|
||||||
|
|
||||||
|
`````go
|
||||||
|
import ui "github.com/gizak/termui" // <- ui shortcut, optional
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := ui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer ui.Close()
|
||||||
|
|
||||||
|
p := ui.NewPar(":PRESS q TO QUIT DEMO")
|
||||||
|
p.Height = 3
|
||||||
|
p.Width = 50
|
||||||
|
p.TextFgColor = ui.ColorWhite
|
||||||
|
p.Border.Label = "Text Box"
|
||||||
|
p.Border.FgColor = ui.ColorCyan
|
||||||
|
|
||||||
|
g := ui.NewGauge()
|
||||||
|
g.Percent = 50
|
||||||
|
g.Width = 50
|
||||||
|
g.Height = 3
|
||||||
|
g.Y = 11
|
||||||
|
g.Border.Label = "Gauge"
|
||||||
|
g.BarColor = ui.ColorRed
|
||||||
|
g.Border.FgColor = ui.ColorWhite
|
||||||
|
g.Border.LabelFgColor = ui.ColorCyan
|
||||||
|
|
||||||
|
ui.Render(p, g)
|
||||||
|
|
||||||
|
// event handler...
|
||||||
|
}
|
||||||
|
`````
|
||||||
|
|
||||||
|
Note that components can be overlapped (I'd rather call this a feature...), `Render(rs ...Renderer)` renders its args from left to right (i.e. each component's weight is arising from left to right).
|
||||||
|
|
||||||
|
## Themes
|
||||||
|
|
||||||
|
_All_ colors in _all_ components can be changed at _any_ time, while there provides some predefined color schemes:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// for now there are only two themes: default and helloworld
|
||||||
|
termui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
// create components...
|
||||||
|
```
|
||||||
|
The `default ` theme's settings depend on the user's terminal color scheme, which is saying if your terminal default font color is white and background is white, it will be like:
|
||||||
|
|
||||||
|
<img src="./example/themedefault.png" alt="default" type="image/png" width="600">
|
||||||
|
|
||||||
|
The `helloworld` color scheme drops in some colors!
|
||||||
|
|
||||||
|
<img src="./example/themehelloworld.png" alt="helloworld" type="image/png" width="600">
|
||||||
|
|
||||||
|
## Widgets
|
||||||
|
|
||||||
|
#### Par
|
||||||
|
|
||||||
|
[demo code](https://github.com/gizak/termui/blob/master/example/par.go)
|
||||||
|
|
||||||
|
<img src="./example/par.png" alt="par" type="image/png" width="300">
|
||||||
|
|
||||||
|
#### List
|
||||||
|
[demo code](https://github.com/gizak/termui/blob/master/example/list.go)
|
||||||
|
|
||||||
|
<img src="./example/list.png" alt="list" type="image/png" width="200">
|
||||||
|
|
||||||
|
#### Gauge
|
||||||
|
[demo code](https://github.com/gizak/termui/blob/master/example/gauge.go)
|
||||||
|
|
||||||
|
<img src="./example/gauge.png" alt="gauge" type="image/png" width="350">
|
||||||
|
|
||||||
|
#### Line Chart
|
||||||
|
[demo code](https://github.com/gizak/termui/blob/master/example/linechart.go)
|
||||||
|
|
||||||
|
<img src="./example/linechart.png" alt="linechart" type="image/png" width="450">
|
||||||
|
|
||||||
|
#### Bar Chart
|
||||||
|
[demo code](https://github.com/gizak/termui/blob/master/example/barchart.go)
|
||||||
|
|
||||||
|
<img src="./example/barchart.png" alt="barchart" type="image/png" width="150">
|
||||||
|
|
||||||
|
#### Mult-Bar / Stacked-Bar Chart
|
||||||
|
[demo code](https://github.com/gizak/termui/blob/master/example/mbarchart.go)
|
||||||
|
|
||||||
|
<img src="./example/mbarchart.png" alt="barchart" type="image/png" width="150">
|
||||||
|
|
||||||
|
#### Sparklines
|
||||||
|
[demo code](https://github.com/gizak/termui/blob/master/example/sparklines.go)
|
||||||
|
|
||||||
|
<img src="./example/sparklines.png" alt="sparklines" type="image/png" width="350">
|
||||||
|
|
||||||
|
|
||||||
|
## GoDoc
|
||||||
|
|
||||||
|
[godoc](https://godoc.org/github.com/gizak/termui)
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- [x] Grid layout
|
||||||
|
- [ ] Event system
|
||||||
|
- [ ] Canvas widget
|
||||||
|
- [ ] Refine APIs
|
||||||
|
- [ ] Focusable widgets
|
||||||
|
|
||||||
|
## License
|
||||||
|
This library is under the [MIT License](http://opensource.org/licenses/MIT)
|
135
Godeps/_workspace/src/github.com/gizak/termui/bar.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// BarChart creates multiple bars in a widget:
|
||||||
|
/*
|
||||||
|
bc := termui.NewBarChart()
|
||||||
|
data := []int{3, 2, 5, 3, 9, 5}
|
||||||
|
bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
|
||||||
|
bc.Border.Label = "Bar Chart"
|
||||||
|
bc.Data = data
|
||||||
|
bc.Width = 26
|
||||||
|
bc.Height = 10
|
||||||
|
bc.DataLabels = bclabels
|
||||||
|
bc.TextColor = termui.ColorGreen
|
||||||
|
bc.BarColor = termui.ColorRed
|
||||||
|
bc.NumColor = termui.ColorYellow
|
||||||
|
*/
|
||||||
|
type BarChart struct {
|
||||||
|
Block
|
||||||
|
BarColor Attribute
|
||||||
|
TextColor Attribute
|
||||||
|
NumColor Attribute
|
||||||
|
Data []int
|
||||||
|
DataLabels []string
|
||||||
|
BarWidth int
|
||||||
|
BarGap int
|
||||||
|
labels [][]rune
|
||||||
|
dataNum [][]rune
|
||||||
|
numBar int
|
||||||
|
scale float64
|
||||||
|
max int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBarChart returns a new *BarChart with current theme.
|
||||||
|
func NewBarChart() *BarChart {
|
||||||
|
bc := &BarChart{Block: *NewBlock()}
|
||||||
|
bc.BarColor = theme.BarChartBar
|
||||||
|
bc.NumColor = theme.BarChartNum
|
||||||
|
bc.TextColor = theme.BarChartText
|
||||||
|
bc.BarGap = 1
|
||||||
|
bc.BarWidth = 3
|
||||||
|
return bc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BarChart) layout() {
|
||||||
|
bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth)
|
||||||
|
bc.labels = make([][]rune, bc.numBar)
|
||||||
|
bc.dataNum = make([][]rune, len(bc.Data))
|
||||||
|
|
||||||
|
for i := 0; i < bc.numBar && i < len(bc.DataLabels) && i < len(bc.Data); i++ {
|
||||||
|
bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth)
|
||||||
|
n := bc.Data[i]
|
||||||
|
s := fmt.Sprint(n)
|
||||||
|
bc.dataNum[i] = trimStr2Runes(s, bc.BarWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
//bc.max = bc.Data[0] // what if Data is nil? Sometimes when bar graph is nill it produces panic with panic: runtime error: index out of range
|
||||||
|
// Asign a negative value to get maxvalue auto-populates
|
||||||
|
if bc.max == 0 {
|
||||||
|
bc.max = -1
|
||||||
|
}
|
||||||
|
for i := 0; i < len(bc.Data); i++ {
|
||||||
|
if bc.max < bc.Data[i] {
|
||||||
|
bc.max = bc.Data[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bc.scale = float64(bc.max) / float64(bc.innerHeight-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BarChart) SetMax(max int) {
|
||||||
|
|
||||||
|
if max > 0 {
|
||||||
|
bc.max = max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (bc *BarChart) Buffer() []Point {
|
||||||
|
ps := bc.Block.Buffer()
|
||||||
|
bc.layout()
|
||||||
|
|
||||||
|
for i := 0; i < bc.numBar && i < len(bc.Data) && i < len(bc.DataLabels); i++ {
|
||||||
|
h := int(float64(bc.Data[i]) / bc.scale)
|
||||||
|
oftX := i * (bc.BarWidth + bc.BarGap)
|
||||||
|
// plot bar
|
||||||
|
for j := 0; j < bc.BarWidth; j++ {
|
||||||
|
for k := 0; k < h; k++ {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = ' '
|
||||||
|
p.Bg = bc.BarColor
|
||||||
|
if bc.BarColor == ColorDefault { // when color is default, space char treated as transparent!
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 2 - k
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// plot text
|
||||||
|
for j, k := 0, 0; j < len(bc.labels[i]); j++ {
|
||||||
|
w := charWidth(bc.labels[i][j])
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = bc.labels[i][j]
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
p.Fg = bc.TextColor
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 1
|
||||||
|
p.X = bc.innerX + oftX + k
|
||||||
|
ps = append(ps, p)
|
||||||
|
k += w
|
||||||
|
}
|
||||||
|
// plot num
|
||||||
|
for j := 0; j < len(bc.dataNum[i]); j++ {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = bc.dataNum[i][j]
|
||||||
|
p.Fg = bc.NumColor
|
||||||
|
p.Bg = bc.BarColor
|
||||||
|
if bc.BarColor == ColorDefault { // the same as above
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
if h == 0 {
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
}
|
||||||
|
p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i]))/2 + j
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 2
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bc.Block.chopOverflow(ps)
|
||||||
|
}
|
142
Godeps/_workspace/src/github.com/gizak/termui/block.go
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
// Block is a base struct for all other upper level widgets,
|
||||||
|
// consider it as css: display:block.
|
||||||
|
// Normally you do not need to create it manually.
|
||||||
|
type Block struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
Border labeledBorder
|
||||||
|
IsDisplay bool
|
||||||
|
HasBorder bool
|
||||||
|
BgColor Attribute
|
||||||
|
Width int
|
||||||
|
Height int
|
||||||
|
innerWidth int
|
||||||
|
innerHeight int
|
||||||
|
innerX int
|
||||||
|
innerY int
|
||||||
|
PaddingTop int
|
||||||
|
PaddingBottom int
|
||||||
|
PaddingLeft int
|
||||||
|
PaddingRight int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBlock returns a *Block which inherits styles from current theme.
|
||||||
|
func NewBlock() *Block {
|
||||||
|
d := Block{}
|
||||||
|
d.IsDisplay = true
|
||||||
|
d.HasBorder = theme.HasBorder
|
||||||
|
d.Border.BgColor = theme.BorderBg
|
||||||
|
d.Border.FgColor = theme.BorderFg
|
||||||
|
d.Border.LabelBgColor = theme.BorderLabelTextBg
|
||||||
|
d.Border.LabelFgColor = theme.BorderLabelTextFg
|
||||||
|
d.BgColor = theme.BlockBg
|
||||||
|
d.Width = 2
|
||||||
|
d.Height = 2
|
||||||
|
return &d
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute box model
|
||||||
|
func (d *Block) align() {
|
||||||
|
d.innerWidth = d.Width - d.PaddingLeft - d.PaddingRight
|
||||||
|
d.innerHeight = d.Height - d.PaddingTop - d.PaddingBottom
|
||||||
|
d.innerX = d.X + d.PaddingLeft
|
||||||
|
d.innerY = d.Y + d.PaddingTop
|
||||||
|
|
||||||
|
if d.HasBorder {
|
||||||
|
d.innerHeight -= 2
|
||||||
|
d.innerWidth -= 2
|
||||||
|
d.Border.X = d.X
|
||||||
|
d.Border.Y = d.Y
|
||||||
|
d.Border.Width = d.Width
|
||||||
|
d.Border.Height = d.Height
|
||||||
|
d.innerX++
|
||||||
|
d.innerY++
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.innerHeight < 0 {
|
||||||
|
d.innerHeight = 0
|
||||||
|
}
|
||||||
|
if d.innerWidth < 0 {
|
||||||
|
d.innerWidth = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// InnerBounds returns the internal bounds of the block after aligning and
|
||||||
|
// calculating the padding and border, if any.
|
||||||
|
func (d *Block) InnerBounds() (x, y, width, height int) {
|
||||||
|
d.align()
|
||||||
|
return d.innerX, d.innerY, d.innerWidth, d.innerHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
// Draw background and border (if any).
|
||||||
|
func (d *Block) Buffer() []Point {
|
||||||
|
d.align()
|
||||||
|
|
||||||
|
ps := []Point{}
|
||||||
|
if !d.IsDisplay {
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasBorder {
|
||||||
|
ps = d.Border.Buffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < d.innerWidth; i++ {
|
||||||
|
for j := 0; j < d.innerHeight; j++ {
|
||||||
|
p := Point{}
|
||||||
|
p.X = d.X + 1 + i
|
||||||
|
p.Y = d.Y + 1 + j
|
||||||
|
p.Ch = ' '
|
||||||
|
p.Bg = d.BgColor
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeight implements GridBufferer.
|
||||||
|
// It returns current height of the block.
|
||||||
|
func (d Block) GetHeight() int {
|
||||||
|
return d.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetX implements GridBufferer interface, which sets block's x position.
|
||||||
|
func (d *Block) SetX(x int) {
|
||||||
|
d.X = x
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetY implements GridBufferer interface, it sets y position for block.
|
||||||
|
func (d *Block) SetY(y int) {
|
||||||
|
d.Y = y
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWidth implements GridBuffer interface, it sets block's width.
|
||||||
|
func (d *Block) SetWidth(w int) {
|
||||||
|
d.Width = w
|
||||||
|
}
|
||||||
|
|
||||||
|
// chop the overflow parts
|
||||||
|
func (d *Block) chopOverflow(ps []Point) []Point {
|
||||||
|
nps := make([]Point, 0, len(ps))
|
||||||
|
x := d.X
|
||||||
|
y := d.Y
|
||||||
|
w := d.Width
|
||||||
|
h := d.Height
|
||||||
|
for _, v := range ps {
|
||||||
|
if v.X >= x &&
|
||||||
|
v.X < x+w &&
|
||||||
|
v.Y >= y &&
|
||||||
|
v.Y < y+h {
|
||||||
|
nps = append(nps, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nps
|
||||||
|
}
|
46
Godeps/_workspace/src/github.com/gizak/termui/block_test.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package termui
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestBlock_InnerBounds(t *testing.T) {
|
||||||
|
b := NewBlock()
|
||||||
|
b.X = 10
|
||||||
|
b.Y = 11
|
||||||
|
b.Width = 12
|
||||||
|
b.Height = 13
|
||||||
|
|
||||||
|
assert := func(name string, x, y, w, h int) {
|
||||||
|
t.Log(name)
|
||||||
|
cx, cy, cw, ch := b.InnerBounds()
|
||||||
|
if cx != x {
|
||||||
|
t.Errorf("expected x to be %d but got %d", x, cx)
|
||||||
|
}
|
||||||
|
if cy != y {
|
||||||
|
t.Errorf("expected y to be %d but got %d", y, cy)
|
||||||
|
}
|
||||||
|
if cw != w {
|
||||||
|
t.Errorf("expected width to be %d but got %d", w, cw)
|
||||||
|
}
|
||||||
|
if ch != h {
|
||||||
|
t.Errorf("expected height to be %d but got %d", h, ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.HasBorder = false
|
||||||
|
assert("no border, no padding", 10, 11, 12, 13)
|
||||||
|
|
||||||
|
b.HasBorder = true
|
||||||
|
assert("border, no padding", 11, 12, 10, 11)
|
||||||
|
|
||||||
|
b.PaddingBottom = 2
|
||||||
|
assert("border, 2b padding", 11, 12, 10, 9)
|
||||||
|
|
||||||
|
b.PaddingTop = 3
|
||||||
|
assert("border, 2b 3t padding", 11, 15, 10, 6)
|
||||||
|
|
||||||
|
b.PaddingLeft = 4
|
||||||
|
assert("border, 2b 3t 4l padding", 15, 15, 6, 6)
|
||||||
|
|
||||||
|
b.PaddingRight = 5
|
||||||
|
assert("border, 2b 3t 4l 5r padding", 15, 15, 1, 6)
|
||||||
|
}
|
117
Godeps/_workspace/src/github.com/gizak/termui/box.go
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
type border struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
Width int
|
||||||
|
Height int
|
||||||
|
FgColor Attribute
|
||||||
|
BgColor Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
type hline struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
Length int
|
||||||
|
FgColor Attribute
|
||||||
|
BgColor Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
type vline struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
Length int
|
||||||
|
FgColor Attribute
|
||||||
|
BgColor Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a horizontal line.
|
||||||
|
func (l hline) Buffer() []Point {
|
||||||
|
pts := make([]Point, l.Length)
|
||||||
|
for i := 0; i < l.Length; i++ {
|
||||||
|
pts[i].X = l.X + i
|
||||||
|
pts[i].Y = l.Y
|
||||||
|
pts[i].Ch = HORIZONTAL_LINE
|
||||||
|
pts[i].Bg = l.BgColor
|
||||||
|
pts[i].Fg = l.FgColor
|
||||||
|
}
|
||||||
|
return pts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a vertical line.
|
||||||
|
func (l vline) Buffer() []Point {
|
||||||
|
pts := make([]Point, l.Length)
|
||||||
|
for i := 0; i < l.Length; i++ {
|
||||||
|
pts[i].X = l.X
|
||||||
|
pts[i].Y = l.Y + i
|
||||||
|
pts[i].Ch = VERTICAL_LINE
|
||||||
|
pts[i].Bg = l.BgColor
|
||||||
|
pts[i].Fg = l.FgColor
|
||||||
|
}
|
||||||
|
return pts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a box border.
|
||||||
|
func (b border) Buffer() []Point {
|
||||||
|
if b.Width < 2 || b.Height < 2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
pts := make([]Point, 2*b.Width+2*b.Height-4)
|
||||||
|
|
||||||
|
pts[0].X = b.X
|
||||||
|
pts[0].Y = b.Y
|
||||||
|
pts[0].Fg = b.FgColor
|
||||||
|
pts[0].Bg = b.BgColor
|
||||||
|
pts[0].Ch = TOP_LEFT
|
||||||
|
|
||||||
|
pts[1].X = b.X + b.Width - 1
|
||||||
|
pts[1].Y = b.Y
|
||||||
|
pts[1].Fg = b.FgColor
|
||||||
|
pts[1].Bg = b.BgColor
|
||||||
|
pts[1].Ch = TOP_RIGHT
|
||||||
|
|
||||||
|
pts[2].X = b.X
|
||||||
|
pts[2].Y = b.Y + b.Height - 1
|
||||||
|
pts[2].Fg = b.FgColor
|
||||||
|
pts[2].Bg = b.BgColor
|
||||||
|
pts[2].Ch = BOTTOM_LEFT
|
||||||
|
|
||||||
|
pts[3].X = b.X + b.Width - 1
|
||||||
|
pts[3].Y = b.Y + b.Height - 1
|
||||||
|
pts[3].Fg = b.FgColor
|
||||||
|
pts[3].Bg = b.BgColor
|
||||||
|
pts[3].Ch = BOTTOM_RIGHT
|
||||||
|
|
||||||
|
copy(pts[4:], (hline{b.X + 1, b.Y, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
|
||||||
|
copy(pts[4+b.Width-2:], (hline{b.X + 1, b.Y + b.Height - 1, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
|
||||||
|
copy(pts[4+2*b.Width-4:], (vline{b.X, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
|
||||||
|
copy(pts[4+2*b.Width-4+b.Height-2:], (vline{b.X + b.Width - 1, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
|
||||||
|
|
||||||
|
return pts
|
||||||
|
}
|
||||||
|
|
||||||
|
type labeledBorder struct {
|
||||||
|
border
|
||||||
|
Label string
|
||||||
|
LabelFgColor Attribute
|
||||||
|
LabelBgColor Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a box border with label.
|
||||||
|
func (lb labeledBorder) Buffer() []Point {
|
||||||
|
ps := lb.border.Buffer()
|
||||||
|
maxTxtW := lb.Width - 2
|
||||||
|
rs := trimStr2Runes(lb.Label, maxTxtW)
|
||||||
|
|
||||||
|
for i, j, w := 0, 0, 0; i < len(rs); i++ {
|
||||||
|
w = charWidth(rs[i])
|
||||||
|
ps = append(ps, newPointWithAttrs(rs[i], lb.X+1+j, lb.Y, lb.LabelFgColor, lb.LabelBgColor))
|
||||||
|
j += w
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps
|
||||||
|
}
|
14
Godeps/_workspace/src/github.com/gizak/termui/box_others.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
const TOP_RIGHT = '┐'
|
||||||
|
const VERTICAL_LINE = '│'
|
||||||
|
const HORIZONTAL_LINE = '─'
|
||||||
|
const TOP_LEFT = '┌'
|
||||||
|
const BOTTOM_RIGHT = '┘'
|
||||||
|
const BOTTOM_LEFT = '└'
|
14
Godeps/_workspace/src/github.com/gizak/termui/box_windows.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
const TOP_RIGHT = '+'
|
||||||
|
const VERTICAL_LINE = '|'
|
||||||
|
const HORIZONTAL_LINE = '-'
|
||||||
|
const TOP_LEFT = '+'
|
||||||
|
const BOTTOM_RIGHT = '+'
|
||||||
|
const BOTTOM_LEFT = '+'
|
74
Godeps/_workspace/src/github.com/gizak/termui/canvas.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
/*
|
||||||
|
dots:
|
||||||
|
,___,
|
||||||
|
|1 4|
|
||||||
|
|2 5|
|
||||||
|
|3 6|
|
||||||
|
|7 8|
|
||||||
|
`````
|
||||||
|
*/
|
||||||
|
|
||||||
|
var brailleBase = '\u2800'
|
||||||
|
|
||||||
|
var brailleOftMap = [4][2]rune{
|
||||||
|
{'\u0001', '\u0008'},
|
||||||
|
{'\u0002', '\u0010'},
|
||||||
|
{'\u0004', '\u0020'},
|
||||||
|
{'\u0040', '\u0080'}}
|
||||||
|
|
||||||
|
// Canvas contains drawing map: i,j -> rune
|
||||||
|
type Canvas map[[2]int]rune
|
||||||
|
|
||||||
|
// NewCanvas returns an empty Canvas
|
||||||
|
func NewCanvas() Canvas {
|
||||||
|
return make(map[[2]int]rune)
|
||||||
|
}
|
||||||
|
|
||||||
|
func chOft(x, y int) rune {
|
||||||
|
return brailleOftMap[y%4][x%2]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Canvas) rawCh(x, y int) rune {
|
||||||
|
if ch, ok := c[[2]int{x, y}]; ok {
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
return '\u0000' //brailleOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
// return coordinate in terminal
|
||||||
|
func chPos(x, y int) (int, int) {
|
||||||
|
return y / 4, x / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets a point (x,y) in the virtual coordinate
|
||||||
|
func (c Canvas) Set(x, y int) {
|
||||||
|
i, j := chPos(x, y)
|
||||||
|
ch := c.rawCh(i, j)
|
||||||
|
ch |= chOft(x, y)
|
||||||
|
c[[2]int{i, j}] = ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unset removes point (x,y)
|
||||||
|
func (c Canvas) Unset(x, y int) {
|
||||||
|
i, j := chPos(x, y)
|
||||||
|
ch := c.rawCh(i, j)
|
||||||
|
ch &= ^chOft(x, y)
|
||||||
|
c[[2]int{i, j}] = ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer returns un-styled points
|
||||||
|
func (c Canvas) Buffer() []Point {
|
||||||
|
ps := make([]Point, len(c))
|
||||||
|
i := 0
|
||||||
|
for k, v := range c {
|
||||||
|
ps[i] = newPoint(v+brailleBase, k[0], k[1])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return ps
|
||||||
|
}
|
55
Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCanvasSet(t *testing.T) {
|
||||||
|
c := NewCanvas()
|
||||||
|
c.Set(0, 0)
|
||||||
|
c.Set(0, 1)
|
||||||
|
c.Set(0, 2)
|
||||||
|
c.Set(0, 3)
|
||||||
|
c.Set(1, 3)
|
||||||
|
c.Set(2, 3)
|
||||||
|
c.Set(3, 3)
|
||||||
|
c.Set(4, 3)
|
||||||
|
c.Set(5, 3)
|
||||||
|
spew.Dump(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCanvasUnset(t *testing.T) {
|
||||||
|
c := NewCanvas()
|
||||||
|
c.Set(0, 0)
|
||||||
|
c.Set(0, 1)
|
||||||
|
c.Set(0, 2)
|
||||||
|
c.Unset(0, 2)
|
||||||
|
spew.Dump(c)
|
||||||
|
c.Unset(0, 3)
|
||||||
|
spew.Dump(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCanvasBuffer(t *testing.T) {
|
||||||
|
c := NewCanvas()
|
||||||
|
c.Set(0, 0)
|
||||||
|
c.Set(0, 1)
|
||||||
|
c.Set(0, 2)
|
||||||
|
c.Set(0, 3)
|
||||||
|
c.Set(1, 3)
|
||||||
|
c.Set(2, 3)
|
||||||
|
c.Set(3, 3)
|
||||||
|
c.Set(4, 3)
|
||||||
|
c.Set(5, 3)
|
||||||
|
c.Set(6, 3)
|
||||||
|
c.Set(7, 2)
|
||||||
|
c.Set(8, 1)
|
||||||
|
c.Set(9, 0)
|
||||||
|
bufs := c.Buffer()
|
||||||
|
rs := make([]rune, len(bufs))
|
||||||
|
for i, v := range bufs {
|
||||||
|
rs[i] = v.Ch
|
||||||
|
}
|
||||||
|
spew.Dump(string(rs))
|
||||||
|
}
|
336
Godeps/_workspace/src/github.com/gizak/termui/chart.go
generated
vendored
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
// only 16 possible combinations, why bother
|
||||||
|
var braillePatterns = map[[2]int]rune{
|
||||||
|
[2]int{0, 0}: '⣀',
|
||||||
|
[2]int{0, 1}: '⡠',
|
||||||
|
[2]int{0, 2}: '⡐',
|
||||||
|
[2]int{0, 3}: '⡈',
|
||||||
|
|
||||||
|
[2]int{1, 0}: '⢄',
|
||||||
|
[2]int{1, 1}: '⠤',
|
||||||
|
[2]int{1, 2}: '⠔',
|
||||||
|
[2]int{1, 3}: '⠌',
|
||||||
|
|
||||||
|
[2]int{2, 0}: '⢂',
|
||||||
|
[2]int{2, 1}: '⠢',
|
||||||
|
[2]int{2, 2}: '⠒',
|
||||||
|
[2]int{2, 3}: '⠊',
|
||||||
|
|
||||||
|
[2]int{3, 0}: '⢁',
|
||||||
|
[2]int{3, 1}: '⠡',
|
||||||
|
[2]int{3, 2}: '⠑',
|
||||||
|
[2]int{3, 3}: '⠉',
|
||||||
|
}
|
||||||
|
|
||||||
|
var lSingleBraille = [4]rune{'\u2840', '⠄', '⠂', '⠁'}
|
||||||
|
var rSingleBraille = [4]rune{'\u2880', '⠠', '⠐', '⠈'}
|
||||||
|
|
||||||
|
// LineChart has two modes: braille(default) and dot. Using braille gives 2x capicity as dot mode,
|
||||||
|
// because one braille char can represent two data points.
|
||||||
|
/*
|
||||||
|
lc := termui.NewLineChart()
|
||||||
|
lc.Border.Label = "braille-mode Line Chart"
|
||||||
|
lc.Data = [1.2, 1.3, 1.5, 1.7, 1.5, 1.6, 1.8, 2.0]
|
||||||
|
lc.Width = 50
|
||||||
|
lc.Height = 12
|
||||||
|
lc.AxesColor = termui.ColorWhite
|
||||||
|
lc.LineColor = termui.ColorGreen | termui.AttrBold
|
||||||
|
// termui.Render(lc)...
|
||||||
|
*/
|
||||||
|
type LineChart struct {
|
||||||
|
Block
|
||||||
|
Data []float64
|
||||||
|
DataLabels []string // if unset, the data indices will be used
|
||||||
|
Mode string // braille | dot
|
||||||
|
DotStyle rune
|
||||||
|
LineColor Attribute
|
||||||
|
scale float64 // data span per cell on y-axis
|
||||||
|
AxesColor Attribute
|
||||||
|
drawingX int
|
||||||
|
drawingY int
|
||||||
|
axisYHeight int
|
||||||
|
axisXWidth int
|
||||||
|
axisYLebelGap int
|
||||||
|
axisXLebelGap int
|
||||||
|
topValue float64
|
||||||
|
bottomValue float64
|
||||||
|
labelX [][]rune
|
||||||
|
labelY [][]rune
|
||||||
|
labelYSpace int
|
||||||
|
maxY float64
|
||||||
|
minY float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLineChart returns a new LineChart with current theme.
|
||||||
|
func NewLineChart() *LineChart {
|
||||||
|
lc := &LineChart{Block: *NewBlock()}
|
||||||
|
lc.AxesColor = theme.LineChartAxes
|
||||||
|
lc.LineColor = theme.LineChartLine
|
||||||
|
lc.Mode = "braille"
|
||||||
|
lc.DotStyle = '•'
|
||||||
|
lc.axisXLebelGap = 2
|
||||||
|
lc.axisYLebelGap = 1
|
||||||
|
lc.bottomValue = math.Inf(1)
|
||||||
|
lc.topValue = math.Inf(-1)
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
// one cell contains two data points
|
||||||
|
// so the capicity is 2x as dot-mode
|
||||||
|
func (lc *LineChart) renderBraille() []Point {
|
||||||
|
ps := []Point{}
|
||||||
|
|
||||||
|
// return: b -> which cell should the point be in
|
||||||
|
// m -> in the cell, divided into 4 equal height levels, which subcell?
|
||||||
|
getPos := func(d float64) (b, m int) {
|
||||||
|
cnt4 := int((d-lc.bottomValue)/(lc.scale/4) + 0.5)
|
||||||
|
b = cnt4 / 4
|
||||||
|
m = cnt4 % 4
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// plot points
|
||||||
|
for i := 0; 2*i+1 < len(lc.Data) && i < lc.axisXWidth; i++ {
|
||||||
|
b0, m0 := getPos(lc.Data[2*i])
|
||||||
|
b1, m1 := getPos(lc.Data[2*i+1])
|
||||||
|
|
||||||
|
if b0 == b1 {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = braillePatterns[[2]int{m0, m1}]
|
||||||
|
p.Bg = lc.BgColor
|
||||||
|
p.Fg = lc.LineColor
|
||||||
|
p.Y = lc.innerY + lc.innerHeight - 3 - b0
|
||||||
|
p.X = lc.innerX + lc.labelYSpace + 1 + i
|
||||||
|
ps = append(ps, p)
|
||||||
|
} else {
|
||||||
|
p0 := newPointWithAttrs(lSingleBraille[m0],
|
||||||
|
lc.innerX+lc.labelYSpace+1+i,
|
||||||
|
lc.innerY+lc.innerHeight-3-b0,
|
||||||
|
lc.LineColor,
|
||||||
|
lc.BgColor)
|
||||||
|
p1 := newPointWithAttrs(rSingleBraille[m1],
|
||||||
|
lc.innerX+lc.labelYSpace+1+i,
|
||||||
|
lc.innerY+lc.innerHeight-3-b1,
|
||||||
|
lc.LineColor,
|
||||||
|
lc.BgColor)
|
||||||
|
ps = append(ps, p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LineChart) renderDot() []Point {
|
||||||
|
ps := []Point{}
|
||||||
|
for i := 0; i < len(lc.Data) && i < lc.axisXWidth; i++ {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = lc.DotStyle
|
||||||
|
p.Fg = lc.LineColor
|
||||||
|
p.Bg = lc.BgColor
|
||||||
|
p.X = lc.innerX + lc.labelYSpace + 1 + i
|
||||||
|
p.Y = lc.innerY + lc.innerHeight - 3 - int((lc.Data[i]-lc.bottomValue)/lc.scale+0.5)
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LineChart) calcLabelX() {
|
||||||
|
lc.labelX = [][]rune{}
|
||||||
|
|
||||||
|
for i, l := 0, 0; i < len(lc.DataLabels) && l < lc.axisXWidth; i++ {
|
||||||
|
if lc.Mode == "dot" {
|
||||||
|
if l >= len(lc.DataLabels) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
s := str2runes(lc.DataLabels[l])
|
||||||
|
w := strWidth(lc.DataLabels[l])
|
||||||
|
if l+w <= lc.axisXWidth {
|
||||||
|
lc.labelX = append(lc.labelX, s)
|
||||||
|
}
|
||||||
|
l += w + lc.axisXLebelGap
|
||||||
|
} else { // braille
|
||||||
|
if 2*l >= len(lc.DataLabels) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
s := str2runes(lc.DataLabels[2*l])
|
||||||
|
w := strWidth(lc.DataLabels[2*l])
|
||||||
|
if l+w <= lc.axisXWidth {
|
||||||
|
lc.labelX = append(lc.labelX, s)
|
||||||
|
}
|
||||||
|
l += w + lc.axisXLebelGap
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func shortenFloatVal(x float64) string {
|
||||||
|
s := fmt.Sprintf("%.2f", x)
|
||||||
|
if len(s)-3 > 3 {
|
||||||
|
s = fmt.Sprintf("%.2e", x)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x < 0 {
|
||||||
|
s = fmt.Sprintf("%.2f", x)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LineChart) calcLabelY() {
|
||||||
|
span := lc.topValue - lc.bottomValue
|
||||||
|
lc.scale = span / float64(lc.axisYHeight)
|
||||||
|
|
||||||
|
n := (1 + lc.axisYHeight) / (lc.axisYLebelGap + 1)
|
||||||
|
lc.labelY = make([][]rune, n)
|
||||||
|
maxLen := 0
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
s := str2runes(shortenFloatVal(lc.bottomValue + float64(i)*span/float64(n)))
|
||||||
|
if len(s) > maxLen {
|
||||||
|
maxLen = len(s)
|
||||||
|
}
|
||||||
|
lc.labelY[i] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
lc.labelYSpace = maxLen
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LineChart) calcLayout() {
|
||||||
|
// set datalabels if it is not provided
|
||||||
|
if lc.DataLabels == nil || len(lc.DataLabels) == 0 {
|
||||||
|
lc.DataLabels = make([]string, len(lc.Data))
|
||||||
|
for i := range lc.Data {
|
||||||
|
lc.DataLabels[i] = fmt.Sprint(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lazy increase, to avoid y shaking frequently
|
||||||
|
// update bound Y when drawing is gonna overflow
|
||||||
|
lc.minY = lc.Data[0]
|
||||||
|
lc.maxY = lc.Data[0]
|
||||||
|
|
||||||
|
// valid visible range
|
||||||
|
vrange := lc.innerWidth
|
||||||
|
if lc.Mode == "braille" {
|
||||||
|
vrange = 2 * lc.innerWidth
|
||||||
|
}
|
||||||
|
if vrange > len(lc.Data) {
|
||||||
|
vrange = len(lc.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range lc.Data[:vrange] {
|
||||||
|
if v > lc.maxY {
|
||||||
|
lc.maxY = v
|
||||||
|
}
|
||||||
|
if v < lc.minY {
|
||||||
|
lc.minY = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span := lc.maxY - lc.minY
|
||||||
|
|
||||||
|
if lc.minY < lc.bottomValue {
|
||||||
|
lc.bottomValue = lc.minY - 0.2*span
|
||||||
|
}
|
||||||
|
|
||||||
|
if lc.maxY > lc.topValue {
|
||||||
|
lc.topValue = lc.maxY + 0.2*span
|
||||||
|
}
|
||||||
|
|
||||||
|
lc.axisYHeight = lc.innerHeight - 2
|
||||||
|
lc.calcLabelY()
|
||||||
|
|
||||||
|
lc.axisXWidth = lc.innerWidth - 1 - lc.labelYSpace
|
||||||
|
lc.calcLabelX()
|
||||||
|
|
||||||
|
lc.drawingX = lc.innerX + 1 + lc.labelYSpace
|
||||||
|
lc.drawingY = lc.innerY
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LineChart) plotAxes() []Point {
|
||||||
|
origY := lc.innerY + lc.innerHeight - 2
|
||||||
|
origX := lc.innerX + lc.labelYSpace
|
||||||
|
|
||||||
|
ps := []Point{newPointWithAttrs(ORIGIN, origX, origY, lc.AxesColor, lc.BgColor)}
|
||||||
|
|
||||||
|
for x := origX + 1; x < origX+lc.axisXWidth; x++ {
|
||||||
|
p := Point{}
|
||||||
|
p.X = x
|
||||||
|
p.Y = origY
|
||||||
|
p.Bg = lc.BgColor
|
||||||
|
p.Fg = lc.AxesColor
|
||||||
|
p.Ch = HDASH
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
for dy := 1; dy <= lc.axisYHeight; dy++ {
|
||||||
|
p := Point{}
|
||||||
|
p.X = origX
|
||||||
|
p.Y = origY - dy
|
||||||
|
p.Bg = lc.BgColor
|
||||||
|
p.Fg = lc.AxesColor
|
||||||
|
p.Ch = VDASH
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// x label
|
||||||
|
oft := 0
|
||||||
|
for _, rs := range lc.labelX {
|
||||||
|
if oft+len(rs) > lc.axisXWidth {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for j, r := range rs {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = r
|
||||||
|
p.Fg = lc.AxesColor
|
||||||
|
p.Bg = lc.BgColor
|
||||||
|
p.X = origX + oft + j
|
||||||
|
p.Y = lc.innerY + lc.innerHeight - 1
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
oft += len(rs) + lc.axisXLebelGap
|
||||||
|
}
|
||||||
|
|
||||||
|
// y labels
|
||||||
|
for i, rs := range lc.labelY {
|
||||||
|
for j, r := range rs {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = r
|
||||||
|
p.Fg = lc.AxesColor
|
||||||
|
p.Bg = lc.BgColor
|
||||||
|
p.X = lc.innerX + j
|
||||||
|
p.Y = origY - i*(lc.axisYLebelGap+1)
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (lc *LineChart) Buffer() []Point {
|
||||||
|
ps := lc.Block.Buffer()
|
||||||
|
if lc.Data == nil || len(lc.Data) == 0 {
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
lc.calcLayout()
|
||||||
|
ps = append(ps, lc.plotAxes()...)
|
||||||
|
|
||||||
|
if lc.Mode == "dot" {
|
||||||
|
ps = append(ps, lc.renderDot()...)
|
||||||
|
} else {
|
||||||
|
ps = append(ps, lc.renderBraille()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lc.Block.chopOverflow(ps)
|
||||||
|
}
|
11
Godeps/_workspace/src/github.com/gizak/termui/chart_others.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
const VDASH = '┊'
|
||||||
|
const HDASH = '┈'
|
||||||
|
const ORIGIN = '└'
|
11
Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
const VDASH = '|'
|
||||||
|
const HDASH = '-'
|
||||||
|
const ORIGIN = '+'
|
27
Godeps/_workspace/src/github.com/gizak/termui/doc.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package termui is a library designed for creating command line UI. For more info, goto http://github.com/gizak/termui
|
||||||
|
|
||||||
|
A simplest example:
|
||||||
|
package main
|
||||||
|
|
||||||
|
import ui "github.com/gizak/termui"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err:=ui.Init(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer ui.Close()
|
||||||
|
|
||||||
|
g := ui.NewGauge()
|
||||||
|
g.Percent = 50
|
||||||
|
g.Width = 50
|
||||||
|
g.Border.Label = "Gauge"
|
||||||
|
|
||||||
|
ui.Render(g)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
package termui
|
219
Godeps/_workspace/src/github.com/gizak/termui/events.go
generated
vendored
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// Portions of this file uses [termbox-go](https://github.com/nsf/termbox-go/blob/54b74d087b7c397c402d0e3b66d2ccb6eaf5c2b4/api_common.go)
|
||||||
|
// by [authors](https://github.com/nsf/termbox-go/blob/master/AUTHORS)
|
||||||
|
// under [license](https://github.com/nsf/termbox-go/blob/master/LICENSE)
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import "github.com/nsf/termbox-go"
|
||||||
|
|
||||||
|
/***********************************termbox-go**************************************/
|
||||||
|
|
||||||
|
type (
|
||||||
|
EventType uint8
|
||||||
|
Modifier uint8
|
||||||
|
Key uint16
|
||||||
|
)
|
||||||
|
|
||||||
|
// This type represents a termbox event. The 'Mod', 'Key' and 'Ch' fields are
|
||||||
|
// valid if 'Type' is EventKey. The 'Width' and 'Height' fields are valid if
|
||||||
|
// 'Type' is EventResize. The 'Err' field is valid if 'Type' is EventError.
|
||||||
|
type Event struct {
|
||||||
|
Type EventType // one of Event* constants
|
||||||
|
Mod Modifier // one of Mod* constants or 0
|
||||||
|
Key Key // one of Key* constants, invalid if 'Ch' is not 0
|
||||||
|
Ch rune // a unicode character
|
||||||
|
Width int // width of the screen
|
||||||
|
Height int // height of the screen
|
||||||
|
Err error // error in case if input failed
|
||||||
|
MouseX int // x coord of mouse
|
||||||
|
MouseY int // y coord of mouse
|
||||||
|
N int // number of bytes written when getting a raw event
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
KeyF1 Key = 0xFFFF - iota
|
||||||
|
KeyF2
|
||||||
|
KeyF3
|
||||||
|
KeyF4
|
||||||
|
KeyF5
|
||||||
|
KeyF6
|
||||||
|
KeyF7
|
||||||
|
KeyF8
|
||||||
|
KeyF9
|
||||||
|
KeyF10
|
||||||
|
KeyF11
|
||||||
|
KeyF12
|
||||||
|
KeyInsert
|
||||||
|
KeyDelete
|
||||||
|
KeyHome
|
||||||
|
KeyEnd
|
||||||
|
KeyPgup
|
||||||
|
KeyPgdn
|
||||||
|
KeyArrowUp
|
||||||
|
KeyArrowDown
|
||||||
|
KeyArrowLeft
|
||||||
|
KeyArrowRight
|
||||||
|
key_min // see terminfo
|
||||||
|
MouseLeft
|
||||||
|
MouseMiddle
|
||||||
|
MouseRight
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
KeyCtrlTilde Key = 0x00
|
||||||
|
KeyCtrl2 Key = 0x00
|
||||||
|
KeyCtrlSpace Key = 0x00
|
||||||
|
KeyCtrlA Key = 0x01
|
||||||
|
KeyCtrlB Key = 0x02
|
||||||
|
KeyCtrlC Key = 0x03
|
||||||
|
KeyCtrlD Key = 0x04
|
||||||
|
KeyCtrlE Key = 0x05
|
||||||
|
KeyCtrlF Key = 0x06
|
||||||
|
KeyCtrlG Key = 0x07
|
||||||
|
KeyBackspace Key = 0x08
|
||||||
|
KeyCtrlH Key = 0x08
|
||||||
|
KeyTab Key = 0x09
|
||||||
|
KeyCtrlI Key = 0x09
|
||||||
|
KeyCtrlJ Key = 0x0A
|
||||||
|
KeyCtrlK Key = 0x0B
|
||||||
|
KeyCtrlL Key = 0x0C
|
||||||
|
KeyEnter Key = 0x0D
|
||||||
|
KeyCtrlM Key = 0x0D
|
||||||
|
KeyCtrlN Key = 0x0E
|
||||||
|
KeyCtrlO Key = 0x0F
|
||||||
|
KeyCtrlP Key = 0x10
|
||||||
|
KeyCtrlQ Key = 0x11
|
||||||
|
KeyCtrlR Key = 0x12
|
||||||
|
KeyCtrlS Key = 0x13
|
||||||
|
KeyCtrlT Key = 0x14
|
||||||
|
KeyCtrlU Key = 0x15
|
||||||
|
KeyCtrlV Key = 0x16
|
||||||
|
KeyCtrlW Key = 0x17
|
||||||
|
KeyCtrlX Key = 0x18
|
||||||
|
KeyCtrlY Key = 0x19
|
||||||
|
KeyCtrlZ Key = 0x1A
|
||||||
|
KeyEsc Key = 0x1B
|
||||||
|
KeyCtrlLsqBracket Key = 0x1B
|
||||||
|
KeyCtrl3 Key = 0x1B
|
||||||
|
KeyCtrl4 Key = 0x1C
|
||||||
|
KeyCtrlBackslash Key = 0x1C
|
||||||
|
KeyCtrl5 Key = 0x1D
|
||||||
|
KeyCtrlRsqBracket Key = 0x1D
|
||||||
|
KeyCtrl6 Key = 0x1E
|
||||||
|
KeyCtrl7 Key = 0x1F
|
||||||
|
KeyCtrlSlash Key = 0x1F
|
||||||
|
KeyCtrlUnderscore Key = 0x1F
|
||||||
|
KeySpace Key = 0x20
|
||||||
|
KeyBackspace2 Key = 0x7F
|
||||||
|
KeyCtrl8 Key = 0x7F
|
||||||
|
)
|
||||||
|
|
||||||
|
// Alt modifier constant, see Event.Mod field and SetInputMode function.
|
||||||
|
const (
|
||||||
|
ModAlt Modifier = 0x01
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event type. See Event.Type field.
|
||||||
|
const (
|
||||||
|
EventKey EventType = iota
|
||||||
|
EventResize
|
||||||
|
EventMouse
|
||||||
|
EventError
|
||||||
|
EventInterrupt
|
||||||
|
EventRaw
|
||||||
|
EventNone
|
||||||
|
)
|
||||||
|
|
||||||
|
/**************************************end**************************************/
|
||||||
|
|
||||||
|
// convert termbox.Event to termui.Event
|
||||||
|
func uiEvt(e termbox.Event) Event {
|
||||||
|
event := Event{}
|
||||||
|
event.Type = EventType(e.Type)
|
||||||
|
event.Mod = Modifier(e.Mod)
|
||||||
|
event.Key = Key(e.Key)
|
||||||
|
event.Ch = e.Ch
|
||||||
|
event.Width = e.Width
|
||||||
|
event.Height = e.Height
|
||||||
|
event.Err = e.Err
|
||||||
|
event.MouseX = e.MouseX
|
||||||
|
event.MouseY = e.MouseY
|
||||||
|
event.N = e.N
|
||||||
|
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
var evtChs = make([]chan Event, 0)
|
||||||
|
|
||||||
|
// EventCh returns an output-only event channel.
|
||||||
|
// This function can be called many times (multiplexer).
|
||||||
|
func EventCh() <-chan Event {
|
||||||
|
out := make(chan Event)
|
||||||
|
evtChs = append(evtChs, out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn on event listener
|
||||||
|
func evtListen() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
e := termbox.PollEvent()
|
||||||
|
// dispatch
|
||||||
|
for _, c := range evtChs {
|
||||||
|
go func(ch chan Event) {
|
||||||
|
ch <- uiEvt(e)
|
||||||
|
}(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// EventHandlers is a handler sequence
|
||||||
|
var EventHandlers []func(Event)
|
||||||
|
|
||||||
|
var signalQuit = make(chan bool)
|
||||||
|
|
||||||
|
// Quit sends quit signal to terminate termui
|
||||||
|
func Quit() {
|
||||||
|
signalQuit <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait listening to signalQuit, block operation.
|
||||||
|
func Wait() {
|
||||||
|
<-signalQuit
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegEvtHandler register function into TSEventHandler sequence.
|
||||||
|
func RegEvtHandler(fn func(Event)) {
|
||||||
|
EventHandlers = append(EventHandlers, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventLoop handles all events and
|
||||||
|
// redirects every event to callbacks in EventHandlers
|
||||||
|
func EventLoop() {
|
||||||
|
evt := make(chan termbox.Event)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
evt <- termbox.PollEvent()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case c := <-signalQuit:
|
||||||
|
defer func() { signalQuit <- c }()
|
||||||
|
return
|
||||||
|
case e := <-evt:
|
||||||
|
for _, fn := range EventHandlers {
|
||||||
|
fn(uiEvt(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
28
Godeps/_workspace/src/github.com/gizak/termui/events_test.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// Portions of this file uses [termbox-go](https://github.com/nsf/termbox-go/blob/54b74d087b7c397c402d0e3b66d2ccb6eaf5c2b4/api_common.go)
|
||||||
|
// by [authors](https://github.com/nsf/termbox-go/blob/master/AUTHORS)
|
||||||
|
// under [license](https://github.com/nsf/termbox-go/blob/master/LICENSE)
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
termbox "github.com/nsf/termbox-go"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type boxEvent termbox.Event
|
||||||
|
|
||||||
|
func TestUiEvt(t *testing.T) {
|
||||||
|
err := errors.New("This is a mock error")
|
||||||
|
event := boxEvent{3, 5, 2, 'H', 200, 500, err, 50, 30, 2}
|
||||||
|
expetced := Event{3, 5, 2, 'H', 200, 500, err, 50, 30, 2}
|
||||||
|
|
||||||
|
// We need to do that ugly casting so that vet does not complain
|
||||||
|
assert.Equal(t, uiEvt(termbox.Event(event)), expetced)
|
||||||
|
}
|
35
Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/gizak/termui"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := termui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer termui.Close()
|
||||||
|
|
||||||
|
termui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
bc := termui.NewBarChart()
|
||||||
|
data := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
|
||||||
|
bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
|
||||||
|
bc.Border.Label = "Bar Chart"
|
||||||
|
bc.Data = data
|
||||||
|
bc.Width = 26
|
||||||
|
bc.Height = 10
|
||||||
|
bc.DataLabels = bclabels
|
||||||
|
bc.TextColor = termui.ColorGreen
|
||||||
|
bc.BarColor = termui.ColorRed
|
||||||
|
bc.NumColor = termui.ColorYellow
|
||||||
|
|
||||||
|
termui.Render(bc)
|
||||||
|
|
||||||
|
<-termui.EventCh()
|
||||||
|
}
|
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png
generated
vendored
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.gif
generated
vendored
Normal file
After Width: | Height: | Size: 443 KiB |
148
Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.go
generated
vendored
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import ui "github.com/gizak/termui"
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := ui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer ui.Close()
|
||||||
|
|
||||||
|
p := ui.NewPar(":PRESS q TO QUIT DEMO")
|
||||||
|
p.Height = 3
|
||||||
|
p.Width = 50
|
||||||
|
p.TextFgColor = ui.ColorWhite
|
||||||
|
p.Border.Label = "Text Box"
|
||||||
|
p.Border.FgColor = ui.ColorCyan
|
||||||
|
|
||||||
|
strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"}
|
||||||
|
list := ui.NewList()
|
||||||
|
list.Items = strs
|
||||||
|
list.ItemFgColor = ui.ColorYellow
|
||||||
|
list.Border.Label = "List"
|
||||||
|
list.Height = 7
|
||||||
|
list.Width = 25
|
||||||
|
list.Y = 4
|
||||||
|
|
||||||
|
g := ui.NewGauge()
|
||||||
|
g.Percent = 50
|
||||||
|
g.Width = 50
|
||||||
|
g.Height = 3
|
||||||
|
g.Y = 11
|
||||||
|
g.Border.Label = "Gauge"
|
||||||
|
g.BarColor = ui.ColorRed
|
||||||
|
g.Border.FgColor = ui.ColorWhite
|
||||||
|
g.Border.LabelFgColor = ui.ColorCyan
|
||||||
|
|
||||||
|
spark := ui.Sparkline{}
|
||||||
|
spark.Height = 1
|
||||||
|
spark.Title = "srv 0:"
|
||||||
|
spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
|
||||||
|
spark.Data = spdata
|
||||||
|
spark.LineColor = ui.ColorCyan
|
||||||
|
spark.TitleColor = ui.ColorWhite
|
||||||
|
|
||||||
|
spark1 := ui.Sparkline{}
|
||||||
|
spark1.Height = 1
|
||||||
|
spark1.Title = "srv 1:"
|
||||||
|
spark1.Data = spdata
|
||||||
|
spark1.TitleColor = ui.ColorWhite
|
||||||
|
spark1.LineColor = ui.ColorRed
|
||||||
|
|
||||||
|
sp := ui.NewSparklines(spark, spark1)
|
||||||
|
sp.Width = 25
|
||||||
|
sp.Height = 7
|
||||||
|
sp.Border.Label = "Sparkline"
|
||||||
|
sp.Y = 4
|
||||||
|
sp.X = 25
|
||||||
|
|
||||||
|
sinps := (func() []float64 {
|
||||||
|
n := 220
|
||||||
|
ps := make([]float64, n)
|
||||||
|
for i := range ps {
|
||||||
|
ps[i] = 1 + math.Sin(float64(i)/5)
|
||||||
|
}
|
||||||
|
return ps
|
||||||
|
})()
|
||||||
|
|
||||||
|
lc := ui.NewLineChart()
|
||||||
|
lc.Border.Label = "dot-mode Line Chart"
|
||||||
|
lc.Data = sinps
|
||||||
|
lc.Width = 50
|
||||||
|
lc.Height = 11
|
||||||
|
lc.X = 0
|
||||||
|
lc.Y = 14
|
||||||
|
lc.AxesColor = ui.ColorWhite
|
||||||
|
lc.LineColor = ui.ColorRed | ui.AttrBold
|
||||||
|
lc.Mode = "dot"
|
||||||
|
|
||||||
|
bc := ui.NewBarChart()
|
||||||
|
bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
|
||||||
|
bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
|
||||||
|
bc.Border.Label = "Bar Chart"
|
||||||
|
bc.Width = 26
|
||||||
|
bc.Height = 10
|
||||||
|
bc.X = 51
|
||||||
|
bc.Y = 0
|
||||||
|
bc.DataLabels = bclabels
|
||||||
|
bc.BarColor = ui.ColorGreen
|
||||||
|
bc.NumColor = ui.ColorBlack
|
||||||
|
|
||||||
|
lc1 := ui.NewLineChart()
|
||||||
|
lc1.Border.Label = "braille-mode Line Chart"
|
||||||
|
lc1.Data = sinps
|
||||||
|
lc1.Width = 26
|
||||||
|
lc1.Height = 11
|
||||||
|
lc1.X = 51
|
||||||
|
lc1.Y = 14
|
||||||
|
lc1.AxesColor = ui.ColorWhite
|
||||||
|
lc1.LineColor = ui.ColorYellow | ui.AttrBold
|
||||||
|
|
||||||
|
p1 := ui.NewPar("Hey!\nI am a borderless block!")
|
||||||
|
p1.HasBorder = false
|
||||||
|
p1.Width = 26
|
||||||
|
p1.Height = 2
|
||||||
|
p1.TextFgColor = ui.ColorMagenta
|
||||||
|
p1.X = 52
|
||||||
|
p1.Y = 11
|
||||||
|
|
||||||
|
draw := func(t int) {
|
||||||
|
g.Percent = t % 101
|
||||||
|
list.Items = strs[t%9:]
|
||||||
|
sp.Lines[0].Data = spdata[:30+t%50]
|
||||||
|
sp.Lines[1].Data = spdata[:35+t%50]
|
||||||
|
lc.Data = sinps[t/2:]
|
||||||
|
lc1.Data = sinps[2*t:]
|
||||||
|
bc.Data = bcdata[t/2%10:]
|
||||||
|
ui.Render(p, list, g, sp, lc, bc, lc1, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
evt := ui.EventCh()
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case e := <-evt:
|
||||||
|
if e.Type == ui.EventKey && e.Ch == 'q' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
draw(i)
|
||||||
|
i++
|
||||||
|
if i == 102 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second / 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/gizak/termui"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := termui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer termui.Close()
|
||||||
|
|
||||||
|
termui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
g0 := termui.NewGauge()
|
||||||
|
g0.Percent = 40
|
||||||
|
g0.Width = 50
|
||||||
|
g0.Height = 3
|
||||||
|
g0.Border.Label = "Slim Gauge"
|
||||||
|
g0.BarColor = termui.ColorRed
|
||||||
|
g0.Border.FgColor = termui.ColorWhite
|
||||||
|
g0.Border.LabelFgColor = termui.ColorCyan
|
||||||
|
|
||||||
|
g2 := termui.NewGauge()
|
||||||
|
g2.Percent = 60
|
||||||
|
g2.Width = 50
|
||||||
|
g2.Height = 3
|
||||||
|
g2.PercentColor = termui.ColorBlue
|
||||||
|
g2.Y = 3
|
||||||
|
g2.Border.Label = "Slim Gauge"
|
||||||
|
g2.BarColor = termui.ColorYellow
|
||||||
|
g2.Border.FgColor = termui.ColorWhite
|
||||||
|
|
||||||
|
g1 := termui.NewGauge()
|
||||||
|
g1.Percent = 30
|
||||||
|
g1.Width = 50
|
||||||
|
g1.Height = 5
|
||||||
|
g1.Y = 6
|
||||||
|
g1.Border.Label = "Big Gauge"
|
||||||
|
g1.PercentColor = termui.ColorYellow
|
||||||
|
g1.BarColor = termui.ColorGreen
|
||||||
|
g1.Border.FgColor = termui.ColorWhite
|
||||||
|
g1.Border.LabelFgColor = termui.ColorMagenta
|
||||||
|
|
||||||
|
g3 := termui.NewGauge()
|
||||||
|
g3.Percent = 50
|
||||||
|
g3.Width = 50
|
||||||
|
g3.Height = 3
|
||||||
|
g3.Y = 11
|
||||||
|
g3.Border.Label = "Gauge with custom label"
|
||||||
|
g3.Label = "{{percent}}% (100MBs free)"
|
||||||
|
g3.LabelAlign = termui.AlignRight
|
||||||
|
|
||||||
|
termui.Render(g0, g1, g2, g3)
|
||||||
|
|
||||||
|
<-termui.EventCh()
|
||||||
|
}
|
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png
generated
vendored
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif
generated
vendored
Normal file
After Width: | Height: | Size: 782 KiB |
134
Godeps/_workspace/src/github.com/gizak/termui/example/grid.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import ui "github.com/gizak/termui"
|
||||||
|
import "math"
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := ui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer ui.Close()
|
||||||
|
|
||||||
|
sinps := (func() []float64 {
|
||||||
|
n := 400
|
||||||
|
ps := make([]float64, n)
|
||||||
|
for i := range ps {
|
||||||
|
ps[i] = 1 + math.Sin(float64(i)/5)
|
||||||
|
}
|
||||||
|
return ps
|
||||||
|
})()
|
||||||
|
sinpsint := (func() []int {
|
||||||
|
ps := make([]int, len(sinps))
|
||||||
|
for i, v := range sinps {
|
||||||
|
ps[i] = int(100*v + 10)
|
||||||
|
}
|
||||||
|
return ps
|
||||||
|
})()
|
||||||
|
|
||||||
|
ui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
spark := ui.Sparkline{}
|
||||||
|
spark.Height = 8
|
||||||
|
spdata := sinpsint
|
||||||
|
spark.Data = spdata[:100]
|
||||||
|
spark.LineColor = ui.ColorCyan
|
||||||
|
spark.TitleColor = ui.ColorWhite
|
||||||
|
|
||||||
|
sp := ui.NewSparklines(spark)
|
||||||
|
sp.Height = 11
|
||||||
|
sp.Border.Label = "Sparkline"
|
||||||
|
|
||||||
|
lc := ui.NewLineChart()
|
||||||
|
lc.Border.Label = "braille-mode Line Chart"
|
||||||
|
lc.Data = sinps
|
||||||
|
lc.Height = 11
|
||||||
|
lc.AxesColor = ui.ColorWhite
|
||||||
|
lc.LineColor = ui.ColorYellow | ui.AttrBold
|
||||||
|
|
||||||
|
gs := make([]*ui.Gauge, 3)
|
||||||
|
for i := range gs {
|
||||||
|
gs[i] = ui.NewGauge()
|
||||||
|
gs[i].Height = 2
|
||||||
|
gs[i].HasBorder = false
|
||||||
|
gs[i].Percent = i * 10
|
||||||
|
gs[i].PaddingBottom = 1
|
||||||
|
gs[i].BarColor = ui.ColorRed
|
||||||
|
}
|
||||||
|
|
||||||
|
ls := ui.NewList()
|
||||||
|
ls.HasBorder = false
|
||||||
|
ls.Items = []string{
|
||||||
|
"[1] Downloading File 1",
|
||||||
|
"", // == \newline
|
||||||
|
"[2] Downloading File 2",
|
||||||
|
"",
|
||||||
|
"[3] Uploading File 3",
|
||||||
|
}
|
||||||
|
ls.Height = 5
|
||||||
|
|
||||||
|
par := ui.NewPar("<> This row has 3 columns\n<- Widgets can be stacked up like left side\n<- Stacked widgets are treated as a single widget")
|
||||||
|
par.Height = 5
|
||||||
|
par.Border.Label = "Demonstration"
|
||||||
|
|
||||||
|
// build layout
|
||||||
|
ui.Body.AddRows(
|
||||||
|
ui.NewRow(
|
||||||
|
ui.NewCol(6, 0, sp),
|
||||||
|
ui.NewCol(6, 0, lc)),
|
||||||
|
ui.NewRow(
|
||||||
|
ui.NewCol(3, 0, ls),
|
||||||
|
ui.NewCol(3, 0, gs[0], gs[1], gs[2]),
|
||||||
|
ui.NewCol(6, 0, par)))
|
||||||
|
|
||||||
|
// calculate layout
|
||||||
|
ui.Body.Align()
|
||||||
|
|
||||||
|
done := make(chan bool)
|
||||||
|
redraw := make(chan bool)
|
||||||
|
|
||||||
|
update := func() {
|
||||||
|
for i := 0; i < 103; i++ {
|
||||||
|
for _, g := range gs {
|
||||||
|
g.Percent = (g.Percent + 3) % 100
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.Lines[0].Data = spdata[:100+i]
|
||||||
|
lc.Data = sinps[2*i:]
|
||||||
|
|
||||||
|
time.Sleep(time.Second / 2)
|
||||||
|
redraw <- true
|
||||||
|
}
|
||||||
|
done <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
evt := ui.EventCh()
|
||||||
|
|
||||||
|
ui.Render(ui.Body)
|
||||||
|
go update()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case e := <-evt:
|
||||||
|
if e.Type == ui.EventKey && e.Ch == 'q' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if e.Type == ui.EventResize {
|
||||||
|
ui.Body.Width = ui.TermWidth()
|
||||||
|
ui.Body.Align()
|
||||||
|
go func() { redraw <- true }()
|
||||||
|
}
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
case <-redraw:
|
||||||
|
ui.Render(ui.Body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/gizak/termui"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := termui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer termui.Close()
|
||||||
|
|
||||||
|
termui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
sinps := (func() []float64 {
|
||||||
|
n := 220
|
||||||
|
ps := make([]float64, n)
|
||||||
|
for i := range ps {
|
||||||
|
ps[i] = 1 + math.Sin(float64(i)/5)
|
||||||
|
}
|
||||||
|
return ps
|
||||||
|
})()
|
||||||
|
|
||||||
|
lc0 := termui.NewLineChart()
|
||||||
|
lc0.Border.Label = "braille-mode Line Chart"
|
||||||
|
lc0.Data = sinps
|
||||||
|
lc0.Width = 50
|
||||||
|
lc0.Height = 12
|
||||||
|
lc0.X = 0
|
||||||
|
lc0.Y = 0
|
||||||
|
lc0.AxesColor = termui.ColorWhite
|
||||||
|
lc0.LineColor = termui.ColorGreen | termui.AttrBold
|
||||||
|
|
||||||
|
lc1 := termui.NewLineChart()
|
||||||
|
lc1.Border.Label = "dot-mode Line Chart"
|
||||||
|
lc1.Mode = "dot"
|
||||||
|
lc1.Data = sinps
|
||||||
|
lc1.Width = 26
|
||||||
|
lc1.Height = 12
|
||||||
|
lc1.X = 51
|
||||||
|
lc1.DotStyle = '+'
|
||||||
|
lc1.AxesColor = termui.ColorWhite
|
||||||
|
lc1.LineColor = termui.ColorYellow | termui.AttrBold
|
||||||
|
|
||||||
|
lc2 := termui.NewLineChart()
|
||||||
|
lc2.Border.Label = "dot-mode Line Chart"
|
||||||
|
lc2.Mode = "dot"
|
||||||
|
lc2.Data = sinps[4:]
|
||||||
|
lc2.Width = 77
|
||||||
|
lc2.Height = 16
|
||||||
|
lc2.X = 0
|
||||||
|
lc2.Y = 12
|
||||||
|
lc2.AxesColor = termui.ColorWhite
|
||||||
|
lc2.LineColor = termui.ColorCyan | termui.AttrBold
|
||||||
|
|
||||||
|
termui.Render(lc0, lc1, lc2)
|
||||||
|
|
||||||
|
<-termui.EventCh()
|
||||||
|
}
|
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png
generated
vendored
Normal file
After Width: | Height: | Size: 136 KiB |
41
Godeps/_workspace/src/github.com/gizak/termui/example/list.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/gizak/termui"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := termui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer termui.Close()
|
||||||
|
|
||||||
|
termui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
strs := []string{
|
||||||
|
"[0] github.com/gizak/termui",
|
||||||
|
"[1] 你好,世界",
|
||||||
|
"[2] こんにちは世界",
|
||||||
|
"[3] keyboard.go",
|
||||||
|
"[4] output.go",
|
||||||
|
"[5] random_out.go",
|
||||||
|
"[6] dashboard.go",
|
||||||
|
"[7] nsf/termbox-go"}
|
||||||
|
|
||||||
|
ls := termui.NewList()
|
||||||
|
ls.Items = strs
|
||||||
|
ls.ItemFgColor = termui.ColorYellow
|
||||||
|
ls.Border.Label = "List"
|
||||||
|
ls.Height = 7
|
||||||
|
ls.Width = 25
|
||||||
|
ls.Y = 0
|
||||||
|
|
||||||
|
termui.Render(ls)
|
||||||
|
|
||||||
|
<-termui.EventCh()
|
||||||
|
}
|
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/list.png
generated
vendored
Normal file
After Width: | Height: | Size: 36 KiB |
50
Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/gizak/termui"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := termui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer termui.Close()
|
||||||
|
|
||||||
|
termui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
bc := termui.NewMBarChart()
|
||||||
|
math := []int{90, 85, 90, 80}
|
||||||
|
english := []int{70, 85, 75, 60}
|
||||||
|
science := []int{75, 60, 80, 85}
|
||||||
|
compsci := []int{100, 100, 100, 100}
|
||||||
|
bc.Data[0] = math
|
||||||
|
bc.Data[1] = english
|
||||||
|
bc.Data[2] = science
|
||||||
|
bc.Data[3] = compsci
|
||||||
|
studentsName := []string{"Ken", "Rob", "Dennis", "Linus"}
|
||||||
|
bc.Border.Label = "Student's Marks X-Axis=Name Y-Axis=Marks[Math,English,Science,ComputerScience] in %"
|
||||||
|
bc.Width = 100
|
||||||
|
bc.Height = 50
|
||||||
|
bc.Y = 10
|
||||||
|
bc.BarWidth = 10
|
||||||
|
bc.DataLabels = studentsName
|
||||||
|
bc.ShowScale = true //Show y_axis scale value (min and max)
|
||||||
|
bc.SetMax(400)
|
||||||
|
|
||||||
|
bc.TextColor = termui.ColorGreen //this is color for label (x-axis)
|
||||||
|
bc.BarColor[3] = termui.ColorGreen //BarColor for computerscience
|
||||||
|
bc.BarColor[1] = termui.ColorYellow //Bar Color for english
|
||||||
|
bc.NumColor[3] = termui.ColorRed // Num color for computerscience
|
||||||
|
bc.NumColor[1] = termui.ColorRed // num color for english
|
||||||
|
|
||||||
|
//Other colors are automatically populated, btw All the students seems do well in computerscience. :p
|
||||||
|
|
||||||
|
termui.Render(bc)
|
||||||
|
|
||||||
|
<-termui.EventCh()
|
||||||
|
}
|
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png
generated
vendored
Normal file
After Width: | Height: | Size: 20 KiB |
48
Godeps/_workspace/src/github.com/gizak/termui/example/par.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/gizak/termui"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := termui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer termui.Close()
|
||||||
|
|
||||||
|
termui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
par0 := termui.NewPar("Borderless Text")
|
||||||
|
par0.Height = 1
|
||||||
|
par0.Width = 20
|
||||||
|
par0.Y = 1
|
||||||
|
par0.HasBorder = false
|
||||||
|
|
||||||
|
par1 := termui.NewPar("你好,世界。")
|
||||||
|
par1.Height = 3
|
||||||
|
par1.Width = 17
|
||||||
|
par1.X = 20
|
||||||
|
par1.Border.Label = "标签"
|
||||||
|
|
||||||
|
par2 := termui.NewPar("Simple text\nwith label. It can be multilined with \\n or break automatically")
|
||||||
|
par2.Height = 5
|
||||||
|
par2.Width = 37
|
||||||
|
par2.Y = 4
|
||||||
|
par2.Border.Label = "Multiline"
|
||||||
|
par2.Border.FgColor = termui.ColorYellow
|
||||||
|
|
||||||
|
par3 := termui.NewPar("Long text with label and it is auto trimmed.")
|
||||||
|
par3.Height = 3
|
||||||
|
par3.Width = 37
|
||||||
|
par3.Y = 9
|
||||||
|
par3.Border.Label = "Auto Trim"
|
||||||
|
|
||||||
|
termui.Render(par0, par1, par2, par3)
|
||||||
|
|
||||||
|
<-termui.EventCh()
|
||||||
|
}
|
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/par.png
generated
vendored
Normal file
After Width: | Height: | Size: 64 KiB |
65
Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/gizak/termui"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := termui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer termui.Close()
|
||||||
|
|
||||||
|
termui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
|
||||||
|
spl0 := termui.NewSparkline()
|
||||||
|
spl0.Data = data[3:]
|
||||||
|
spl0.Title = "Sparkline 0"
|
||||||
|
spl0.LineColor = termui.ColorGreen
|
||||||
|
|
||||||
|
// single
|
||||||
|
spls0 := termui.NewSparklines(spl0)
|
||||||
|
spls0.Height = 2
|
||||||
|
spls0.Width = 20
|
||||||
|
spls0.HasBorder = false
|
||||||
|
|
||||||
|
spl1 := termui.NewSparkline()
|
||||||
|
spl1.Data = data
|
||||||
|
spl1.Title = "Sparkline 1"
|
||||||
|
spl1.LineColor = termui.ColorRed
|
||||||
|
|
||||||
|
spl2 := termui.NewSparkline()
|
||||||
|
spl2.Data = data[5:]
|
||||||
|
spl2.Title = "Sparkline 2"
|
||||||
|
spl2.LineColor = termui.ColorMagenta
|
||||||
|
|
||||||
|
// group
|
||||||
|
spls1 := termui.NewSparklines(spl0, spl1, spl2)
|
||||||
|
spls1.Height = 8
|
||||||
|
spls1.Width = 20
|
||||||
|
spls1.Y = 3
|
||||||
|
spls1.Border.Label = "Group Sparklines"
|
||||||
|
|
||||||
|
spl3 := termui.NewSparkline()
|
||||||
|
spl3.Data = data
|
||||||
|
spl3.Title = "Enlarged Sparkline"
|
||||||
|
spl3.Height = 8
|
||||||
|
spl3.LineColor = termui.ColorYellow
|
||||||
|
|
||||||
|
spls2 := termui.NewSparklines(spl3)
|
||||||
|
spls2.Height = 11
|
||||||
|
spls2.Width = 30
|
||||||
|
spls2.Border.FgColor = termui.ColorCyan
|
||||||
|
spls2.X = 21
|
||||||
|
spls2.Border.Label = "Tweeked Sparkline"
|
||||||
|
|
||||||
|
termui.Render(spls0, spls1, spls2)
|
||||||
|
|
||||||
|
<-termui.EventCh()
|
||||||
|
}
|
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png
generated
vendored
Normal file
After Width: | Height: | Size: 42 KiB |
143
Godeps/_workspace/src/github.com/gizak/termui/example/theme.go
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import ui "github.com/gizak/termui"
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := ui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer ui.Close()
|
||||||
|
|
||||||
|
ui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
p := ui.NewPar(":PRESS q TO QUIT DEMO")
|
||||||
|
p.Height = 3
|
||||||
|
p.Width = 50
|
||||||
|
p.Border.Label = "Text Box"
|
||||||
|
|
||||||
|
strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"}
|
||||||
|
list := ui.NewList()
|
||||||
|
list.Items = strs
|
||||||
|
list.Border.Label = "List"
|
||||||
|
list.Height = 7
|
||||||
|
list.Width = 25
|
||||||
|
list.Y = 4
|
||||||
|
|
||||||
|
g := ui.NewGauge()
|
||||||
|
g.Percent = 50
|
||||||
|
g.Width = 50
|
||||||
|
g.Height = 3
|
||||||
|
g.Y = 11
|
||||||
|
g.Border.Label = "Gauge"
|
||||||
|
|
||||||
|
spark := ui.NewSparkline()
|
||||||
|
spark.Title = "srv 0:"
|
||||||
|
spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
|
||||||
|
spark.Data = spdata
|
||||||
|
|
||||||
|
spark1 := ui.NewSparkline()
|
||||||
|
spark1.Title = "srv 1:"
|
||||||
|
spark1.Data = spdata
|
||||||
|
|
||||||
|
sp := ui.NewSparklines(spark, spark1)
|
||||||
|
sp.Width = 25
|
||||||
|
sp.Height = 7
|
||||||
|
sp.Border.Label = "Sparkline"
|
||||||
|
sp.Y = 4
|
||||||
|
sp.X = 25
|
||||||
|
|
||||||
|
lc := ui.NewLineChart()
|
||||||
|
sinps := (func() []float64 {
|
||||||
|
n := 100
|
||||||
|
ps := make([]float64, n)
|
||||||
|
for i := range ps {
|
||||||
|
ps[i] = 1 + math.Sin(float64(i)/4)
|
||||||
|
}
|
||||||
|
return ps
|
||||||
|
})()
|
||||||
|
|
||||||
|
lc.Border.Label = "Line Chart"
|
||||||
|
lc.Data = sinps
|
||||||
|
lc.Width = 50
|
||||||
|
lc.Height = 11
|
||||||
|
lc.X = 0
|
||||||
|
lc.Y = 14
|
||||||
|
lc.Mode = "dot"
|
||||||
|
|
||||||
|
bc := ui.NewBarChart()
|
||||||
|
bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
|
||||||
|
bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
|
||||||
|
bc.Border.Label = "Bar Chart"
|
||||||
|
bc.Width = 26
|
||||||
|
bc.Height = 10
|
||||||
|
bc.X = 51
|
||||||
|
bc.Y = 0
|
||||||
|
bc.DataLabels = bclabels
|
||||||
|
|
||||||
|
lc1 := ui.NewLineChart()
|
||||||
|
lc1.Border.Label = "Line Chart"
|
||||||
|
rndwalk := (func() []float64 {
|
||||||
|
n := 150
|
||||||
|
d := make([]float64, n)
|
||||||
|
for i := 1; i < n; i++ {
|
||||||
|
if i < 20 {
|
||||||
|
d[i] = d[i-1] + 0.01
|
||||||
|
}
|
||||||
|
if i > 20 {
|
||||||
|
d[i] = d[i-1] - 0.05
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
})()
|
||||||
|
lc1.Data = rndwalk
|
||||||
|
lc1.Width = 26
|
||||||
|
lc1.Height = 11
|
||||||
|
lc1.X = 51
|
||||||
|
lc1.Y = 14
|
||||||
|
|
||||||
|
p1 := ui.NewPar("Hey!\nI am a borderless block!")
|
||||||
|
p1.HasBorder = false
|
||||||
|
p1.Width = 26
|
||||||
|
p1.Height = 2
|
||||||
|
p1.X = 52
|
||||||
|
p1.Y = 11
|
||||||
|
|
||||||
|
draw := func(t int) {
|
||||||
|
g.Percent = t % 101
|
||||||
|
list.Items = strs[t%9:]
|
||||||
|
sp.Lines[0].Data = spdata[t%10:]
|
||||||
|
sp.Lines[1].Data = spdata[t/2%10:]
|
||||||
|
lc.Data = sinps[t/2:]
|
||||||
|
lc1.Data = rndwalk[t:]
|
||||||
|
bc.Data = bcdata[t/2%10:]
|
||||||
|
ui.Render(p, list, g, sp, lc, bc, lc1, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
evt := ui.EventCh()
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case e := <-evt:
|
||||||
|
if e.Type == ui.EventKey && e.Ch == 'q' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
draw(i)
|
||||||
|
i++
|
||||||
|
if i == 102 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second / 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png
generated
vendored
Normal file
After Width: | Height: | Size: 103 KiB |
BIN
Godeps/_workspace/src/github.com/gizak/termui/example/themehelloworld.png
generated
vendored
Normal file
After Width: | Height: | Size: 88 KiB |
113
Godeps/_workspace/src/github.com/gizak/termui/gauge.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Gauge is a progress bar like widget.
|
||||||
|
// A simple example:
|
||||||
|
/*
|
||||||
|
g := termui.NewGauge()
|
||||||
|
g.Percent = 40
|
||||||
|
g.Width = 50
|
||||||
|
g.Height = 3
|
||||||
|
g.Border.Label = "Slim Gauge"
|
||||||
|
g.BarColor = termui.ColorRed
|
||||||
|
g.PercentColor = termui.ColorBlue
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Align is the position of the gauge's label.
|
||||||
|
type Align int
|
||||||
|
|
||||||
|
// All supported positions.
|
||||||
|
const (
|
||||||
|
AlignLeft Align = iota
|
||||||
|
AlignCenter
|
||||||
|
AlignRight
|
||||||
|
)
|
||||||
|
|
||||||
|
type Gauge struct {
|
||||||
|
Block
|
||||||
|
Percent int
|
||||||
|
BarColor Attribute
|
||||||
|
PercentColor Attribute
|
||||||
|
Label string
|
||||||
|
LabelAlign Align
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGauge return a new gauge with current theme.
|
||||||
|
func NewGauge() *Gauge {
|
||||||
|
g := &Gauge{
|
||||||
|
Block: *NewBlock(),
|
||||||
|
PercentColor: theme.GaugePercent,
|
||||||
|
BarColor: theme.GaugeBar,
|
||||||
|
Label: "{{percent}}%",
|
||||||
|
LabelAlign: AlignCenter,
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Width = 12
|
||||||
|
g.Height = 5
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (g *Gauge) Buffer() []Point {
|
||||||
|
ps := g.Block.Buffer()
|
||||||
|
|
||||||
|
// plot bar
|
||||||
|
w := g.Percent * g.innerWidth / 100
|
||||||
|
for i := 0; i < g.innerHeight; i++ {
|
||||||
|
for j := 0; j < w; j++ {
|
||||||
|
p := Point{}
|
||||||
|
p.X = g.innerX + j
|
||||||
|
p.Y = g.innerY + i
|
||||||
|
p.Ch = ' '
|
||||||
|
p.Bg = g.BarColor
|
||||||
|
if p.Bg == ColorDefault {
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// plot percentage
|
||||||
|
s := strings.Replace(g.Label, "{{percent}}", strconv.Itoa(g.Percent), -1)
|
||||||
|
pry := g.innerY + g.innerHeight/2
|
||||||
|
rs := str2runes(s)
|
||||||
|
var pos int
|
||||||
|
switch g.LabelAlign {
|
||||||
|
case AlignLeft:
|
||||||
|
pos = 0
|
||||||
|
|
||||||
|
case AlignCenter:
|
||||||
|
pos = (g.innerWidth - strWidth(s)) / 2
|
||||||
|
|
||||||
|
case AlignRight:
|
||||||
|
pos = g.innerWidth - strWidth(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range rs {
|
||||||
|
p := Point{}
|
||||||
|
p.X = 1 + pos + i
|
||||||
|
p.Y = pry
|
||||||
|
p.Ch = v
|
||||||
|
p.Fg = g.PercentColor
|
||||||
|
if w+g.innerX > pos+i {
|
||||||
|
p.Bg = g.BarColor
|
||||||
|
if p.Bg == ColorDefault {
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
p.Bg = g.Block.BgColor
|
||||||
|
}
|
||||||
|
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
return g.Block.chopOverflow(ps)
|
||||||
|
}
|
279
Godeps/_workspace/src/github.com/gizak/termui/grid.go
generated
vendored
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
// GridBufferer introduces a Bufferer that can be manipulated by Grid.
|
||||||
|
type GridBufferer interface {
|
||||||
|
Bufferer
|
||||||
|
GetHeight() int
|
||||||
|
SetWidth(int)
|
||||||
|
SetX(int)
|
||||||
|
SetY(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Row builds a layout tree
|
||||||
|
type Row struct {
|
||||||
|
Cols []*Row //children
|
||||||
|
Widget GridBufferer // root
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
Width int
|
||||||
|
Height int
|
||||||
|
Span int
|
||||||
|
Offset int
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate and set the underlying layout tree's x, y, height and width.
|
||||||
|
func (r *Row) calcLayout() {
|
||||||
|
r.assignWidth(r.Width)
|
||||||
|
r.Height = r.solveHeight()
|
||||||
|
r.assignX(r.X)
|
||||||
|
r.assignY(r.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell if the node is leaf in the tree.
|
||||||
|
func (r *Row) isLeaf() bool {
|
||||||
|
return r.Cols == nil || len(r.Cols) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Row) isRenderableLeaf() bool {
|
||||||
|
return r.isLeaf() && r.Widget != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign widgets' (and their parent rows') width recursively.
|
||||||
|
func (r *Row) assignWidth(w int) {
|
||||||
|
r.SetWidth(w)
|
||||||
|
|
||||||
|
accW := 0 // acc span and offset
|
||||||
|
calcW := make([]int, len(r.Cols)) // calculated width
|
||||||
|
calcOftX := make([]int, len(r.Cols)) // computated start position of x
|
||||||
|
|
||||||
|
for i, c := range r.Cols {
|
||||||
|
accW += c.Span + c.Offset
|
||||||
|
cw := int(float64(c.Span*r.Width) / 12.0)
|
||||||
|
|
||||||
|
if i >= 1 {
|
||||||
|
calcOftX[i] = calcOftX[i-1] +
|
||||||
|
calcW[i-1] +
|
||||||
|
int(float64(r.Cols[i-1].Offset*r.Width)/12.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// use up the space if it is the last col
|
||||||
|
if i == len(r.Cols)-1 && accW == 12 {
|
||||||
|
cw = r.Width - calcOftX[i]
|
||||||
|
}
|
||||||
|
calcW[i] = cw
|
||||||
|
r.Cols[i].assignWidth(cw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom up calc and set rows' (and their widgets') height,
|
||||||
|
// return r's total height.
|
||||||
|
func (r *Row) solveHeight() int {
|
||||||
|
if r.isRenderableLeaf() {
|
||||||
|
r.Height = r.Widget.GetHeight()
|
||||||
|
return r.Widget.GetHeight()
|
||||||
|
}
|
||||||
|
|
||||||
|
maxh := 0
|
||||||
|
if !r.isLeaf() {
|
||||||
|
for _, c := range r.Cols {
|
||||||
|
nh := c.solveHeight()
|
||||||
|
// when embed rows in Cols, row widgets stack up
|
||||||
|
if r.Widget != nil {
|
||||||
|
nh += r.Widget.GetHeight()
|
||||||
|
}
|
||||||
|
if nh > maxh {
|
||||||
|
maxh = nh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Height = maxh
|
||||||
|
return maxh
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursively assign x position for r tree.
|
||||||
|
func (r *Row) assignX(x int) {
|
||||||
|
r.SetX(x)
|
||||||
|
|
||||||
|
if !r.isLeaf() {
|
||||||
|
acc := 0
|
||||||
|
for i, c := range r.Cols {
|
||||||
|
if c.Offset != 0 {
|
||||||
|
acc += int(float64(c.Offset*r.Width) / 12.0)
|
||||||
|
}
|
||||||
|
r.Cols[i].assignX(x + acc)
|
||||||
|
acc += c.Width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursively assign y position to r.
|
||||||
|
func (r *Row) assignY(y int) {
|
||||||
|
r.SetY(y)
|
||||||
|
|
||||||
|
if r.isLeaf() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range r.Cols {
|
||||||
|
acc := 0
|
||||||
|
if r.Widget != nil {
|
||||||
|
acc = r.Widget.GetHeight()
|
||||||
|
}
|
||||||
|
r.Cols[i].assignY(y + acc)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeight implements GridBufferer interface.
|
||||||
|
func (r Row) GetHeight() int {
|
||||||
|
return r.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetX implements GridBufferer interface.
|
||||||
|
func (r *Row) SetX(x int) {
|
||||||
|
r.X = x
|
||||||
|
if r.Widget != nil {
|
||||||
|
r.Widget.SetX(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetY implements GridBufferer interface.
|
||||||
|
func (r *Row) SetY(y int) {
|
||||||
|
r.Y = y
|
||||||
|
if r.Widget != nil {
|
||||||
|
r.Widget.SetY(y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWidth implements GridBufferer interface.
|
||||||
|
func (r *Row) SetWidth(w int) {
|
||||||
|
r.Width = w
|
||||||
|
if r.Widget != nil {
|
||||||
|
r.Widget.SetWidth(w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface,
|
||||||
|
// recursively merge all widgets buffer
|
||||||
|
func (r *Row) Buffer() []Point {
|
||||||
|
merged := []Point{}
|
||||||
|
|
||||||
|
if r.isRenderableLeaf() {
|
||||||
|
return r.Widget.Buffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// for those are not leaves but have a renderable widget
|
||||||
|
if r.Widget != nil {
|
||||||
|
merged = append(merged, r.Widget.Buffer()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect buffer from children
|
||||||
|
if !r.isLeaf() {
|
||||||
|
for _, c := range r.Cols {
|
||||||
|
merged = append(merged, c.Buffer()...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grid implements 12 columns system.
|
||||||
|
// A simple example:
|
||||||
|
/*
|
||||||
|
import ui "github.com/gizak/termui"
|
||||||
|
// init and create widgets...
|
||||||
|
|
||||||
|
// build
|
||||||
|
ui.Body.AddRows(
|
||||||
|
ui.NewRow(
|
||||||
|
ui.NewCol(6, 0, widget0),
|
||||||
|
ui.NewCol(6, 0, widget1)),
|
||||||
|
ui.NewRow(
|
||||||
|
ui.NewCol(3, 0, widget2),
|
||||||
|
ui.NewCol(3, 0, widget30, widget31, widget32),
|
||||||
|
ui.NewCol(6, 0, widget4)))
|
||||||
|
|
||||||
|
// calculate layout
|
||||||
|
ui.Body.Align()
|
||||||
|
|
||||||
|
ui.Render(ui.Body)
|
||||||
|
*/
|
||||||
|
type Grid struct {
|
||||||
|
Rows []*Row
|
||||||
|
Width int
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
BgColor Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGrid returns *Grid with given rows.
|
||||||
|
func NewGrid(rows ...*Row) *Grid {
|
||||||
|
return &Grid{Rows: rows}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRows appends given rows to Grid.
|
||||||
|
func (g *Grid) AddRows(rs ...*Row) {
|
||||||
|
g.Rows = append(g.Rows, rs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRow creates a new row out of given columns.
|
||||||
|
func NewRow(cols ...*Row) *Row {
|
||||||
|
rs := &Row{Span: 12, Cols: cols}
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCol accepts: widgets are LayoutBufferer or widgets is A NewRow.
|
||||||
|
// Note that if multiple widgets are provided, they will stack up in the col.
|
||||||
|
func NewCol(span, offset int, widgets ...GridBufferer) *Row {
|
||||||
|
r := &Row{Span: span, Offset: offset}
|
||||||
|
|
||||||
|
if widgets != nil && len(widgets) == 1 {
|
||||||
|
wgt := widgets[0]
|
||||||
|
nw, isRow := wgt.(*Row)
|
||||||
|
if isRow {
|
||||||
|
r.Cols = nw.Cols
|
||||||
|
} else {
|
||||||
|
r.Widget = wgt
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Cols = []*Row{}
|
||||||
|
ir := r
|
||||||
|
for _, w := range widgets {
|
||||||
|
nr := &Row{Span: 12, Widget: w}
|
||||||
|
ir.Cols = []*Row{nr}
|
||||||
|
ir = nr
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align calculate each rows' layout.
|
||||||
|
func (g *Grid) Align() {
|
||||||
|
h := 0
|
||||||
|
for _, r := range g.Rows {
|
||||||
|
r.SetWidth(g.Width)
|
||||||
|
r.SetX(g.X)
|
||||||
|
r.SetY(g.Y + h)
|
||||||
|
r.calcLayout()
|
||||||
|
h += r.GetHeight()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implments Bufferer interface.
|
||||||
|
func (g Grid) Buffer() []Point {
|
||||||
|
ps := []Point{}
|
||||||
|
for _, r := range g.Rows {
|
||||||
|
ps = append(ps, r.Buffer()...)
|
||||||
|
}
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Body corresponds to the entire terminal display region.
|
||||||
|
var Body *Grid
|
98
Godeps/_workspace/src/github.com/gizak/termui/grid_test.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
var r *Row
|
||||||
|
|
||||||
|
func TestRowWidth(t *testing.T) {
|
||||||
|
p0 := NewPar("p0")
|
||||||
|
p0.Height = 1
|
||||||
|
p1 := NewPar("p1")
|
||||||
|
p1.Height = 1
|
||||||
|
p2 := NewPar("p2")
|
||||||
|
p2.Height = 1
|
||||||
|
p3 := NewPar("p3")
|
||||||
|
p3.Height = 1
|
||||||
|
|
||||||
|
/* test against tree:
|
||||||
|
|
||||||
|
r
|
||||||
|
/ \
|
||||||
|
0:w 1
|
||||||
|
/ \
|
||||||
|
10:w 11
|
||||||
|
/
|
||||||
|
110:w
|
||||||
|
/
|
||||||
|
1100:w
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
r = &row{
|
||||||
|
Span: 12,
|
||||||
|
Cols: []*row{
|
||||||
|
&row{Widget: p0, Span: 6},
|
||||||
|
&row{
|
||||||
|
Span: 6,
|
||||||
|
Cols: []*row{
|
||||||
|
&row{Widget: p1, Span: 6},
|
||||||
|
&row{
|
||||||
|
Span: 6,
|
||||||
|
Cols: []*row{
|
||||||
|
&row{
|
||||||
|
Span: 12,
|
||||||
|
Widget: p2,
|
||||||
|
Cols: []*row{
|
||||||
|
&row{Span: 12, Widget: p3}}}}}}}}}
|
||||||
|
*/
|
||||||
|
|
||||||
|
r = NewRow(
|
||||||
|
NewCol(6, 0, p0),
|
||||||
|
NewCol(6, 0,
|
||||||
|
NewRow(
|
||||||
|
NewCol(6, 0, p1),
|
||||||
|
NewCol(6, 0, p2, p3))))
|
||||||
|
|
||||||
|
r.assignWidth(100)
|
||||||
|
if r.Width != 100 ||
|
||||||
|
(r.Cols[0].Width) != 50 ||
|
||||||
|
(r.Cols[1].Width) != 50 ||
|
||||||
|
(r.Cols[1].Cols[0].Width) != 25 ||
|
||||||
|
(r.Cols[1].Cols[1].Width) != 25 ||
|
||||||
|
(r.Cols[1].Cols[1].Cols[0].Width) != 25 ||
|
||||||
|
(r.Cols[1].Cols[1].Cols[0].Cols[0].Width) != 25 {
|
||||||
|
t.Error("assignWidth fails")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRowHeight(t *testing.T) {
|
||||||
|
spew.Dump()
|
||||||
|
|
||||||
|
if (r.solveHeight()) != 2 ||
|
||||||
|
(r.Cols[1].Cols[1].Height) != 2 ||
|
||||||
|
(r.Cols[1].Cols[1].Cols[0].Height) != 2 ||
|
||||||
|
(r.Cols[1].Cols[0].Height) != 1 {
|
||||||
|
t.Error("solveHeight fails")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAssignXY(t *testing.T) {
|
||||||
|
r.assignX(0)
|
||||||
|
r.assignY(0)
|
||||||
|
if (r.Cols[0].X) != 0 ||
|
||||||
|
(r.Cols[1].Cols[0].X) != 50 ||
|
||||||
|
(r.Cols[1].Cols[1].X) != 75 ||
|
||||||
|
(r.Cols[1].Cols[1].Cols[0].X) != 75 ||
|
||||||
|
(r.Cols[1].Cols[0].Y) != 0 ||
|
||||||
|
(r.Cols[1].Cols[1].Cols[0].Y) != 0 ||
|
||||||
|
(r.Cols[1].Cols[1].Cols[0].Cols[0].Y) != 1 {
|
||||||
|
t.Error("assignXY fails")
|
||||||
|
}
|
||||||
|
}
|
66
Godeps/_workspace/src/github.com/gizak/termui/helper.go
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import tm "github.com/nsf/termbox-go"
|
||||||
|
import rw "github.com/mattn/go-runewidth"
|
||||||
|
|
||||||
|
/* ---------------Port from termbox-go --------------------- */
|
||||||
|
|
||||||
|
// Attribute is printable cell's color and style.
|
||||||
|
type Attribute uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
ColorDefault Attribute = iota
|
||||||
|
ColorBlack
|
||||||
|
ColorRed
|
||||||
|
ColorGreen
|
||||||
|
ColorYellow
|
||||||
|
ColorBlue
|
||||||
|
ColorMagenta
|
||||||
|
ColorCyan
|
||||||
|
ColorWhite
|
||||||
|
)
|
||||||
|
|
||||||
|
const NumberofColors = 8 //Have a constant that defines number of colors
|
||||||
|
const (
|
||||||
|
AttrBold Attribute = 1 << (iota + 9)
|
||||||
|
AttrUnderline
|
||||||
|
AttrReverse
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dot = "…"
|
||||||
|
dotw = rw.StringWidth(dot)
|
||||||
|
)
|
||||||
|
|
||||||
|
/* ----------------------- End ----------------------------- */
|
||||||
|
|
||||||
|
func toTmAttr(x Attribute) tm.Attribute {
|
||||||
|
return tm.Attribute(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func str2runes(s string) []rune {
|
||||||
|
return []rune(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func trimStr2Runes(s string, w int) []rune {
|
||||||
|
if w <= 0 {
|
||||||
|
return []rune{}
|
||||||
|
}
|
||||||
|
sw := rw.StringWidth(s)
|
||||||
|
if sw > w {
|
||||||
|
return []rune(rw.Truncate(s, w, dot))
|
||||||
|
}
|
||||||
|
return str2runes(s) //[]rune(rw.Truncate(s, w, ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
func strWidth(s string) int {
|
||||||
|
return rw.StringWidth(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func charWidth(ch rune) int {
|
||||||
|
return rw.RuneWidth(ch)
|
||||||
|
}
|
58
Godeps/_workspace/src/github.com/gizak/termui/helper_test.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStr2Rune(t *testing.T) {
|
||||||
|
s := "你好,世界."
|
||||||
|
rs := str2runes(s)
|
||||||
|
if len(rs) != 6 {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWidth(t *testing.T) {
|
||||||
|
s0 := "つのだ☆HIRO"
|
||||||
|
s1 := "11111111111"
|
||||||
|
spew.Dump(s0)
|
||||||
|
spew.Dump(s1)
|
||||||
|
// above not align for setting East Asian Ambiguous to wide!!
|
||||||
|
|
||||||
|
if strWidth(s0) != strWidth(s1) {
|
||||||
|
t.Error("str len failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
len1 := []rune{'a', '2', '&', '「', 'オ', '。'} //will false: 'ᆵ', 'ᄚ', 'ᄒ'
|
||||||
|
for _, v := range len1 {
|
||||||
|
if charWidth(v) != 1 {
|
||||||
|
t.Error("len1 failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len2 := []rune{'漢', '字', '한', '자', '你', '好', 'だ', '。', '%', 's', 'E', 'ョ', '、', 'ヲ'}
|
||||||
|
for _, v := range len2 {
|
||||||
|
if charWidth(v) != 2 {
|
||||||
|
t.Error("len2 failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTrim(t *testing.T) {
|
||||||
|
s := "つのだ☆HIRO"
|
||||||
|
if string(trimStr2Runes(s, 10)) != "つのだ☆HI"+dot {
|
||||||
|
t.Error("trim failed")
|
||||||
|
}
|
||||||
|
if string(trimStr2Runes(s, 11)) != "つのだ☆HIRO" {
|
||||||
|
t.Error("avoid tail trim failed")
|
||||||
|
}
|
||||||
|
if string(trimStr2Runes(s, 15)) != "つのだ☆HIRO" {
|
||||||
|
t.Error("avoid trim failed")
|
||||||
|
}
|
||||||
|
}
|
104
Godeps/_workspace/src/github.com/gizak/termui/list.go
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// List displays []string as its items,
|
||||||
|
// it has a Overflow option (default is "hidden"), when set to "hidden",
|
||||||
|
// the item exceeding List's width is truncated, but when set to "wrap",
|
||||||
|
// the overflowed text breaks into next line.
|
||||||
|
/*
|
||||||
|
strs := []string{
|
||||||
|
"[0] github.com/gizak/termui",
|
||||||
|
"[1] editbox.go",
|
||||||
|
"[2] iterrupt.go",
|
||||||
|
"[3] keyboard.go",
|
||||||
|
"[4] output.go",
|
||||||
|
"[5] random_out.go",
|
||||||
|
"[6] dashboard.go",
|
||||||
|
"[7] nsf/termbox-go"}
|
||||||
|
|
||||||
|
ls := termui.NewList()
|
||||||
|
ls.Items = strs
|
||||||
|
ls.ItemFgColor = termui.ColorYellow
|
||||||
|
ls.Border.Label = "List"
|
||||||
|
ls.Height = 7
|
||||||
|
ls.Width = 25
|
||||||
|
ls.Y = 0
|
||||||
|
*/
|
||||||
|
type List struct {
|
||||||
|
Block
|
||||||
|
Items []string
|
||||||
|
Overflow string
|
||||||
|
ItemFgColor Attribute
|
||||||
|
ItemBgColor Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewList returns a new *List with current theme.
|
||||||
|
func NewList() *List {
|
||||||
|
l := &List{Block: *NewBlock()}
|
||||||
|
l.Overflow = "hidden"
|
||||||
|
l.ItemFgColor = theme.ListItemFg
|
||||||
|
l.ItemBgColor = theme.ListItemBg
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (l *List) Buffer() []Point {
|
||||||
|
ps := l.Block.Buffer()
|
||||||
|
switch l.Overflow {
|
||||||
|
case "wrap":
|
||||||
|
rs := str2runes(strings.Join(l.Items, "\n"))
|
||||||
|
i, j, k := 0, 0, 0
|
||||||
|
for i < l.innerHeight && k < len(rs) {
|
||||||
|
w := charWidth(rs[k])
|
||||||
|
if rs[k] == '\n' || j+w > l.innerWidth {
|
||||||
|
i++
|
||||||
|
j = 0
|
||||||
|
if rs[k] == '\n' {
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pi := Point{}
|
||||||
|
pi.X = l.innerX + j
|
||||||
|
pi.Y = l.innerY + i
|
||||||
|
|
||||||
|
pi.Ch = rs[k]
|
||||||
|
pi.Bg = l.ItemBgColor
|
||||||
|
pi.Fg = l.ItemFgColor
|
||||||
|
|
||||||
|
ps = append(ps, pi)
|
||||||
|
k++
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
case "hidden":
|
||||||
|
trimItems := l.Items
|
||||||
|
if len(trimItems) > l.innerHeight {
|
||||||
|
trimItems = trimItems[:l.innerHeight]
|
||||||
|
}
|
||||||
|
for i, v := range trimItems {
|
||||||
|
rs := trimStr2Runes(v, l.innerWidth)
|
||||||
|
|
||||||
|
j := 0
|
||||||
|
for _, vv := range rs {
|
||||||
|
w := charWidth(vv)
|
||||||
|
p := Point{}
|
||||||
|
p.X = l.innerX + j
|
||||||
|
p.Y = l.innerY + i
|
||||||
|
|
||||||
|
p.Ch = vv
|
||||||
|
p.Bg = l.ItemBgColor
|
||||||
|
p.Fg = l.ItemFgColor
|
||||||
|
|
||||||
|
ps = append(ps, p)
|
||||||
|
j += w
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l.Block.chopOverflow(ps)
|
||||||
|
}
|
233
Godeps/_workspace/src/github.com/gizak/termui/mbar.go
generated
vendored
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is the implemetation of multi-colored or stacked bar graph. This is different from default barGraph which is implemented in bar.go
|
||||||
|
// Multi-Colored-BarChart creates multiple bars in a widget:
|
||||||
|
/*
|
||||||
|
bc := termui.NewMBarChart()
|
||||||
|
data := make([][]int, 2)
|
||||||
|
data[0] := []int{3, 2, 5, 7, 9, 4}
|
||||||
|
data[1] := []int{7, 8, 5, 3, 1, 6}
|
||||||
|
bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
|
||||||
|
bc.Border.Label = "Bar Chart"
|
||||||
|
bc.Data = data
|
||||||
|
bc.Width = 26
|
||||||
|
bc.Height = 10
|
||||||
|
bc.DataLabels = bclabels
|
||||||
|
bc.TextColor = termui.ColorGreen
|
||||||
|
bc.BarColor = termui.ColorRed
|
||||||
|
bc.NumColor = termui.ColorYellow
|
||||||
|
*/
|
||||||
|
type MBarChart struct {
|
||||||
|
Block
|
||||||
|
BarColor [NumberofColors]Attribute
|
||||||
|
TextColor Attribute
|
||||||
|
NumColor [NumberofColors]Attribute
|
||||||
|
Data [NumberofColors][]int
|
||||||
|
DataLabels []string
|
||||||
|
BarWidth int
|
||||||
|
BarGap int
|
||||||
|
labels [][]rune
|
||||||
|
dataNum [NumberofColors][][]rune
|
||||||
|
numBar int
|
||||||
|
scale float64
|
||||||
|
max int
|
||||||
|
minDataLen int
|
||||||
|
numStack int
|
||||||
|
ShowScale bool
|
||||||
|
maxScale []rune
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBarChart returns a new *BarChart with current theme.
|
||||||
|
func NewMBarChart() *MBarChart {
|
||||||
|
bc := &MBarChart{Block: *NewBlock()}
|
||||||
|
bc.BarColor[0] = theme.MBarChartBar
|
||||||
|
bc.NumColor[0] = theme.MBarChartNum
|
||||||
|
bc.TextColor = theme.MBarChartText
|
||||||
|
bc.BarGap = 1
|
||||||
|
bc.BarWidth = 3
|
||||||
|
return bc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *MBarChart) layout() {
|
||||||
|
bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth)
|
||||||
|
bc.labels = make([][]rune, bc.numBar)
|
||||||
|
DataLen := 0
|
||||||
|
LabelLen := len(bc.DataLabels)
|
||||||
|
bc.minDataLen = 9999 //Set this to some very hight value so that we find the minimum one We want to know which array among data[][] has got the least length
|
||||||
|
|
||||||
|
// We need to know how many stack/data array data[0] , data[1] are there
|
||||||
|
for i := 0; i < len(bc.Data); i++ {
|
||||||
|
if bc.Data[i] == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
DataLen++
|
||||||
|
}
|
||||||
|
bc.numStack = DataLen
|
||||||
|
|
||||||
|
//We need to know what is the mimimum size of data array data[0] could have 10 elements data[1] could have only 5, so we plot only 5 bar graphs
|
||||||
|
|
||||||
|
for i := 0; i < DataLen; i++ {
|
||||||
|
if bc.minDataLen > len(bc.Data[i]) {
|
||||||
|
bc.minDataLen = len(bc.Data[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if LabelLen > bc.minDataLen {
|
||||||
|
LabelLen = bc.minDataLen
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < LabelLen && i < bc.numBar; i++ {
|
||||||
|
bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < bc.numStack; i++ {
|
||||||
|
bc.dataNum[i] = make([][]rune, len(bc.Data[i]))
|
||||||
|
//For each stack of bar calcualte the rune
|
||||||
|
for j := 0; j < LabelLen && i < bc.numBar; j++ {
|
||||||
|
n := bc.Data[i][j]
|
||||||
|
s := fmt.Sprint(n)
|
||||||
|
bc.dataNum[i][j] = trimStr2Runes(s, bc.BarWidth)
|
||||||
|
}
|
||||||
|
//If color is not defined by default then populate a color that is different from the prevous bar
|
||||||
|
if bc.BarColor[i] == ColorDefault && bc.NumColor[i] == ColorDefault {
|
||||||
|
if i == 0 {
|
||||||
|
bc.BarColor[i] = ColorBlack
|
||||||
|
} else {
|
||||||
|
bc.BarColor[i] = bc.BarColor[i-1] + 1
|
||||||
|
if bc.BarColor[i] > NumberofColors {
|
||||||
|
bc.BarColor[i] = ColorBlack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bc.NumColor[i] = (NumberofColors + 1) - bc.BarColor[i] //Make NumColor opposite of barColor for visibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If Max value is not set then we have to populate, this time the max value will be max(sum(d1[0],d2[0],d3[0]) .... sum(d1[n], d2[n], d3[n]))
|
||||||
|
|
||||||
|
if bc.max == 0 {
|
||||||
|
bc.max = -1
|
||||||
|
}
|
||||||
|
for i := 0; i < bc.minDataLen && i < LabelLen; i++ {
|
||||||
|
var dsum int
|
||||||
|
for j := 0; j < bc.numStack; j++ {
|
||||||
|
dsum += bc.Data[j][i]
|
||||||
|
}
|
||||||
|
if dsum > bc.max {
|
||||||
|
bc.max = dsum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Finally Calculate max sale
|
||||||
|
if bc.ShowScale {
|
||||||
|
s := fmt.Sprintf("%d", bc.max)
|
||||||
|
bc.maxScale = trimStr2Runes(s, len(s))
|
||||||
|
bc.scale = float64(bc.max) / float64(bc.innerHeight-2)
|
||||||
|
} else {
|
||||||
|
bc.scale = float64(bc.max) / float64(bc.innerHeight-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *MBarChart) SetMax(max int) {
|
||||||
|
|
||||||
|
if max > 0 {
|
||||||
|
bc.max = max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (bc *MBarChart) Buffer() []Point {
|
||||||
|
ps := bc.Block.Buffer()
|
||||||
|
bc.layout()
|
||||||
|
var oftX int
|
||||||
|
|
||||||
|
for i := 0; i < bc.numBar && i < bc.minDataLen && i < len(bc.DataLabels); i++ {
|
||||||
|
ph := 0 //Previous Height to stack up
|
||||||
|
oftX = i * (bc.BarWidth + bc.BarGap)
|
||||||
|
for i1 := 0; i1 < bc.numStack; i1++ {
|
||||||
|
h := int(float64(bc.Data[i1][i]) / bc.scale)
|
||||||
|
// plot bars
|
||||||
|
for j := 0; j < bc.BarWidth; j++ {
|
||||||
|
for k := 0; k < h; k++ {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = ' '
|
||||||
|
p.Bg = bc.BarColor[i1]
|
||||||
|
if bc.BarColor[i1] == ColorDefault { // when color is default, space char treated as transparent!
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 2 - k - ph
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ph += h
|
||||||
|
}
|
||||||
|
// plot text
|
||||||
|
for j, k := 0, 0; j < len(bc.labels[i]); j++ {
|
||||||
|
w := charWidth(bc.labels[i][j])
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = bc.labels[i][j]
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
p.Fg = bc.TextColor
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 1
|
||||||
|
p.X = bc.innerX + oftX + ((bc.BarWidth - len(bc.labels[i])) / 2) + k
|
||||||
|
ps = append(ps, p)
|
||||||
|
k += w
|
||||||
|
}
|
||||||
|
// plot num
|
||||||
|
ph = 0 //re-initialize previous height
|
||||||
|
for i1 := 0; i1 < bc.numStack; i1++ {
|
||||||
|
h := int(float64(bc.Data[i1][i]) / bc.scale)
|
||||||
|
for j := 0; j < len(bc.dataNum[i1][i]) && h > 0; j++ {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = bc.dataNum[i1][i][j]
|
||||||
|
p.Fg = bc.NumColor[i1]
|
||||||
|
p.Bg = bc.BarColor[i1]
|
||||||
|
if bc.BarColor[i1] == ColorDefault { // the same as above
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
if h == 0 {
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
}
|
||||||
|
p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i1][i]))/2 + j
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 2 - ph
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
ph += h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bc.ShowScale {
|
||||||
|
//Currently bar graph only supprts data range from 0 to MAX
|
||||||
|
//Plot 0
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = '0'
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
p.Fg = bc.TextColor
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 2
|
||||||
|
p.X = bc.X
|
||||||
|
ps = append(ps, p)
|
||||||
|
|
||||||
|
//Plot the maximum sacle value
|
||||||
|
for i := 0; i < len(bc.maxScale); i++ {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = bc.maxScale[i]
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
p.Fg = bc.TextColor
|
||||||
|
p.Y = bc.innerY
|
||||||
|
p.X = bc.X + i
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return bc.Block.chopOverflow(ps)
|
||||||
|
}
|
71
Godeps/_workspace/src/github.com/gizak/termui/p.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
// Par displays a paragraph.
|
||||||
|
/*
|
||||||
|
par := termui.NewPar("Simple Text")
|
||||||
|
par.Height = 3
|
||||||
|
par.Width = 17
|
||||||
|
par.Border.Label = "Label"
|
||||||
|
*/
|
||||||
|
type Par struct {
|
||||||
|
Block
|
||||||
|
Text string
|
||||||
|
TextFgColor Attribute
|
||||||
|
TextBgColor Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPar returns a new *Par with given text as its content.
|
||||||
|
func NewPar(s string) *Par {
|
||||||
|
return &Par{
|
||||||
|
Block: *NewBlock(),
|
||||||
|
Text: s,
|
||||||
|
TextFgColor: theme.ParTextFg,
|
||||||
|
TextBgColor: theme.ParTextBg}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (p *Par) Buffer() []Point {
|
||||||
|
ps := p.Block.Buffer()
|
||||||
|
|
||||||
|
rs := str2runes(p.Text)
|
||||||
|
i, j, k := 0, 0, 0
|
||||||
|
for i < p.innerHeight && k < len(rs) {
|
||||||
|
// the width of char is about to print
|
||||||
|
w := charWidth(rs[k])
|
||||||
|
|
||||||
|
if rs[k] == '\n' || j+w > p.innerWidth {
|
||||||
|
i++
|
||||||
|
j = 0 // set x = 0
|
||||||
|
if rs[k] == '\n' {
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
|
||||||
|
if i >= p.innerHeight {
|
||||||
|
ps = append(ps, newPointWithAttrs('…',
|
||||||
|
p.innerX+p.innerWidth-1,
|
||||||
|
p.innerY+p.innerHeight-1,
|
||||||
|
p.TextFgColor, p.TextBgColor))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pi := Point{}
|
||||||
|
pi.X = p.innerX + j
|
||||||
|
pi.Y = p.innerY + i
|
||||||
|
|
||||||
|
pi.Ch = rs[k]
|
||||||
|
pi.Bg = p.TextBgColor
|
||||||
|
pi.Fg = p.TextFgColor
|
||||||
|
|
||||||
|
ps = append(ps, pi)
|
||||||
|
|
||||||
|
k++
|
||||||
|
j += w
|
||||||
|
}
|
||||||
|
return p.Block.chopOverflow(ps)
|
||||||
|
}
|
28
Godeps/_workspace/src/github.com/gizak/termui/point.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
// Point stands for a single cell in terminal.
|
||||||
|
type Point struct {
|
||||||
|
Ch rune
|
||||||
|
Bg Attribute
|
||||||
|
Fg Attribute
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPoint(c rune, x, y int) (p Point) {
|
||||||
|
p.Ch = c
|
||||||
|
p.X = x
|
||||||
|
p.Y = y
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPointWithAttrs(c rune, x, y int, fg, bg Attribute) Point {
|
||||||
|
p := newPoint(c, x, y)
|
||||||
|
p.Bg = bg
|
||||||
|
p.Fg = fg
|
||||||
|
return p
|
||||||
|
}
|
60
Godeps/_workspace/src/github.com/gizak/termui/render.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import tm "github.com/nsf/termbox-go"
|
||||||
|
|
||||||
|
// Bufferer should be implemented by all renderable components.
|
||||||
|
type Bufferer interface {
|
||||||
|
Buffer() []Point
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes termui library. This function should be called before any others.
|
||||||
|
// After initialization, the library must be finalized by 'Close' function.
|
||||||
|
func Init() error {
|
||||||
|
Body = NewGrid()
|
||||||
|
Body.X = 0
|
||||||
|
Body.Y = 0
|
||||||
|
Body.BgColor = theme.BodyBg
|
||||||
|
defer func() {
|
||||||
|
w, _ := tm.Size()
|
||||||
|
Body.Width = w
|
||||||
|
evtListen()
|
||||||
|
}()
|
||||||
|
return tm.Init()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close finalizes termui library,
|
||||||
|
// should be called after successful initialization when termui's functionality isn't required anymore.
|
||||||
|
func Close() {
|
||||||
|
tm.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TermWidth returns the current terminal's width.
|
||||||
|
func TermWidth() int {
|
||||||
|
tm.Sync()
|
||||||
|
w, _ := tm.Size()
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
// TermHeight returns the current terminal's height.
|
||||||
|
func TermHeight() int {
|
||||||
|
tm.Sync()
|
||||||
|
_, h := tm.Size()
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render renders all Bufferer in the given order from left to right,
|
||||||
|
// right could overlap on left ones.
|
||||||
|
func Render(rs ...Bufferer) {
|
||||||
|
tm.Clear(tm.ColorDefault, toTmAttr(theme.BodyBg))
|
||||||
|
for _, r := range rs {
|
||||||
|
buf := r.Buffer()
|
||||||
|
for _, v := range buf {
|
||||||
|
tm.SetCell(v.X, v.Y, v.Ch, toTmAttr(v.Fg), toTmAttr(v.Bg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tm.Flush()
|
||||||
|
}
|
156
Godeps/_workspace/src/github.com/gizak/termui/sparkline.go
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃
|
||||||
|
/*
|
||||||
|
data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1}
|
||||||
|
spl := termui.NewSparkline()
|
||||||
|
spl.Data = data
|
||||||
|
spl.Title = "Sparkline 0"
|
||||||
|
spl.LineColor = termui.ColorGreen
|
||||||
|
*/
|
||||||
|
type Sparkline struct {
|
||||||
|
Data []int
|
||||||
|
Height int
|
||||||
|
Title string
|
||||||
|
TitleColor Attribute
|
||||||
|
LineColor Attribute
|
||||||
|
displayHeight int
|
||||||
|
scale float32
|
||||||
|
max int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sparklines is a renderable widget which groups together the given sparklines.
|
||||||
|
/*
|
||||||
|
spls := termui.NewSparklines(spl0,spl1,spl2) //...
|
||||||
|
spls.Height = 2
|
||||||
|
spls.Width = 20
|
||||||
|
*/
|
||||||
|
type Sparklines struct {
|
||||||
|
Block
|
||||||
|
Lines []Sparkline
|
||||||
|
displayLines int
|
||||||
|
displayWidth int
|
||||||
|
}
|
||||||
|
|
||||||
|
var sparks = []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}
|
||||||
|
|
||||||
|
// Add appends a given Sparkline to s *Sparklines.
|
||||||
|
func (s *Sparklines) Add(sl Sparkline) {
|
||||||
|
s.Lines = append(s.Lines, sl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSparkline returns a unrenderable single sparkline that intended to be added into Sparklines.
|
||||||
|
func NewSparkline() Sparkline {
|
||||||
|
return Sparkline{
|
||||||
|
Height: 1,
|
||||||
|
TitleColor: theme.SparklineTitle,
|
||||||
|
LineColor: theme.SparklineLine}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSparklines return a new *Spaklines with given Sparkline(s), you can always add a new Sparkline later.
|
||||||
|
func NewSparklines(ss ...Sparkline) *Sparklines {
|
||||||
|
s := &Sparklines{Block: *NewBlock(), Lines: ss}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sl *Sparklines) update() {
|
||||||
|
for i, v := range sl.Lines {
|
||||||
|
if v.Title == "" {
|
||||||
|
sl.Lines[i].displayHeight = v.Height
|
||||||
|
} else {
|
||||||
|
sl.Lines[i].displayHeight = v.Height + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sl.displayWidth = sl.innerWidth
|
||||||
|
|
||||||
|
// get how many lines gotta display
|
||||||
|
h := 0
|
||||||
|
sl.displayLines = 0
|
||||||
|
for _, v := range sl.Lines {
|
||||||
|
if h+v.displayHeight <= sl.innerHeight {
|
||||||
|
sl.displayLines++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
h += v.displayHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < sl.displayLines; i++ {
|
||||||
|
data := sl.Lines[i].Data
|
||||||
|
|
||||||
|
max := math.MinInt32
|
||||||
|
for _, v := range data {
|
||||||
|
if max < v {
|
||||||
|
max = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sl.Lines[i].max = max
|
||||||
|
sl.Lines[i].scale = float32(8*sl.Lines[i].Height) / float32(max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (sl *Sparklines) Buffer() []Point {
|
||||||
|
ps := sl.Block.Buffer()
|
||||||
|
sl.update()
|
||||||
|
|
||||||
|
oftY := 0
|
||||||
|
for i := 0; i < sl.displayLines; i++ {
|
||||||
|
l := sl.Lines[i]
|
||||||
|
data := l.Data
|
||||||
|
|
||||||
|
if len(data) > sl.innerWidth {
|
||||||
|
data = data[len(data)-sl.innerWidth:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Title != "" {
|
||||||
|
rs := trimStr2Runes(l.Title, sl.innerWidth)
|
||||||
|
oftX := 0
|
||||||
|
for _, v := range rs {
|
||||||
|
w := charWidth(v)
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = v
|
||||||
|
p.Fg = l.TitleColor
|
||||||
|
p.Bg = sl.BgColor
|
||||||
|
p.X = sl.innerX + oftX
|
||||||
|
p.Y = sl.innerY + oftY
|
||||||
|
ps = append(ps, p)
|
||||||
|
oftX += w
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for j, v := range data {
|
||||||
|
h := int(float32(v)*l.scale + 0.5)
|
||||||
|
barCnt := h / 8
|
||||||
|
barMod := h % 8
|
||||||
|
for jj := 0; jj < barCnt; jj++ {
|
||||||
|
p := Point{}
|
||||||
|
p.X = sl.innerX + j
|
||||||
|
p.Y = sl.innerY + oftY + l.Height - jj
|
||||||
|
p.Ch = ' ' // => sparks[7]
|
||||||
|
p.Bg = l.LineColor
|
||||||
|
//p.Bg = sl.BgColor
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
if barMod != 0 {
|
||||||
|
p := Point{}
|
||||||
|
p.X = sl.innerX + j
|
||||||
|
p.Y = sl.innerY + oftY + l.Height - barCnt
|
||||||
|
p.Ch = sparks[barMod-1]
|
||||||
|
p.Fg = l.LineColor
|
||||||
|
p.Bg = sl.BgColor
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oftY += l.displayHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
return sl.Block.chopOverflow(ps)
|
||||||
|
}
|
84
Godeps/_workspace/src/github.com/gizak/termui/theme.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
// A ColorScheme represents the current look-and-feel of the dashboard.
|
||||||
|
type ColorScheme struct {
|
||||||
|
BodyBg Attribute
|
||||||
|
BlockBg Attribute
|
||||||
|
HasBorder bool
|
||||||
|
BorderFg Attribute
|
||||||
|
BorderBg Attribute
|
||||||
|
BorderLabelTextFg Attribute
|
||||||
|
BorderLabelTextBg Attribute
|
||||||
|
ParTextFg Attribute
|
||||||
|
ParTextBg Attribute
|
||||||
|
SparklineLine Attribute
|
||||||
|
SparklineTitle Attribute
|
||||||
|
GaugeBar Attribute
|
||||||
|
GaugePercent Attribute
|
||||||
|
LineChartLine Attribute
|
||||||
|
LineChartAxes Attribute
|
||||||
|
ListItemFg Attribute
|
||||||
|
ListItemBg Attribute
|
||||||
|
BarChartBar Attribute
|
||||||
|
BarChartText Attribute
|
||||||
|
BarChartNum Attribute
|
||||||
|
MBarChartBar Attribute
|
||||||
|
MBarChartText Attribute
|
||||||
|
MBarChartNum Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// default color scheme depends on the user's terminal setting.
|
||||||
|
var themeDefault = ColorScheme{HasBorder: true}
|
||||||
|
|
||||||
|
var themeHelloWorld = ColorScheme{
|
||||||
|
BodyBg: ColorBlack,
|
||||||
|
BlockBg: ColorBlack,
|
||||||
|
HasBorder: true,
|
||||||
|
BorderFg: ColorWhite,
|
||||||
|
BorderBg: ColorBlack,
|
||||||
|
BorderLabelTextBg: ColorBlack,
|
||||||
|
BorderLabelTextFg: ColorGreen,
|
||||||
|
ParTextBg: ColorBlack,
|
||||||
|
ParTextFg: ColorWhite,
|
||||||
|
SparklineLine: ColorMagenta,
|
||||||
|
SparklineTitle: ColorWhite,
|
||||||
|
GaugeBar: ColorRed,
|
||||||
|
GaugePercent: ColorWhite,
|
||||||
|
LineChartLine: ColorYellow | AttrBold,
|
||||||
|
LineChartAxes: ColorWhite,
|
||||||
|
ListItemBg: ColorBlack,
|
||||||
|
ListItemFg: ColorYellow,
|
||||||
|
BarChartBar: ColorRed,
|
||||||
|
BarChartNum: ColorWhite,
|
||||||
|
BarChartText: ColorCyan,
|
||||||
|
MBarChartBar: ColorRed,
|
||||||
|
MBarChartNum: ColorWhite,
|
||||||
|
MBarChartText: ColorCyan,
|
||||||
|
}
|
||||||
|
|
||||||
|
var theme = themeDefault // global dep
|
||||||
|
|
||||||
|
// Theme returns the currently used theme.
|
||||||
|
func Theme() ColorScheme {
|
||||||
|
return theme
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTheme sets a new, custom theme.
|
||||||
|
func SetTheme(newTheme ColorScheme) {
|
||||||
|
theme = newTheme
|
||||||
|
}
|
||||||
|
|
||||||
|
// UseTheme sets a predefined scheme. Currently available: "hello-world" and
|
||||||
|
// "black-and-white".
|
||||||
|
func UseTheme(th string) {
|
||||||
|
switch th {
|
||||||
|
case "helloworld":
|
||||||
|
theme = themeHelloWorld
|
||||||
|
default:
|
||||||
|
theme = themeDefault
|
||||||
|
}
|
||||||
|
}
|
23
Godeps/_workspace/src/github.com/hashicorp/golang-lru/.gitignore
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
362
Godeps/_workspace/src/github.com/hashicorp/golang-lru/LICENSE
generated
vendored
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the terms of
|
||||||
|
a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a
|
||||||
|
separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether
|
||||||
|
at the time of the initial grant or subsequently, any and all of the
|
||||||
|
rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the License,
|
||||||
|
by the making, using, selling, offering for sale, having made, import,
|
||||||
|
or transfer of either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, "control" means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights to
|
||||||
|
grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter the
|
||||||
|
recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||||
|
limitations of liability) contained within the Source Code Form of the
|
||||||
|
Covered Software, except that You may alter any license notices to the
|
||||||
|
extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute,
|
||||||
|
judicial order, or regulation then You must: (a) comply with the terms of
|
||||||
|
this License to the maximum extent possible; and (b) describe the
|
||||||
|
limitations and the code they affect. Such description must be placed in a
|
||||||
|
text file included with all distributions of the Covered Software under
|
||||||
|
this License. Except to the extent prohibited by statute or regulation,
|
||||||
|
such description must be sufficiently detailed for a recipient of ordinary
|
||||||
|
skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||||
|
basis, if such Contributor fails to notify You of the non-compliance by
|
||||||
|
some reasonable means prior to 60 days after You have come back into
|
||||||
|
compliance. Moreover, Your grants from a particular Contributor are
|
||||||
|
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||||
|
non-compliance by some reasonable means, this is the first time You have
|
||||||
|
received notice of non-compliance with this License from such
|
||||||
|
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||||
|
of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an "as is" basis,
|
||||||
|
without warranty of any kind, either expressed, implied, or statutory,
|
||||||
|
including, without limitation, warranties that the Covered Software is free
|
||||||
|
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||||
|
The entire risk as to the quality and performance of the Covered Software
|
||||||
|
is with You. Should any Covered Software prove defective in any respect,
|
||||||
|
You (not any Contributor) assume the cost of any necessary servicing,
|
||||||
|
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this License. No use of any Covered Software is authorized under
|
||||||
|
this License except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from
|
||||||
|
such party's negligence to the extent applicable law prohibits such
|
||||||
|
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||||
|
incidental or consequential damages, so this exclusion and limitation may
|
||||||
|
not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts
|
||||||
|
of a jurisdiction where the defendant maintains its principal place of
|
||||||
|
business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||||
|
in this Section shall prevent a party's ability to bring cross-claims or
|
||||||
|
counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides that
|
||||||
|
the language of a contract shall be construed against the drafter shall not
|
||||||
|
be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses If You choose to distribute Source Code Form that is
|
||||||
|
Incompatible With Secondary Licenses under the terms of this version of
|
||||||
|
the License, the notice described in Exhibit B of this License must be
|
||||||
|
attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file,
|
||||||
|
then You may include the notice in a location (such as a LICENSE file in a
|
||||||
|
relevant directory) where a recipient would be likely to look for such a
|
||||||
|
notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible
|
||||||
|
With Secondary Licenses", as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
25
Godeps/_workspace/src/github.com/hashicorp/golang-lru/README.md
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
golang-lru
|
||||||
|
==========
|
||||||
|
|
||||||
|
This provides the `lru` package which implements a fixed-size
|
||||||
|
thread safe LRU cache. It is based on the cache in Groupcache.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
Full docs are available on [Godoc](http://godoc.org/github.com/hashicorp/golang-lru)
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
Using the LRU is very simple:
|
||||||
|
|
||||||
|
```go
|
||||||
|
l, _ := New(128)
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
l.Add(i, nil)
|
||||||
|
}
|
||||||
|
if l.Len() != 128 {
|
||||||
|
panic(fmt.Sprintf("bad len: %v", l.Len()))
|
||||||
|
}
|
||||||
|
```
|
175
Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go
generated
vendored
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
// This package provides a simple LRU cache. It is based on the
|
||||||
|
// LRU implementation in groupcache:
|
||||||
|
// https://github.com/golang/groupcache/tree/master/lru
|
||||||
|
package lru
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cache is a thread-safe fixed size LRU cache.
|
||||||
|
type Cache struct {
|
||||||
|
size int
|
||||||
|
evictList *list.List
|
||||||
|
items map[interface{}]*list.Element
|
||||||
|
lock sync.RWMutex
|
||||||
|
onEvicted func(key interface{}, value interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// entry is used to hold a value in the evictList
|
||||||
|
type entry struct {
|
||||||
|
key interface{}
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates an LRU of the given size
|
||||||
|
func New(size int) (*Cache, error) {
|
||||||
|
return NewWithEvict(size, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) {
|
||||||
|
if size <= 0 {
|
||||||
|
return nil, errors.New("Must provide a positive size")
|
||||||
|
}
|
||||||
|
c := &Cache{
|
||||||
|
size: size,
|
||||||
|
evictList: list.New(),
|
||||||
|
items: make(map[interface{}]*list.Element, size),
|
||||||
|
onEvicted: onEvicted,
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge is used to completely clear the cache
|
||||||
|
func (c *Cache) Purge() {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
if c.onEvicted != nil {
|
||||||
|
for k, v := range c.items {
|
||||||
|
c.onEvicted(k, v.Value.(*entry).value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.evictList = list.New()
|
||||||
|
c.items = make(map[interface{}]*list.Element, c.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds a value to the cache. Returns true if an eviction occured.
|
||||||
|
func (c *Cache) Add(key, value interface{}) bool {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
// Check for existing item
|
||||||
|
if ent, ok := c.items[key]; ok {
|
||||||
|
c.evictList.MoveToFront(ent)
|
||||||
|
ent.Value.(*entry).value = value
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new item
|
||||||
|
ent := &entry{key, value}
|
||||||
|
entry := c.evictList.PushFront(ent)
|
||||||
|
c.items[key] = entry
|
||||||
|
|
||||||
|
evict := c.evictList.Len() > c.size
|
||||||
|
// Verify size not exceeded
|
||||||
|
if evict {
|
||||||
|
c.removeOldest()
|
||||||
|
}
|
||||||
|
return evict
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get looks up a key's value from the cache.
|
||||||
|
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
if ent, ok := c.items[key]; ok {
|
||||||
|
c.evictList.MoveToFront(ent)
|
||||||
|
return ent.Value.(*entry).value, true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a key is in the cache, without updating the recent-ness or deleting it for being stale.
|
||||||
|
func (c *Cache) Contains(key interface{}) (ok bool) {
|
||||||
|
c.lock.RLock()
|
||||||
|
defer c.lock.RUnlock()
|
||||||
|
|
||||||
|
_, ok = c.items[key]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the key value (or undefined if not found) without updating the "recently used"-ness of the key.
|
||||||
|
// (If you find yourself using this a lot, you might be using the wrong sort of data structure, but there are some use cases where it's handy.)
|
||||||
|
func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
|
||||||
|
c.lock.RLock()
|
||||||
|
defer c.lock.RUnlock()
|
||||||
|
|
||||||
|
if ent, ok := c.items[key]; ok {
|
||||||
|
return ent.Value.(*entry).value, true
|
||||||
|
}
|
||||||
|
return nil, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes the provided key from the cache.
|
||||||
|
func (c *Cache) Remove(key interface{}) {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
if ent, ok := c.items[key]; ok {
|
||||||
|
c.removeElement(ent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveOldest removes the oldest item from the cache.
|
||||||
|
func (c *Cache) RemoveOldest() {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
c.removeOldest()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys returns a slice of the keys in the cache, from oldest to newest.
|
||||||
|
func (c *Cache) Keys() []interface{} {
|
||||||
|
c.lock.RLock()
|
||||||
|
defer c.lock.RUnlock()
|
||||||
|
|
||||||
|
keys := make([]interface{}, len(c.items))
|
||||||
|
ent := c.evictList.Back()
|
||||||
|
i := 0
|
||||||
|
for ent != nil {
|
||||||
|
keys[i] = ent.Value.(*entry).key
|
||||||
|
ent = ent.Prev()
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of items in the cache.
|
||||||
|
func (c *Cache) Len() int {
|
||||||
|
c.lock.RLock()
|
||||||
|
defer c.lock.RUnlock()
|
||||||
|
return c.evictList.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeOldest removes the oldest item from the cache.
|
||||||
|
func (c *Cache) removeOldest() {
|
||||||
|
ent := c.evictList.Back()
|
||||||
|
if ent != nil {
|
||||||
|
c.removeElement(ent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeElement is used to remove a given list element from the cache
|
||||||
|
func (c *Cache) removeElement(e *list.Element) {
|
||||||
|
c.evictList.Remove(e)
|
||||||
|
kv := e.Value.(*entry)
|
||||||
|
delete(c.items, kv.key)
|
||||||
|
if c.onEvicted != nil {
|
||||||
|
c.onEvicted(kv.key, kv.value)
|
||||||
|
}
|
||||||
|
}
|
127
Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go
generated
vendored
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package lru
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestLRU(t *testing.T) {
|
||||||
|
evictCounter := 0
|
||||||
|
onEvicted := func(k interface{}, v interface{}) {
|
||||||
|
if k != v {
|
||||||
|
t.Fatalf("Evict values not equal (%v!=%v)", k, v)
|
||||||
|
}
|
||||||
|
evictCounter += 1
|
||||||
|
}
|
||||||
|
l, err := NewWithEvict(128, onEvicted)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
l.Add(i, i)
|
||||||
|
}
|
||||||
|
if l.Len() != 128 {
|
||||||
|
t.Fatalf("bad len: %v", l.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
if evictCounter != 128 {
|
||||||
|
t.Fatalf("bad evict count: %v", evictCounter)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, k := range l.Keys() {
|
||||||
|
if v, ok := l.Get(k); !ok || v != k || v != i+128 {
|
||||||
|
t.Fatalf("bad key: %v", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 0; i < 128; i++ {
|
||||||
|
_, ok := l.Get(i)
|
||||||
|
if ok {
|
||||||
|
t.Fatalf("should be evicted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 128; i < 256; i++ {
|
||||||
|
_, ok := l.Get(i)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("should not be evicted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 128; i < 192; i++ {
|
||||||
|
l.Remove(i)
|
||||||
|
_, ok := l.Get(i)
|
||||||
|
if ok {
|
||||||
|
t.Fatalf("should be deleted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Get(192) // expect 192 to be last key in l.Keys()
|
||||||
|
|
||||||
|
for i, k := range l.Keys() {
|
||||||
|
if (i < 63 && k != i+193) || (i == 63 && k != 192) {
|
||||||
|
t.Fatalf("out of order key: %v", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Purge()
|
||||||
|
if l.Len() != 0 {
|
||||||
|
t.Fatalf("bad len: %v", l.Len())
|
||||||
|
}
|
||||||
|
if _, ok := l.Get(200); ok {
|
||||||
|
t.Fatalf("should contain nothing")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that Add returns true/false if an eviction occured
|
||||||
|
func TestLRUAdd(t *testing.T) {
|
||||||
|
evictCounter := 0
|
||||||
|
onEvicted := func(k interface{}, v interface{}) {
|
||||||
|
evictCounter += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
l, err := NewWithEvict(1, onEvicted)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Add(1, 1) == true || evictCounter != 0 {
|
||||||
|
t.Errorf("should not have an eviction")
|
||||||
|
}
|
||||||
|
if l.Add(2, 2) == false || evictCounter != 1 {
|
||||||
|
t.Errorf("should have an eviction")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that Contains doesn't update recent-ness
|
||||||
|
func TestLRUContains(t *testing.T) {
|
||||||
|
l, err := New(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Add(1, 1)
|
||||||
|
l.Add(2, 2)
|
||||||
|
if !l.Contains(1) {
|
||||||
|
t.Errorf("1 should be contained")
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Add(3, 3)
|
||||||
|
if l.Contains(1) {
|
||||||
|
t.Errorf("Contains should not have updated recent-ness of 1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that Peek doesn't update recent-ness
|
||||||
|
func TestLRUPeek(t *testing.T) {
|
||||||
|
l, err := New(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Add(1, 1)
|
||||||
|
l.Add(2, 2)
|
||||||
|
if v, ok := l.Peek(1); !ok || v != 1 {
|
||||||
|
t.Errorf("1 should be set to 1: %v, %v", v, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Add(3, 3)
|
||||||
|
if l.Contains(1) {
|
||||||
|
t.Errorf("should not have updated recent-ness of 1")
|
||||||
|
}
|
||||||
|
}
|
5
Godeps/_workspace/src/github.com/howeyc/fsnotify/.gitignore
generated
vendored
@ -1,5 +0,0 @@
|
|||||||
# Setup a Global .gitignore for OS and editor generated files:
|
|
||||||
# https://help.github.com/articles/ignoring-files
|
|
||||||
# git config --global core.excludesfile ~/.gitignore_global
|
|
||||||
|
|
||||||
.vagrant
|
|
28
Godeps/_workspace/src/github.com/howeyc/fsnotify/AUTHORS
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
# Names should be added to this file as
|
|
||||||
# Name or Organization <email address>
|
|
||||||
# The email address is not required for organizations.
|
|
||||||
|
|
||||||
# You can update this list using the following command:
|
|
||||||
#
|
|
||||||
# $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
|
|
||||||
|
|
||||||
# Please keep the list sorted.
|
|
||||||
|
|
||||||
Adrien Bustany <adrien@bustany.org>
|
|
||||||
Caleb Spare <cespare@gmail.com>
|
|
||||||
Case Nelson <case@teammating.com>
|
|
||||||
Chris Howey <howeyc@gmail.com> <chris@howey.me>
|
|
||||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
|
||||||
Dave Cheney <dave@cheney.net>
|
|
||||||
Francisco Souza <f@souza.cc>
|
|
||||||
John C Barstow
|
|
||||||
Kelvin Fo <vmirage@gmail.com>
|
|
||||||
Nathan Youngman <git@nathany.com>
|
|
||||||
Paul Hammond <paul@paulhammond.org>
|
|
||||||
Pursuit92 <JoshChase@techpursuit.net>
|
|
||||||
Rob Figueiredo <robfig@gmail.com>
|
|
||||||
Travis Cline <travis.cline@gmail.com>
|
|
||||||
Tudor Golubenco <tudor.g@gmail.com>
|
|
||||||
bronze1man <bronze1man@gmail.com>
|
|
||||||
debrando <denis.brandolini@gmail.com>
|
|
||||||
henrikedwards <henrik.edwards@gmail.com>
|
|
160
Godeps/_workspace/src/github.com/howeyc/fsnotify/CHANGELOG.md
generated
vendored
@ -1,160 +0,0 @@
|
|||||||
# Changelog
|
|
||||||
|
|
||||||
## v0.9.0 / 2014-01-17
|
|
||||||
|
|
||||||
* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
|
|
||||||
* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
|
|
||||||
* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
|
|
||||||
|
|
||||||
## v0.8.12 / 2013-11-13
|
|
||||||
|
|
||||||
* [API] Remove FD_SET and friends from Linux adapter
|
|
||||||
|
|
||||||
## v0.8.11 / 2013-11-02
|
|
||||||
|
|
||||||
* [Doc] Add Changelog [#72][] (thanks @nathany)
|
|
||||||
* [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond)
|
|
||||||
|
|
||||||
## v0.8.10 / 2013-10-19
|
|
||||||
|
|
||||||
* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
|
|
||||||
* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
|
|
||||||
* [Doc] specify OS-specific limits in README (thanks @debrando)
|
|
||||||
|
|
||||||
## v0.8.9 / 2013-09-08
|
|
||||||
|
|
||||||
* [Doc] Contributing (thanks @nathany)
|
|
||||||
* [Doc] update package path in example code [#63][] (thanks @paulhammond)
|
|
||||||
* [Doc] GoCI badge in README (Linux only) [#60][]
|
|
||||||
* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
|
|
||||||
|
|
||||||
## v0.8.8 / 2013-06-17
|
|
||||||
|
|
||||||
* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
|
|
||||||
|
|
||||||
## v0.8.7 / 2013-06-03
|
|
||||||
|
|
||||||
* [API] Make syscall flags internal
|
|
||||||
* [Fix] inotify: ignore event changes
|
|
||||||
* [Fix] race in symlink test [#45][] (reported by @srid)
|
|
||||||
* [Fix] tests on Windows
|
|
||||||
* lower case error messages
|
|
||||||
|
|
||||||
## v0.8.6 / 2013-05-23
|
|
||||||
|
|
||||||
* kqueue: Use EVT_ONLY flag on Darwin
|
|
||||||
* [Doc] Update README with full example
|
|
||||||
|
|
||||||
## v0.8.5 / 2013-05-09
|
|
||||||
|
|
||||||
* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
|
|
||||||
|
|
||||||
## v0.8.4 / 2013-04-07
|
|
||||||
|
|
||||||
* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
|
|
||||||
|
|
||||||
## v0.8.3 / 2013-03-13
|
|
||||||
|
|
||||||
* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
|
|
||||||
* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
|
|
||||||
|
|
||||||
## v0.8.2 / 2013-02-07
|
|
||||||
|
|
||||||
* [Doc] add Authors
|
|
||||||
* [Fix] fix data races for map access [#29][] (thanks @fsouza)
|
|
||||||
|
|
||||||
## v0.8.1 / 2013-01-09
|
|
||||||
|
|
||||||
* [Fix] Windows path separators
|
|
||||||
* [Doc] BSD License
|
|
||||||
|
|
||||||
## v0.8.0 / 2012-11-09
|
|
||||||
|
|
||||||
* kqueue: directory watching improvements (thanks @vmirage)
|
|
||||||
* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
|
|
||||||
* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
|
|
||||||
|
|
||||||
## v0.7.4 / 2012-10-09
|
|
||||||
|
|
||||||
* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
|
|
||||||
* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
|
|
||||||
* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
|
|
||||||
* [Fix] kqueue: modify after recreation of file
|
|
||||||
|
|
||||||
## v0.7.3 / 2012-09-27
|
|
||||||
|
|
||||||
* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
|
|
||||||
* [Fix] kqueue: no longer get duplicate CREATE events
|
|
||||||
|
|
||||||
## v0.7.2 / 2012-09-01
|
|
||||||
|
|
||||||
* kqueue: events for created directories
|
|
||||||
|
|
||||||
## v0.7.1 / 2012-07-14
|
|
||||||
|
|
||||||
* [Fix] for renaming files
|
|
||||||
|
|
||||||
## v0.7.0 / 2012-07-02
|
|
||||||
|
|
||||||
* [Feature] FSNotify flags
|
|
||||||
* [Fix] inotify: Added file name back to event path
|
|
||||||
|
|
||||||
## v0.6.0 / 2012-06-06
|
|
||||||
|
|
||||||
* kqueue: watch files after directory created (thanks @tmc)
|
|
||||||
|
|
||||||
## v0.5.1 / 2012-05-22
|
|
||||||
|
|
||||||
* [Fix] inotify: remove all watches before Close()
|
|
||||||
|
|
||||||
## v0.5.0 / 2012-05-03
|
|
||||||
|
|
||||||
* [API] kqueue: return errors during watch instead of sending over channel
|
|
||||||
* kqueue: match symlink behavior on Linux
|
|
||||||
* inotify: add `DELETE_SELF` (requested by @taralx)
|
|
||||||
* [Fix] kqueue: handle EINTR (reported by @robfig)
|
|
||||||
* [Doc] Godoc example [#1][] (thanks @davecheney)
|
|
||||||
|
|
||||||
## v0.4.0 / 2012-03-30
|
|
||||||
|
|
||||||
* Go 1 released: build with go tool
|
|
||||||
* [Feature] Windows support using winfsnotify
|
|
||||||
* Windows does not have attribute change notifications
|
|
||||||
* Roll attribute notifications into IsModify
|
|
||||||
|
|
||||||
## v0.3.0 / 2012-02-19
|
|
||||||
|
|
||||||
* kqueue: add files when watch directory
|
|
||||||
|
|
||||||
## v0.2.0 / 2011-12-30
|
|
||||||
|
|
||||||
* update to latest Go weekly code
|
|
||||||
|
|
||||||
## v0.1.0 / 2011-10-19
|
|
||||||
|
|
||||||
* kqueue: add watch on file creation to match inotify
|
|
||||||
* kqueue: create file event
|
|
||||||
* inotify: ignore `IN_IGNORED` events
|
|
||||||
* event String()
|
|
||||||
* linux: common FileEvent functions
|
|
||||||
* initial commit
|
|
||||||
|
|
||||||
[#79]: https://github.com/howeyc/fsnotify/pull/79
|
|
||||||
[#77]: https://github.com/howeyc/fsnotify/pull/77
|
|
||||||
[#72]: https://github.com/howeyc/fsnotify/issues/72
|
|
||||||
[#71]: https://github.com/howeyc/fsnotify/issues/71
|
|
||||||
[#70]: https://github.com/howeyc/fsnotify/issues/70
|
|
||||||
[#63]: https://github.com/howeyc/fsnotify/issues/63
|
|
||||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
|
||||||
[#60]: https://github.com/howeyc/fsnotify/issues/60
|
|
||||||
[#59]: https://github.com/howeyc/fsnotify/issues/59
|
|
||||||
[#49]: https://github.com/howeyc/fsnotify/issues/49
|
|
||||||
[#45]: https://github.com/howeyc/fsnotify/issues/45
|
|
||||||
[#40]: https://github.com/howeyc/fsnotify/issues/40
|
|
||||||
[#36]: https://github.com/howeyc/fsnotify/issues/36
|
|
||||||
[#33]: https://github.com/howeyc/fsnotify/issues/33
|
|
||||||
[#29]: https://github.com/howeyc/fsnotify/issues/29
|
|
||||||
[#25]: https://github.com/howeyc/fsnotify/issues/25
|
|
||||||
[#24]: https://github.com/howeyc/fsnotify/issues/24
|
|
||||||
[#21]: https://github.com/howeyc/fsnotify/issues/21
|
|
||||||
[#1]: https://github.com/howeyc/fsnotify/issues/1
|
|
7
Godeps/_workspace/src/github.com/howeyc/fsnotify/CONTRIBUTING.md
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
# Contributing
|
|
||||||
|
|
||||||
## Moving Notice
|
|
||||||
|
|
||||||
There is a fork being actively developed with a new API in preparation for the Go Standard Library:
|
|
||||||
[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify)
|
|
||||||
|
|
28
Godeps/_workspace/src/github.com/howeyc/fsnotify/LICENSE
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
|
||||||
Copyright (c) 2012 fsnotify Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
92
Godeps/_workspace/src/github.com/howeyc/fsnotify/README.md
generated
vendored
@ -1,92 +0,0 @@
|
|||||||
# File system notifications for Go
|
|
||||||
|
|
||||||
[](http://godoc.org/github.com/howeyc/fsnotify)
|
|
||||||
|
|
||||||
Cross platform: Windows, Linux, BSD and OS X.
|
|
||||||
|
|
||||||
## Moving Notice
|
|
||||||
|
|
||||||
There is a fork being actively developed with a new API in preparation for the Go Standard Library:
|
|
||||||
[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify)
|
|
||||||
|
|
||||||
## Example:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/howeyc/fsnotify"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
watcher, err := fsnotify.NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
done := make(chan bool)
|
|
||||||
|
|
||||||
// Process events
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case ev := <-watcher.Event:
|
|
||||||
log.Println("event:", ev)
|
|
||||||
case err := <-watcher.Error:
|
|
||||||
log.Println("error:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = watcher.Watch("testDir")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
<-done
|
|
||||||
|
|
||||||
/* ... do stuff ... */
|
|
||||||
watcher.Close()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For each event:
|
|
||||||
* Name
|
|
||||||
* IsCreate()
|
|
||||||
* IsDelete()
|
|
||||||
* IsModify()
|
|
||||||
* IsRename()
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
**When a file is moved to another directory is it still being watched?**
|
|
||||||
|
|
||||||
No (it shouldn't be, unless you are watching where it was moved to).
|
|
||||||
|
|
||||||
**When I watch a directory, are all subdirectories watched as well?**
|
|
||||||
|
|
||||||
No, you must add watches for any directory you want to watch (a recursive watcher is in the works [#56][]).
|
|
||||||
|
|
||||||
**Do I have to watch the Error and Event channels in a separate goroutine?**
|
|
||||||
|
|
||||||
As of now, yes. Looking into making this single-thread friendly (see [#7][])
|
|
||||||
|
|
||||||
**Why am I receiving multiple events for the same file on OS X?**
|
|
||||||
|
|
||||||
Spotlight indexing on OS X can result in multiple events (see [#62][]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#54][]).
|
|
||||||
|
|
||||||
**How many files can be watched at once?**
|
|
||||||
|
|
||||||
There are OS-specific limits as to how many watches can be created:
|
|
||||||
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit,
|
|
||||||
reaching this limit results in a "no space left on device" error.
|
|
||||||
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
|
|
||||||
|
|
||||||
|
|
||||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
|
||||||
[#56]: https://github.com/howeyc/fsnotify/issues/56
|
|
||||||
[#54]: https://github.com/howeyc/fsnotify/issues/54
|
|
||||||
[#7]: https://github.com/howeyc/fsnotify/issues/7
|
|
||||||
|
|