Compare commits
2555 Commits
Author | SHA1 | Date | |
---|---|---|---|
3783c19d02 | |||
1f6e0255c0 | |||
b61af9a26a | |||
6e2f6c71fe | |||
f51d5789a3 | |||
933cee27ae | |||
4566c904d0 | |||
9b020c056b | |||
60b5863058 | |||
836f914163 | |||
594006cfa0 | |||
57761149f4 | |||
521e28dcdc | |||
a30930324d | |||
625e807a35 | |||
d18f34daa4 | |||
4fd73ef54a | |||
58f395989a | |||
791e8a0e59 | |||
14066ccc30 | |||
683b912263 | |||
3bac480ca0 | |||
97eb8492a3 | |||
0892a16a3d | |||
0b85938415 | |||
aaec840b91 | |||
74d0f19291 | |||
7ce570e52c | |||
3a0eded0b8 | |||
5afd45414e | |||
6ed033737d | |||
d38a3a8b4e | |||
6b4cb8b0e0 | |||
48fa25fd42 | |||
bdfad6b1de | |||
4f974efeba | |||
e86c1b118e | |||
5e177fe8e7 | |||
4129f15eb9 | |||
690ec9abfa | |||
b2c52b51b7 | |||
888369022f | |||
4409185e1b | |||
ef1934a7ee | |||
591fb4bd36 | |||
12d3e4e424 | |||
c3bed1352a | |||
3ceb39c82c | |||
13869e7d52 | |||
121a4f06fb | |||
d0e636ae7a | |||
6e7e2dbb97 | |||
d64cf1687e | |||
657b631fdc | |||
fa6ed7a40b | |||
80f21d37e0 | |||
e2cf4cc7d6 | |||
abe028f930 | |||
ef1cf7e634 | |||
1e4b33b9c6 | |||
4654f03d31 | |||
608b6f3634 | |||
a86e6ce89b | |||
c4cfbaec2d | |||
d40109f210 | |||
20be8a4987 | |||
d6dd4078b1 | |||
6649da3f5d | |||
62901573d0 | |||
80c9888f82 | |||
19c3570cf9 | |||
2cb815b7b4 | |||
a088081695 | |||
4bb95a880f | |||
9beecff736 | |||
fa0400c3f2 | |||
1d2d31580b | |||
834f993547 | |||
2193910579 | |||
f692da487e | |||
0986c61a5d | |||
6a6471b04b | |||
05f7d7d38b | |||
d89ad4fafd | |||
385bc40627 | |||
e2d24c5956 | |||
82633e2df7 | |||
31a4fc41eb | |||
79182db587 | |||
a2872b4ccc | |||
0afa18ac4a | |||
1aef3a730a | |||
e934062542 | |||
2e3b74f1b2 | |||
a87f53072a | |||
047081fa72 | |||
5586d4a0a0 | |||
911fba8a8a | |||
2873e943b3 | |||
0c9dd6a29a | |||
a4410fef40 | |||
0011f4df56 | |||
ee5064abed | |||
82e3bb0f38 | |||
319930a1b9 | |||
a64e0956cd | |||
91e17d2f9f | |||
56a546e73d | |||
cf88c8eef3 | |||
3484e0defd | |||
79e4d35f01 | |||
71dd857926 | |||
7a789d68a2 | |||
8a9cc33aac | |||
66087b01e6 | |||
19fa41b114 | |||
91cd1717e9 | |||
12b85beecc | |||
2252833917 | |||
4e9c1067fb | |||
e505e57a7a | |||
d122827a30 | |||
b007290a4e | |||
7c92791eed | |||
80769b7197 | |||
9b5dff828d | |||
90013295aa | |||
ea7c8c237e | |||
5d5b02d8dc | |||
00b67d338d | |||
d32e878868 | |||
41af2e4b30 | |||
e9f9aab79f | |||
e826540037 | |||
a435a9924c | |||
02ed15b932 | |||
81e269c483 | |||
eceae26b0a | |||
ec5fd62f9f | |||
74af31a42f | |||
1c964cdfe7 | |||
352cf31db2 | |||
66e736dab4 | |||
18067138aa | |||
bd7a506897 | |||
1d38ff071e | |||
e6a5011fdb | |||
d5f23ab592 | |||
bd5778fa24 | |||
f3bb1d11d3 | |||
285f91e67a | |||
01c1e5e8b0 | |||
d6669d3f33 | |||
3db608eb5c | |||
b293282e9b | |||
983d115bc0 | |||
5a1af4d661 | |||
4f05e9f4a6 | |||
7773c4cd4d | |||
d0cbb2d12c | |||
0986eefb64 | |||
6e69d40bb9 | |||
9db356e174 | |||
6700fbeed7 | |||
ca12f39db3 | |||
460d635ed0 | |||
1a16b9a2c4 | |||
0bd8664f33 | |||
762da0989c | |||
65baeaecd4 | |||
cb5d997adf | |||
10d805c1fa | |||
54d9fff4f2 | |||
6e65aef9bf | |||
72daf8c64e | |||
c023d4111a | |||
ff3dffd813 | |||
30bb090cd4 | |||
dfffd45bcd | |||
c73d8d5f95 | |||
0ff9cc679e | |||
b342270112 | |||
ccc85a2979 | |||
005301647a | |||
5fcc670860 | |||
90b2ec537f | |||
f3626f7c3a | |||
7debb27d78 | |||
675d30d980 | |||
2f70442165 | |||
ce690ed18f | |||
14dc662e50 | |||
ffa3aaaa56 | |||
2b3843c7c0 | |||
9abb14b5fd | |||
12bf23faa6 | |||
643cce8a6f | |||
3bdd924349 | |||
be43b3c5fc | |||
355b1d9929 | |||
0d82d7df60 | |||
8fcf51908a | |||
0835073d85 | |||
925e9f4dcb | |||
e0fac7bc72 | |||
fac086c826 | |||
088d19ad47 | |||
99f7636b03 | |||
2ac990655e | |||
4ddf24269a | |||
b73af3b8df | |||
dc0c5a9772 | |||
477f3be8df | |||
ae7c0b1097 | |||
cede9b3156 | |||
299fea8538 | |||
35ff1076f3 | |||
073f8655eb | |||
1837bf775c | |||
a3df2e5631 | |||
0a95bc7e60 | |||
a2723c2ba4 | |||
0b6b321ad6 | |||
4f43d75130 | |||
fbbbde1489 | |||
7701c6b1d4 | |||
5ae5ef5146 | |||
69fd777120 | |||
fa7d66347f | |||
4aa9a18c63 | |||
1527b34d9c | |||
a4a8f5df54 | |||
32601bb352 | |||
6a1e504a50 | |||
488f81d012 | |||
bc119a5e98 | |||
9c17c73d5f | |||
cd721fc363 | |||
5b3cc73ac6 | |||
02dfb57ed1 | |||
fbb2e7136c | |||
b714e034aa | |||
e64ca97fe2 | |||
eef3de2d05 | |||
89b7f4d57c | |||
7c205d7a3a | |||
1157fcf372 | |||
eeef9f27eb | |||
47d5501f9f | |||
97b3e4a233 | |||
52f4c4ba7e | |||
7d0531d270 | |||
13f2048ffb | |||
210d25f2a0 | |||
2fd42d25b1 | |||
d90b7953dd | |||
50399c349f | |||
96a1bf5f8d | |||
fd88920a9d | |||
88d7b50e37 | |||
0da9213de6 | |||
4965f4cbf4 | |||
fef7f38da8 | |||
42f1874a3a | |||
2a89936bee | |||
ece5e7dbb7 | |||
a6a96b29cb | |||
e3100e6afd | |||
cb5c61d217 | |||
b09acdb7f9 | |||
0924975b4c | |||
d6a6c4b034 | |||
eec1730449 | |||
10364c4f22 | |||
ef70c8dbe4 | |||
0f437589fc | |||
796d4920ab | |||
7819210037 | |||
4ebbe07d27 | |||
10ceac998e | |||
446c2aab17 | |||
995757c055 | |||
799fa98411 | |||
d2bd71d2aa | |||
11bc056576 | |||
3eca43c0bb | |||
ed46f0ea17 | |||
0c3ea636fb | |||
2b377391c2 | |||
c6a3066103 | |||
977ef66356 | |||
e6570b41ca | |||
2126bef052 | |||
e8a6458f0d | |||
2b1e4dd242 | |||
70009c015d | |||
cbad648d0e | |||
3c62d27c28 | |||
2c9d8c4818 | |||
c984ce9dc9 | |||
308ab91aff | |||
c3979ef1cf | |||
784382edde | |||
feb4f5c347 | |||
21c0f7d738 | |||
4b18fdcc6e | |||
63487941fb | |||
676457acd3 | |||
f507613b38 | |||
25712760ba | |||
d054a724d1 | |||
c2bad71123 | |||
b448d1dbe1 | |||
3e8a41fbc9 | |||
31925c3d40 | |||
9888f8f298 | |||
739e403cd5 | |||
359bb6eebe | |||
6d4784a7c1 | |||
e4dcdcb254 | |||
88fa40d698 | |||
24fc9c657e | |||
6670b77b27 | |||
c0a1d18e3d | |||
2e167ea0c6 | |||
41fa1ab656 | |||
53b5012f1e | |||
07cd8f483e | |||
d1ec05b12b | |||
a2c4c92fce | |||
917886f8ad | |||
4f367a59de | |||
968427c4e9 | |||
d454fad4dc | |||
a96f8b891e | |||
5befa6f80a | |||
5bf2ffeaf5 | |||
9b2a022f5b | |||
fd22211737 | |||
2ba12afb01 | |||
6024a17a5b | |||
56aacc4852 | |||
643c5097d6 | |||
52ee1917ba | |||
9ea5a2ecd3 | |||
a32ce93c79 | |||
b92aaf0432 | |||
2ecae0ef43 | |||
aea4355d04 | |||
a6c565ed4e | |||
7163721571 | |||
965cea3af5 | |||
efd62f917f | |||
ac99ac003a | |||
3ecf17e7af | |||
da42100374 | |||
dfc478e074 | |||
28b5399fb7 | |||
3f14b75153 | |||
0f4f660759 | |||
d53eaac7a1 | |||
f085bd97f6 | |||
c893cc1485 | |||
e5bf56a7dd | |||
06f9047be4 | |||
786e4ab971 | |||
f65955ccc5 | |||
1235d516a5 | |||
dd11be03be | |||
a967854332 | |||
a5f9ad2a43 | |||
1377693f0f | |||
bccce0ab46 | |||
c7c427723b | |||
d4cd3f9578 | |||
9415352447 | |||
8f5b857fcf | |||
fa75c93765 | |||
393cb7ca6f | |||
f5f9d56c37 | |||
d50ccdf083 | |||
6e733f49bc | |||
f169a9be3b | |||
b8b2737890 | |||
d620f76a21 | |||
b64ac9eb7b | |||
5b6156687e | |||
c4e1559f89 | |||
644435bfe3 | |||
bd96ce4e9c | |||
7e6430def0 | |||
e763a8dcef | |||
df07e8e410 | |||
f824388f63 | |||
f11fa99d30 | |||
56b3fc61a3 | |||
66669d7839 | |||
5c1a1be02b | |||
9114a2d31d | |||
84f85ff9ae | |||
a743db8e8f | |||
fbaafaa459 | |||
f3d3e819fb | |||
63a2c2bc2d | |||
8c0a2d3c15 | |||
06f5affc0b | |||
7a3aeaf080 | |||
3576350b4b | |||
0fc03dbb00 | |||
4fdfc76d04 | |||
a520599fa0 | |||
77eb4c4188 | |||
e82ffc4dee | |||
6fc082f6e9 | |||
560be6e73e | |||
c5e7bccee5 | |||
73f94105a5 | |||
94a0e3060a | |||
eceb2d5106 | |||
9829e449e3 | |||
baf6348e66 | |||
cc171b6ad4 | |||
0256e42e3b | |||
48f4766a5f | |||
8ccc8e445f | |||
1fd7b9ac38 | |||
b4b7524206 | |||
328f7e92a0 | |||
fcc13224c1 | |||
926177235c | |||
85d1a681c7 | |||
968ef1e953 | |||
a16e485cce | |||
a767fa369c | |||
886ed5ab2d | |||
e16d6ae00c | |||
ba4d8ae8c3 | |||
e6db37bc82 | |||
0e5f4d88c5 | |||
2e3b2a48ee | |||
5cf91cb30d | |||
28947ff9a9 | |||
c2118e7505 | |||
e1f98c1bfd | |||
12d4c2986c | |||
f275644e13 | |||
fc88a8538b | |||
5d18e07b7d | |||
5a1d81221f | |||
43850bf20e | |||
94ab981235 | |||
f9e1c4ef50 | |||
659da3c4a4 | |||
9c7feb2b19 | |||
cf20eed7bc | |||
6d303f2ca3 | |||
b16e72f0a5 | |||
56ba57c74a | |||
baceb54660 | |||
19caef260d | |||
565be6aaef | |||
7242e52faa | |||
101f4f62a8 | |||
5fabfda57b | |||
a660720b68 | |||
d70d91e559 | |||
10c4c50f1f | |||
dbcadbc12c | |||
fdce6c49ab | |||
9259a56a28 | |||
265ee1281d | |||
a78c82d811 | |||
3ab55f7de9 | |||
84d3620d9b | |||
8a373dd554 | |||
c3e0e8eb5c | |||
de4449c3ee | |||
796b7a1962 | |||
a911b21256 | |||
80306f9ba6 | |||
2dd32c2b88 | |||
3eba90232a | |||
c4858fb202 | |||
8a93548de2 | |||
e45e8109aa | |||
709927cee4 | |||
abaeffab91 | |||
73dcec8ea1 | |||
b26acf97bd | |||
f29dbeddd7 | |||
8204cc4f28 | |||
c2f6dfa75c | |||
90f6b6aedf | |||
ece1e43238 | |||
fefd5fef12 | |||
dd2d601471 | |||
c6dad0d5eb | |||
522a53af68 | |||
1a246d141e | |||
b86c6db400 | |||
1e86af2fb9 | |||
a008f1aa80 | |||
ac0b331f00 | |||
3d3298290a | |||
e1c28cf06b | |||
2f0bbf5adb | |||
0043b9da74 | |||
b9c2bf226f | |||
cc1b784e3d | |||
cbdc0e2010 | |||
004d7b5ff0 | |||
ebaa584c5e | |||
c80a15cdfe | |||
4c9df9c7c1 | |||
96fedb47ee | |||
b1aa8f4edf | |||
d62716c83e | |||
def5869c1c | |||
76a4455255 | |||
2fbd182993 | |||
67cb720f24 | |||
a51d45b99d | |||
1fd0ddb52c | |||
060a4b3f48 | |||
95a5e9229a | |||
3c8716873e | |||
44821d9941 | |||
bffb4950c2 | |||
dc6f1c496b | |||
65ae3160ca | |||
1a25970645 | |||
9450bcb90c | |||
e91d8655c6 | |||
4c029d2545 | |||
c37f844644 | |||
86eeb4a5e7 | |||
020ad24b25 | |||
3f9fa28ae3 | |||
e11ac9f6f8 | |||
fd9e380a1e | |||
bfb9822475 | |||
9926561dd7 | |||
267ff4b0cf | |||
04395ee05c | |||
6f4b7efd3e | |||
a4421434d9 | |||
e8b8836977 | |||
78b5da8255 | |||
83ec374995 | |||
8ee619954d | |||
cdc8e67d61 | |||
285f65ba34 | |||
3023af66fd | |||
1ca3e03578 | |||
f4c0538653 | |||
69954a362d | |||
0cecaf82b1 | |||
5c749fcc63 | |||
6e44012a2f | |||
988a873466 | |||
ec94ca46bb | |||
53f41c1985 | |||
12189d417b | |||
0875d0451b | |||
62e9698b11 | |||
3d0b1ef1ce | |||
525ed7653f | |||
8a1b2d0812 | |||
d4fb95a98c | |||
f82e2fbac6 | |||
e11a030780 | |||
4e171203cc | |||
be0d221d56 | |||
fd3eec81b5 | |||
3d40e169ce | |||
bf9340ec48 | |||
310ecb79b6 | |||
89d852f76c | |||
af52def93c | |||
6a446f708d | |||
afe83104c6 | |||
b58aad5eb0 | |||
47d004ae24 | |||
446f160320 | |||
564c2dd7d1 | |||
e1272f3b73 | |||
6fa022b0a8 | |||
2df37d6ec2 | |||
0651e2b31f | |||
0ef0277882 | |||
939745ad67 | |||
f44954da68 | |||
846a048bba | |||
057bfff0cb | |||
ac07d93b02 | |||
91883bd572 | |||
69b2ed5566 | |||
b4e61a056c | |||
724cfaa890 | |||
65ef7b630b | |||
45b3592739 | |||
33ffb2c39a | |||
d4b6b4b09a | |||
54ed82a19a | |||
be8c905ca7 | |||
d2d22815fb | |||
6514a30b5d | |||
73ad862042 | |||
71feacf46c | |||
db704ebaed | |||
ff9d88887b | |||
4e8e03867c | |||
49e8af8ea5 | |||
d5d61d14b3 | |||
6d554398a7 | |||
60cbb7e75d | |||
efd9c5c7c3 | |||
f562a4526c | |||
e6c09f2dfc | |||
73a68954c4 | |||
20eb348896 | |||
2c75aabbfc | |||
01e691c5ba | |||
ac36f32647 | |||
085a7c18cb | |||
0f85646d8e | |||
c55b6c5ed5 | |||
283a615ecc | |||
9b128b7a03 | |||
bfe3c50dce | |||
5fae96a6b1 | |||
3b4baa31b6 | |||
746641edae | |||
fa5aab8170 | |||
b78924c777 | |||
75db4a75bc | |||
8f4ee14d85 | |||
89d99db94f | |||
f9c0d223c1 | |||
21a7278259 | |||
bee5ba3deb | |||
a7241f9899 | |||
40484966c3 | |||
7c23ae5cb0 | |||
ca215c1152 | |||
2b6ce4dfe5 | |||
bc1e1aa944 | |||
1ecbebb24a | |||
82d90f4930 | |||
d0f9943709 | |||
58c5ea4937 | |||
186da4d725 | |||
47495715a6 | |||
ffb086d56f | |||
74fd78e02c | |||
160339bd1f | |||
d3bfc61524 | |||
733b2836f1 | |||
3a17b60862 | |||
7970e71bd4 | |||
b49885bb85 | |||
4860014cec | |||
476d543dee | |||
d63eac69e5 | |||
38e0527083 | |||
3b467bedd9 | |||
f964ce9bc0 | |||
f016a5cb72 | |||
3478f35330 | |||
eab6b322bb | |||
8a0d2b4e32 | |||
e44789556b | |||
d39e8c15fe | |||
47544ad219 | |||
d0c280f6cc | |||
14cd798f00 | |||
cc1ae969fe | |||
3c2a336ef9 | |||
f71e16685c | |||
058738c48c | |||
affb9696c7 | |||
c158d29577 | |||
b4c72e85e1 | |||
41dbc641cc | |||
4584d69715 | |||
74dcd91cc3 | |||
8f6843c600 | |||
4d1ce6c27b | |||
857ecda050 | |||
36079f1a3d | |||
b6fcd46075 | |||
cb8b7e08a5 | |||
681e37cec6 | |||
91d807b1d2 | |||
fe5f65a247 | |||
9535e2c309 | |||
398502b0d6 | |||
850f66aa9d | |||
354d51a3a6 | |||
c9dcd212ba | |||
ffaaa53526 | |||
f7e3d4de24 | |||
a56994ccc5 | |||
ac487dfcbc | |||
4383b372f5 | |||
7fa1ad010b | |||
5d58f68c59 | |||
f734995170 | |||
44791b5835 | |||
15b979b06e | |||
18ddcdcb97 | |||
2320987862 | |||
822309be8e | |||
15b0424d73 | |||
56ae07adb9 | |||
80649f2341 | |||
7faa4fbff4 | |||
7d1d6f075c | |||
832a801c11 | |||
c8330523c8 | |||
62011b6bcc | |||
e94b8007c1 | |||
0c1a7459b2 | |||
384ea111eb | |||
5c94528fe2 | |||
53330c5676 | |||
1837acfc70 | |||
1dbf351425 | |||
f50f37c853 | |||
3706bef0a1 | |||
de30236f38 | |||
e1c92e90ca | |||
39f03bf5e4 | |||
e62e0fb679 | |||
89a000a572 | |||
ca6baf7a46 | |||
d603086d2f | |||
a811eee6b8 | |||
1efae6876d | |||
1214cd57e8 | |||
3522bead97 | |||
7f0921a14b | |||
b719f8d4eb | |||
29c8b826d4 | |||
ba1ff4cf6c | |||
5c83f4d405 | |||
f3c175562d | |||
c33104c4ae | |||
ef59b4aa51 | |||
3389baa392 | |||
5d3b63fa90 | |||
6cd124ddb2 | |||
061c822c5d | |||
0c920f7d05 | |||
43dd0960a0 | |||
9fb12fefb0 | |||
8ba3e3570c | |||
ea6912c3f7 | |||
deeb1da359 | |||
52dba91e1a | |||
266fac910a | |||
3ad5d4af66 | |||
a93a9b9029 | |||
6a35e6b7b6 | |||
c3a16902fe | |||
fc7ed1bfe4 | |||
d32aec5906 | |||
1609101e62 | |||
0571a6ee34 | |||
152467a858 | |||
caf73c36f2 | |||
e949658381 | |||
ff5b7e5ad2 | |||
cf5048205f | |||
c37bdcd119 | |||
038ad951da | |||
2883d6cd1e | |||
b54e9b6bfd | |||
ebf57c70e0 | |||
00bb203756 | |||
8933dde324 | |||
b3b328d19d | |||
46b86f3541 | |||
d8847f1082 | |||
ada9c742c6 | |||
6f6340186a | |||
6ba1e6172c | |||
438c2df8b6 | |||
6a0f404558 | |||
342584e5f8 | |||
efb4a9f95c | |||
bf6780967b | |||
a148ad8697 | |||
9a864b5017 | |||
17a7a85c78 | |||
89e2169521 | |||
e289630920 | |||
1d74d9c5ae | |||
aea2adc44a | |||
0450cc25e0 | |||
e9525627e6 | |||
1cbb785969 | |||
a41ae72bc1 | |||
a5c1dd0da5 | |||
e919f9a73b | |||
a3c349746f | |||
04a9c8f3fd | |||
673fe2b56a | |||
b5f8f64d79 | |||
930cb26e99 | |||
3701fd1d76 | |||
ee6ab17fde | |||
486f91e3a7 | |||
906c0e6bca | |||
1336acd34a | |||
2013e9300a | |||
90ddb23492 | |||
bee7ef21eb | |||
1576b959f9 | |||
4096f52003 | |||
7ceb668419 | |||
420aee18ca | |||
d1d1402512 | |||
c33d082ecc | |||
6f53912655 | |||
34a8a897c5 | |||
4d7dd23779 | |||
f8e6620e48 | |||
7cbeebaac1 | |||
9d7685e565 | |||
c2aa6c708d | |||
626b1b99cd | |||
4103abc685 | |||
d0119ea05d | |||
3df5e63c05 | |||
e77c6bb284 | |||
95841e3489 | |||
c2c4a1968b | |||
2e2d5ef0eb | |||
7a892ec5d7 | |||
865906e450 | |||
7319b6b168 | |||
c3b6e07de6 | |||
5c27ffa42e | |||
3dc19d4179 | |||
a8e5cb871e | |||
15e9c11849 | |||
9fd680ae2b | |||
ad94ed5e13 | |||
a7a213b3f2 | |||
1bdcdcca70 | |||
512dcf0988 | |||
8d027a0617 | |||
610e3911f6 | |||
11a781fc36 | |||
a42bbea98d | |||
c8b9913718 | |||
1fd26727c5 | |||
ee9eddd851 | |||
fdde95f675 | |||
9548e5ef5b | |||
29efbee285 | |||
22469a9cb1 | |||
03e22b071a | |||
71a8eb6f8e | |||
ddd8c3d9dc | |||
c6aff972da | |||
82aa84706e | |||
3e0c5e55b6 | |||
8a06ea133b | |||
eed22605ef | |||
8cf4402e6c | |||
df5ac9b71c | |||
bef138232c | |||
ee45755ea9 | |||
405a4e58c7 | |||
f3c8d35eb7 | |||
a28d38b05f | |||
574d7f6936 | |||
3d8394a909 | |||
349e83abd0 | |||
bf82417d52 | |||
c5297d2b64 | |||
d9bedaae2f | |||
19766556f3 | |||
687fefd791 | |||
ccd5f59314 | |||
c08e145501 | |||
ff673ba0ba | |||
c00853a473 | |||
f57d629b55 | |||
43972db131 | |||
f2aa952e86 | |||
071066b6d9 | |||
79c7b20cfd | |||
ac2afab40b | |||
99de2b1d77 | |||
45eba8b922 | |||
56307553ae | |||
2bbba3f5da | |||
34e0fd622b | |||
124561ff12 | |||
89cbfd758d | |||
d8c721282b | |||
d2a1564b94 | |||
7cf96c6597 | |||
b8f1fea7fe | |||
e6e6b730f3 | |||
0fe6a7c1b5 | |||
3916ac4165 | |||
c17e1473db | |||
21ddfc61f4 | |||
ce4d9dc7c6 | |||
414ed4877a | |||
5de12da765 | |||
1794ad51bd | |||
bab8f6bd28 | |||
ee239a0d37 | |||
e07ce57423 | |||
6d58e2b51e | |||
c8b16c14d5 | |||
e1e7e94261 | |||
8c0fa0d26e | |||
f7f8b0dbff | |||
63c3d19c67 | |||
0ba0daa2c4 | |||
fb197f562a | |||
91c270c14a | |||
5d88ed6c75 | |||
f052b3313d | |||
3e93ae8af4 | |||
8043516d75 | |||
6a1942b18f | |||
76019f434e | |||
a2aaeb38ed | |||
143855b662 | |||
d30dfc63c4 | |||
250743f60f | |||
e06df124ca | |||
00aac850fd | |||
e01e73cb67 | |||
ff43ca4d24 | |||
88988dc9f4 | |||
aa7226d5f6 | |||
adb7eeb740 | |||
96bdcc4ff7 | |||
f8f437b060 | |||
b35914bd17 | |||
2590fcbe5c | |||
09691ff866 | |||
6fbe02eb21 | |||
5459d30a24 | |||
16db368232 | |||
df87d90b8c | |||
f2f01b8a4d | |||
6c0190cd38 | |||
b26246bf12 | |||
36a4effbb2 | |||
ab22619f4a | |||
9fca417f8c | |||
d09e1148b2 | |||
42367ddf6d | |||
e324c1a078 | |||
4fd020ab7f | |||
50cbd16ec7 | |||
be827e5628 | |||
f1b2ab0b27 | |||
0f107b2830 | |||
493bc2b1c9 | |||
74b812228c | |||
e76451866d | |||
08d316f6a7 | |||
14a2918bba | |||
db2bca56c9 | |||
e756a9ea04 | |||
568e566adf | |||
586c6d9fa8 | |||
f5b20f0e3b | |||
75cfee28b2 | |||
d094f654c3 | |||
bb1740d733 | |||
0f516a0830 | |||
ef20b5f1ef | |||
e1468c0440 | |||
6f4993618d | |||
2103294d11 | |||
9c3c7b82c8 | |||
0a20052799 | |||
34617fabd9 | |||
47628946b6 | |||
ce714f098f | |||
066afb059e | |||
e9a7def183 | |||
e0a26cd048 | |||
b5bade6187 | |||
fcee3c65bd | |||
19645575d6 | |||
dd6452dfaa | |||
cfd40ffaf5 | |||
00a8752c76 | |||
7e070e2e5b | |||
573cb38bab | |||
a1f141d18a | |||
6c31377c21 | |||
d401ed64ed | |||
02b8027749 | |||
c7d159a0f3 | |||
649b3804c1 | |||
345b51b272 | |||
5837cdb3f1 | |||
183d200b9f | |||
8c43f60e2e | |||
f8e48aa0af | |||
44fad9e698 | |||
14f30287f1 | |||
ae1109139d | |||
1d356276c2 | |||
4a1df604c9 | |||
d23929fc80 | |||
df6a53f52e | |||
cfd24bc2ad | |||
f6d7df5a45 | |||
2b03748681 | |||
1949ba080e | |||
260838e5ea | |||
112ebe1842 | |||
47ebde4087 | |||
bfae75ca2e | |||
806cd4851f | |||
ea27300ca0 | |||
d3e5c5a342 | |||
5ae823612f | |||
20f3b8b274 | |||
6906de7c48 | |||
bf6c3e53a0 | |||
af5799c702 | |||
756773a6ed | |||
8192ba8d88 | |||
86e1092785 | |||
e193bf43fb | |||
12eed1f98a | |||
d134774f4b | |||
dfb846dec6 | |||
5e42b14026 | |||
78cc3452df | |||
070067b75e | |||
52cb50b937 | |||
b53570ceaa | |||
ce54764bea | |||
6e49d0f84b | |||
e1ea0d42a9 | |||
8368b52ac7 | |||
19301751ee | |||
7b2116dc29 | |||
732ff317f0 | |||
25846d3c1e | |||
bc8d90672e | |||
d856cebebd | |||
3c1b3473ae | |||
89b8ee6ad8 | |||
4a68c989e4 | |||
e16b0e7b01 | |||
e14945fdf5 | |||
1c2741c598 | |||
89225cf55c | |||
1f4c34fa04 | |||
f4ed4fa7e3 | |||
c56a233808 | |||
468b9affde | |||
ef94c71866 | |||
43c3cfecf7 | |||
3176f60b5b | |||
ef56d482b2 | |||
304c7a0c92 | |||
8707fbee33 | |||
032356bfb7 | |||
3437dacf0b | |||
80a4a5eb28 | |||
b340672331 | |||
73ae3daf85 | |||
f182524298 | |||
b7c0ba104f | |||
7112664b3f | |||
5add6035a4 | |||
a390f66dbf | |||
fa8a0958e4 | |||
20c770370b | |||
c4af5df828 | |||
e549c1112b | |||
f94a3e15f5 | |||
da515b1c9d | |||
37f7a36123 | |||
9838154ad1 | |||
f301f686b5 | |||
2dcfecbbd7 | |||
751595e72e | |||
a160d480b1 | |||
cf3f3fde92 | |||
6e6df46469 | |||
624edce4f7 | |||
75782f0f50 | |||
51e48bee53 | |||
d853127c2e | |||
520d9e1fb6 | |||
37150af970 | |||
bac8b8a450 | |||
40ad9acbc3 | |||
1308eb45d5 | |||
f92e9d25a5 | |||
4fc533340b | |||
c998bbbe6d | |||
c114f41545 | |||
9baf720156 | |||
4b31fe1924 | |||
656e86a7ca | |||
5d62f1a9c1 | |||
6d6b850911 | |||
b5329fe4ec | |||
78256b4923 | |||
bd6c550470 | |||
95628bef16 | |||
ca7ff37697 | |||
af02c8f6ea | |||
0f27249319 | |||
1eb93e5c07 | |||
2b06ce27d3 | |||
3625324bad | |||
7e66aca18e | |||
595fc7a7f6 | |||
402a4acd7a | |||
a240aead8c | |||
75b3b3e090 | |||
5163dbb7a1 | |||
cbda1b1650 | |||
e66fd91045 | |||
a29c333cb1 | |||
0c7ec03ba0 | |||
6b14f9d6b0 | |||
29dde84394 | |||
543c566ccc | |||
9995cbc03b | |||
abb6d9f10f | |||
e039e5f6a4 | |||
9b67899f8d | |||
5455270446 | |||
11d8e6c71f | |||
2ce034d0f0 | |||
017b1d8996 | |||
a2c2a07638 | |||
3a5b943d11 | |||
766726d0fa | |||
798552b1b3 | |||
df07ed5bf6 | |||
301d1f6f87 | |||
962adf5a12 | |||
c18f0dcc84 | |||
4be61ce604 | |||
85a69c0a45 | |||
d29208dd9e | |||
f84582ca2b | |||
5d19017603 | |||
3f313da4c3 | |||
baac60a5a7 | |||
b5965ee8ef | |||
397a31e69c | |||
b6d269e90a | |||
aa5ab8a666 | |||
ab9d6b206d | |||
ffb361833b | |||
36a834c1e3 | |||
90c750285c | |||
4bb2406772 | |||
4887b5e4fd | |||
1296100d31 | |||
5a1d99cefb | |||
232790f488 | |||
297f3ba575 | |||
7bd5f887d1 | |||
66dad40092 | |||
72c241348b | |||
ab2d2db987 | |||
51bea2e884 | |||
b1d7e3aa49 | |||
1c52919103 | |||
b322a12f58 | |||
07e05ef183 | |||
11070ffbbe | |||
7ef5a7945f | |||
e330fdabb7 | |||
c9439c962b | |||
b7ad4dc78a | |||
1b745015c3 | |||
2be26127c9 | |||
68601629c0 | |||
82b0415d92 | |||
bd5009a865 | |||
5bd20e4d36 | |||
28b26ca44d | |||
b3192ddc97 | |||
8c2ae1eed1 | |||
9807b4a484 | |||
fdf6bbb6fc | |||
68b7aa9470 | |||
0d7b10fd0b | |||
9ea7cdfc33 | |||
87d57108e6 | |||
dcda7a4e50 | |||
fdd2c35fd9 | |||
ff6cc2cbdd | |||
5c46138563 | |||
ef58348ea2 | |||
e473bdb26d | |||
9b60f76d04 | |||
a760e46c1c | |||
f5ce63ad55 | |||
151bdc8910 | |||
2b99e49792 | |||
94d00b28b7 | |||
8fee0b32e7 | |||
97d7157773 | |||
ffd922f393 | |||
1ea124a65b | |||
6024a001b4 | |||
67b8438bda | |||
270e4fdd4c | |||
aea8627c30 | |||
5f14faf4b4 | |||
60f0394106 | |||
c8277a3da9 | |||
9f02307bd7 | |||
96419f168b | |||
1f45304cf9 | |||
db62bce6aa | |||
63e3552eef | |||
ce81cd6e2f | |||
0d031636a9 | |||
1a15f30eb8 | |||
6e92812cdf | |||
0676f32509 | |||
576471cc3c | |||
e0433076ff | |||
a67be074e6 | |||
dada7a9867 | |||
ea9aad9b5d | |||
38bc394a12 | |||
020143d050 | |||
d33a9549b5 | |||
c4fe190cee | |||
ba73e0eb06 | |||
0504a7a776 | |||
1b9b709dec | |||
0e36b4b1bd | |||
acb0360180 | |||
4d0a253924 | |||
c3a032950d | |||
b4344b3964 | |||
491efab09b | |||
7cafdc9675 | |||
89267df9eb | |||
ecee5a9845 | |||
77c520e10b | |||
40741254f6 | |||
0b35905ce9 | |||
beb15dcc77 | |||
97ca242634 | |||
a986de8ad0 | |||
53f3d2572c | |||
a0a63c966f | |||
d5fdfdb614 | |||
75de7f7e61 | |||
4e443b2088 | |||
9e7e8ed48f | |||
5f9ad0947d | |||
4235cf1191 | |||
357b9ccaa9 | |||
d1f0740765 | |||
29cbcb8459 | |||
7f06d6144f | |||
7db6b876ab | |||
d3bc096d47 | |||
8783cf0138 | |||
563a0b92b5 | |||
8df9ea6c68 | |||
b28f876095 | |||
5d36d37d20 | |||
789fc30bf9 | |||
2c01901fcf | |||
e4ce41ba15 | |||
a1bfa2788c | |||
8756e88e3c | |||
41366f6cc4 | |||
e3e4ae0591 | |||
9a3b0312d2 | |||
2cd1f634d0 | |||
ddea4b416d | |||
5c29a83a7a | |||
60f9fe1aa4 | |||
44fbf0fce3 | |||
4ddc953e38 | |||
6c5a99b1a5 | |||
64d83142c3 | |||
b654415494 | |||
dea9c1482b | |||
c79dca999c | |||
1b977c658c | |||
ed9fa2b4c3 | |||
42113a767a | |||
7f3f41ff14 | |||
c636c30a19 | |||
5ddf0d209d | |||
1a3a837f3e | |||
c4dabe8327 | |||
a2eba38e81 | |||
bdfe8c0888 | |||
c4977ae143 | |||
54a41c535b | |||
8550f50522 | |||
e8e1ead99d | |||
adabc839bf | |||
698f768a06 | |||
ae8b315e76 | |||
58d73d4c23 | |||
22cfe4391e | |||
5021d61800 | |||
97d17311f4 | |||
06d819ecc8 | |||
bb126e8e09 | |||
0f6fd30619 | |||
248decc546 | |||
2500f23fcb | |||
7eb022b58c | |||
d481d5ca96 | |||
996ee363b7 | |||
011ad2e4e6 | |||
d6d0bad7aa | |||
b35d47c500 | |||
b3b51a2ed6 | |||
c7de1ee13a | |||
cc8a470668 | |||
74d4c501a8 | |||
5cc7fbcde7 | |||
48f534cd3b | |||
8536c12bd9 | |||
8dc3ebd6e2 | |||
5da1310696 | |||
9d49618e87 | |||
7697f7bdce | |||
e1ebd461d2 | |||
f000d5d0a1 | |||
51a43f5617 | |||
11b40a6c31 | |||
3c843f7f61 | |||
e402adbba0 | |||
c4ea398160 | |||
27dcbe5c8a | |||
4eb43adef2 | |||
0ef0588e29 | |||
80e7a8d594 | |||
1b96da5e5b | |||
e3ce58475b | |||
31ce8c1e33 | |||
14426433aa | |||
535ece4e76 | |||
574c5961c8 | |||
75ec0d123a | |||
c884d5ca31 | |||
f80e9d4b60 | |||
26166192e5 | |||
7c2bf68d45 | |||
6f5f1fa43a | |||
58b0e571d3 | |||
a88058006a | |||
1e1e12b027 | |||
9737d4a614 | |||
0fe525de87 | |||
4dacfaa44a | |||
b2148e32b8 | |||
e325fd114d | |||
dfd321a679 | |||
909b7d2160 | |||
2b5cc63118 | |||
75e323ee35 | |||
758fce8ae3 | |||
91090e1db1 | |||
5bf51b5a7a | |||
69708f7244 | |||
1d7ab28a0f | |||
eba3484611 | |||
b5ec9e0360 | |||
0cc121876b | |||
e4e1b7a11e | |||
be68b84473 | |||
ae34a34e00 | |||
81cd03626d | |||
6f4df31927 | |||
03339beae1 | |||
62c5df5fc6 | |||
92c855a412 | |||
9a64f1bff3 | |||
63a0aa6088 | |||
a8f9e6dcc2 | |||
6b76dd7cd7 | |||
7899745c4b | |||
5843acec02 | |||
9e7285ad46 | |||
8ef16c6da6 | |||
e1a0ad2987 | |||
2d4e471052 | |||
16c60f44d5 | |||
adb92b970e | |||
6595c06598 | |||
3567bbbf32 | |||
c5e9ff5f14 | |||
2c1b074bdc | |||
fb0f83e574 | |||
891d79d2aa | |||
25b05dec9e | |||
2af8116f50 | |||
aa06a71e1f | |||
8ed6afe1e5 | |||
244289c901 | |||
7488254cca | |||
3cbf99053f | |||
93521da9d8 | |||
561feff365 | |||
1b89ccf25b | |||
5b3b74ebec | |||
a16144baf1 | |||
d395816929 | |||
5a5205d5d9 | |||
503939dcbe | |||
000db46618 | |||
d6e24cceb4 | |||
99666829e0 | |||
db3e9efc4b | |||
3e232a5db8 | |||
e00755a2e9 | |||
d34e083976 | |||
8250b44ce5 | |||
f0d5e2dcf1 | |||
5e34ef6dff | |||
d567c58cc1 | |||
125c8c82c3 | |||
4e0d7bc77c | |||
2b5ef1b2d7 | |||
719920fa37 | |||
3b134a1ae2 | |||
84d0e0a059 | |||
0a48bc973d | |||
0108a935ed | |||
5ccbf4df67 | |||
9ee4dc49ee | |||
756269ee8d | |||
abb0d7bd22 | |||
47421e9ca7 | |||
3f8f3ecf9a | |||
f57f7b2def | |||
9e176674a5 | |||
57a07385ac | |||
12cf1a8f83 | |||
e9f1575924 | |||
32581497ef | |||
1015ea814c | |||
abac7e3795 | |||
22c6ed4718 | |||
3421a8b58b | |||
75510b172a | |||
04a8280d51 | |||
139775dcce | |||
d9c42eb194 | |||
6387401041 | |||
dadc354847 | |||
25a776c36b | |||
637e4f6e6d | |||
b12a265f1e | |||
cf60f72452 | |||
a176f12c9e | |||
d6df367c6b | |||
a2996abd47 | |||
b8d218e65b | |||
4e6327de1d | |||
b3d8666db0 | |||
d1da75d315 | |||
1de7c3d033 | |||
767d822cbf | |||
b4977f1515 | |||
6c589affe7 | |||
cb9db792a6 | |||
04990eeba4 | |||
772f8598dd | |||
95439f5e9c | |||
36c32e9832 | |||
660e8b5b73 | |||
5d442a287f | |||
962b258cc6 | |||
59697cab63 | |||
984538555c | |||
0ccbebee7a | |||
9f9bec38e1 | |||
d1474c0691 | |||
673137be8b | |||
180dafb84c | |||
2553da3dc4 | |||
a7ecf7af90 | |||
ff1adbd346 | |||
32f39c2fb8 | |||
923330aadd | |||
c87414e462 | |||
dbfd2808ba | |||
3c18cac134 | |||
4841d62d76 | |||
e5aa8b9d3f | |||
a1d6cefdf8 | |||
d532f3f304 | |||
349af05da8 | |||
29771c7d23 | |||
cb0914ecb0 | |||
b3b3cf0689 | |||
672dd5a868 | |||
cbe85cbeaf | |||
6731e3542d | |||
5d59234f8d | |||
5a6aebfcb2 | |||
96af23f370 | |||
4e6b6a8902 | |||
bafc50fd5c | |||
4f7b423f36 | |||
f7043bf690 | |||
1297499d7a | |||
bd0baa961c | |||
4ee536f044 | |||
8581bec891 | |||
8bcbc8eeb3 | |||
c164ef5489 | |||
cc3653cfd9 | |||
c03324ec9c | |||
7fc65067cf | |||
f9ae882012 | |||
1d80a68f4c | |||
1a9247b77f | |||
22e30d5ea7 | |||
b4f918b889 | |||
7b54e5c4ab | |||
c4d1c458a2 | |||
fda69354db | |||
7aa1d8ac2a | |||
b6fdf611f6 | |||
c0bad7ab23 | |||
d7a3c7522b | |||
4dfde7393b | |||
32c1f0c8d4 | |||
eb67eab122 | |||
d88e46d2d1 | |||
caa6236f1f | |||
f459f77335 | |||
66c58217af | |||
8f07f40f22 | |||
e6a2e27e33 | |||
8577d3ff41 | |||
78054a5352 | |||
ce0b5bf4ab | |||
9936946eb5 | |||
013b12a864 | |||
2f04c172fe | |||
cc5c4d38bb | |||
648fe052db | |||
55aa70c88a | |||
aa7ebdc9ce | |||
9c98783917 | |||
4b8ba29cdb | |||
4749776984 | |||
47ee50072e | |||
198c884158 | |||
1d945d8ce3 | |||
2d3a56f0d3 | |||
bfd05772ef | |||
9a16a8fd06 | |||
2ea19aeac0 | |||
0794ebf5fa | |||
a8ba00b250 | |||
26d50ebcd5 | |||
0fa0c25fb3 | |||
0694245ccd | |||
c1194b3d1e | |||
16baf5e16a | |||
55eafadf02 | |||
51c74eebd0 | |||
5edcf3910d | |||
abda6f148c | |||
f7333ebe58 | |||
6b2f639095 | |||
bb6781a3b1 | |||
b821b14987 | |||
56b3f119c0 | |||
4ee1776ceb | |||
90204bd0c8 | |||
2d7192e390 | |||
1e09a8e5ff | |||
85a45ccf6a | |||
d35a58e05c | |||
5605678bab | |||
ecbe7bf8d7 | |||
1e4146aec5 | |||
3990120813 | |||
fa84205e31 | |||
6dd9f05ea1 | |||
ab3820890b | |||
8e8ef83875 | |||
ed6abced5b | |||
2904002008 | |||
eccf0b9903 | |||
a8646f94ab | |||
71bbd70a57 | |||
6af3affee2 | |||
b0ab78a767 | |||
2055b83c34 | |||
e00da070fd | |||
b8e8061787 | |||
bdce34676a | |||
8f54ba10aa | |||
8db844a8d0 | |||
3b7d7861e3 | |||
f71b7e89e0 | |||
f7a19d37c6 | |||
c027a14b9b | |||
f91d0d6d65 | |||
4ce9a5c894 | |||
7191b08903 | |||
3534bd8a64 | |||
cdbd333c9b | |||
a1f7a3c17b | |||
76c92fc706 | |||
9b56221b5c | |||
3b99ce71a0 | |||
5f4cc50ce7 | |||
96b0edf9b0 | |||
9e7d96ea50 | |||
faa53de893 | |||
b930fc5d9d | |||
979faf853a | |||
aaee3a8b61 | |||
036c6a9a52 | |||
b3d287815d | |||
fda7e096cd | |||
57677a50b5 | |||
6f17695891 | |||
6ebc97dec2 | |||
56c8987e0f | |||
7ae4ca88b6 | |||
f0d469f1d4 | |||
6b4fee88c9 | |||
672fa852b3 | |||
0b412cd6b3 | |||
ae9f4135c0 | |||
2794556eaa | |||
a26c42a9b6 | |||
331ccd544f | |||
d6b1ff932a | |||
26b1f022b7 | |||
ab307c8d38 | |||
a3d4794341 | |||
25c7d8ead6 | |||
2834d71a12 | |||
bf9b6d8088 | |||
d9cff4238d | |||
198a36b744 | |||
f259992b4b | |||
ca8d311c78 | |||
acc035dbef | |||
5e33b8536b | |||
74bb2af3e1 | |||
b20c4047d4 | |||
4e2d3ceaaf | |||
82cf6caba4 | |||
bc3f820227 | |||
12d80c2732 | |||
6c0ce95d0f | |||
750502c870 | |||
df63490266 | |||
c9c6bd4836 | |||
d90420ac4c | |||
7c8504ea24 | |||
94687a7603 | |||
e1be8f61fc | |||
3d252a9797 | |||
45683a53c9 | |||
c4c4d82bf4 | |||
4ed79614ac | |||
73f6a57b12 | |||
260ff99710 | |||
fcc1cd3d57 | |||
08014c6a98 | |||
5da2ab1b7d | |||
d0be193307 | |||
b3fb106cce | |||
66cedf0b3a | |||
707a4ebc15 | |||
46d2efca13 | |||
d95375d494 | |||
1c1c58e802 | |||
7fe05b8296 | |||
17ef531905 | |||
24cd1b591c | |||
bb9e6731ea | |||
5dd5a89775 | |||
b8e2bdd6b1 | |||
88817a8f10 | |||
3e8ce43dcb | |||
9d8845d7ad | |||
2f91aca897 | |||
35c3622405 | |||
52578ba483 | |||
991a4801b1 | |||
02b2c55146 | |||
0abe753003 | |||
487fafbca3 | |||
188a352c6f | |||
e11b400a75 | |||
6db5692be4 | |||
8ab7b27d4f | |||
ead4029d49 | |||
9e76fb2231 | |||
9c7d2ab8f2 | |||
9bd408449e | |||
739425431a | |||
dda6554990 | |||
2f43cc353b | |||
2b7390c2a1 | |||
ab961a78cb | |||
65c639cf13 | |||
0cf5dc11e3 | |||
ceea7e5aeb | |||
579814895d | |||
b873fa7a5f | |||
ee563ecf4e | |||
183b35d683 | |||
463dd48180 | |||
1bd3fdd912 | |||
7655b070df | |||
1355a5dd33 | |||
f62e3119c4 | |||
828585a312 | |||
ef4af443a5 | |||
1a3e1e0959 | |||
40004e64a6 | |||
50dc0ad207 | |||
3da4f02ffa | |||
8a2bba4efb | |||
1ba80224ad | |||
bf19918e3c | |||
38fef28c84 | |||
273f964293 | |||
d2577acccd | |||
d92e661253 | |||
de71cbdd43 | |||
c9b87c4c03 | |||
38848082ae | |||
b6728efcd4 | |||
cd814851da | |||
6646daab45 | |||
ba483155d7 | |||
63abe1cb3e | |||
28db8022fe | |||
7dcc08985c | |||
55acdaaf8c | |||
575c07c9c4 | |||
325f45fa66 | |||
bc682066d8 | |||
0a1cdc5107 | |||
6984185e61 | |||
5826126284 | |||
cb11f042ab | |||
b82a4869d5 | |||
c2be740ad4 | |||
61258d03ad | |||
79a05d63c8 | |||
762e528ec5 | |||
c3de9848b4 | |||
370ae8c20c | |||
18752672d0 | |||
69083bfca0 | |||
cdc37bb142 | |||
083dcd4541 | |||
b6f00d07e8 | |||
b0ffaf1c91 | |||
2af61bd07e | |||
1caae90c02 | |||
184125a70a | |||
7cac5bb633 | |||
53314cb8b2 | |||
b5e287e065 | |||
1e15f26e98 | |||
23ba01d89c | |||
2eeceae613 | |||
653cbe651f | |||
f3e487e829 | |||
9c016ad479 | |||
e602647d4d | |||
9696e4d315 | |||
7f7af2bbaa | |||
b190051e15 | |||
83b28cad8d | |||
ea42a84a4a | |||
e4c282f0a6 | |||
d54d7cc431 | |||
111477aa74 | |||
226739d13f | |||
f1ee9113ac | |||
9120a64cfb | |||
fcd624a722 | |||
e6af7f75a1 | |||
27f1e7b60c | |||
2e24de7f47 | |||
e514204db0 | |||
a8366ebf15 | |||
ad48387aa0 | |||
a4bcc1ff3d | |||
fca3a6b75e | |||
6fcdc76059 | |||
0f9e55dac6 | |||
5d7677dd07 | |||
57073cc6cf | |||
f9f39c0a1c | |||
3eefa6dec8 | |||
8c6feb7e80 | |||
37f8ff0efc | |||
d88d7f26e4 | |||
aeaedd2e5e | |||
1f4ef3b606 | |||
9b5db297a6 | |||
07c22c7e81 | |||
1ac0c0bfc5 | |||
c25209eb34 | |||
b7215b5dde | |||
411435d68f | |||
f656f906ff | |||
d0a7363e64 | |||
7401fa2fa5 | |||
4deed7c836 | |||
92f72b4103 | |||
30f54626d3 | |||
3a8206d1fb | |||
6b0b8744c1 | |||
0b8352049c | |||
c03f700662 | |||
d08f2e73d0 | |||
aa7f23e1e1 | |||
4249c5b3e0 | |||
6f1a5c8e02 | |||
03a93bd089 | |||
6aef00ecff | |||
949c6a5932 | |||
7922bb4020 | |||
697bf16f26 | |||
181ee1dade | |||
3645a0f0e4 | |||
2864eaebae | |||
37612345f2 | |||
bb218b824e | |||
279329bfaa | |||
71f4ea9d76 | |||
1881a297c9 | |||
56c7a99eb4 | |||
3262ffc1a6 | |||
5bc7a1f435 | |||
11cb5ed10e | |||
9916f35b22 | |||
0a6f62bc0e | |||
bc974a3e7d | |||
1aa70c50aa | |||
134b45dc03 | |||
2b80f40164 | |||
70215fe480 | |||
96c0b933d9 | |||
7b51c5c49f | |||
eac02b55f6 | |||
5d4ae4a2a4 | |||
04cbef3aa8 | |||
e540f0ad26 | |||
69fa040361 | |||
720217a5e4 | |||
1911aad57f | |||
1943071d12 | |||
08c624576c | |||
a99a2ce7e8 | |||
56855f9791 | |||
b32979bc84 | |||
651d425046 | |||
d1df9b9e38 | |||
bf1a23afcf | |||
04a6a4f860 | |||
f603b7ef8b | |||
b8c3a10e5b | |||
cab181832f | |||
af2b2c668d | |||
c94c87eec0 | |||
666bee61f7 | |||
a6e0f0bb74 | |||
03ce896f6f | |||
80e0cd4e00 | |||
049477a9bd | |||
d644a8d41f | |||
e0c2074ed5 | |||
d8bf48e692 | |||
a91efc3cbd | |||
fb42c94b79 | |||
ba2e3d94eb | |||
4ef65f0983 | |||
2675ad9304 | |||
c1240f214c | |||
7f3eab418f | |||
4e13c339ec | |||
9a1e1d5b1e | |||
4f89ed5d66 | |||
17008bb648 | |||
43fd0b6ae9 | |||
bb5ab5d16c | |||
e3abadd686 | |||
c36d356f4e | |||
e8c06b7152 | |||
3cc0ea5ff9 | |||
333335c366 | |||
08306f0db8 | |||
3d2e227f11 | |||
29d2449fb3 | |||
008bdfa43f | |||
1d0483c946 | |||
7cb9fddc11 | |||
989062d2f8 | |||
c2f78aaf88 | |||
8f39f4580a | |||
6202c67fe8 | |||
0c82c1920e | |||
a2dc4199d0 | |||
b1970f79ee | |||
6cdd8a2b07 | |||
4ed615cfcc | |||
91da4e3168 | |||
596062ccab | |||
93b5f3f421 | |||
cac2875c96 | |||
a3f119e0bd | |||
6ba40773bb | |||
19c79f0a73 | |||
e58faeb66a | |||
3a3d80826c | |||
49c93e5b9e | |||
3f2a99a936 | |||
62eae9b470 | |||
a1aae8ca38 | |||
104cf5b51b | |||
4fe9d8a007 | |||
edbc828fc3 | |||
03c9eaf005 | |||
2b021472d6 | |||
55cab9eb4f | |||
b39dda0550 | |||
7c0a52a81e | |||
318d13ed58 | |||
21a3ceee92 | |||
a8f6a13239 | |||
b9f1371994 | |||
51c685aa99 | |||
9e39284de9 | |||
26899bc0f0 | |||
a74d05061d | |||
4140834e4c | |||
bd44bcee32 | |||
1e4678f929 | |||
fe5055cf29 | |||
d9d956e54f | |||
6c2c16a971 | |||
955a5ed8fb | |||
a59414203f | |||
631b067281 | |||
02bac0a326 | |||
7c8fb060f1 | |||
04c0e94349 | |||
2a946af81e | |||
18be6768c9 | |||
fbe61a06f6 | |||
7a4d6d64fd | |||
0eae9c49b0 | |||
d0bca1fb0f | |||
7c7e5112ea | |||
ec96e85d04 | |||
d60d71a697 | |||
6f0dd8e885 | |||
de99e35106 | |||
774be79321 | |||
721f704260 | |||
2846e3f5d9 | |||
b9ca3b2039 | |||
8ac572ed27 | |||
c4163c3621 | |||
1d7c909080 | |||
500683831c | |||
9a2fe7ec0c | |||
3ae3e3d23d | |||
fc07e849fe | |||
fadcdde7f8 | |||
d056bf070f | |||
2591050fbe | |||
e8dfd4ba39 | |||
383e874166 | |||
e8a2250ef8 | |||
440e12abc4 | |||
25ba6ea459 | |||
5ec226a416 | |||
a021b99614 | |||
e9de4c08b0 | |||
2e968d2557 | |||
bc6fa85a4b | |||
4e6c2c0fa1 | |||
7eadbd938d | |||
31a5de973d | |||
94fc8a1334 | |||
aa1cd7eba6 | |||
16faafb7a8 | |||
e376c2d0d4 | |||
c4dc61425d | |||
128f5bce30 | |||
82d69305b6 | |||
57a009b8e6 | |||
a2e6f5ebdb | |||
995dbd25b3 | |||
1d0d0425d4 | |||
51890baace | |||
4bca36f479 | |||
7d78f40bf6 | |||
131b5b56d7 | |||
fcd94efbd6 | |||
13257004bc | |||
8b193db0cb | |||
5537dce3cc | |||
fd5da62c66 | |||
927578a26f | |||
290c712cde | |||
2486492c4d | |||
7bf10b980c | |||
55c243a17b | |||
df526f73be | |||
29a77fd6ae | |||
be9ebd9e18 | |||
01f1208ad1 | |||
9dbb3e80fe | |||
a5c14ba7d4 | |||
4b11b283ac | |||
6fdfc84904 | |||
bff81f24aa | |||
ed515cbc0c | |||
87a6d7166c | |||
55baee9a9a | |||
0886afe650 | |||
872f6166e1 | |||
fe348e236f | |||
e0f083d117 | |||
48171f8e24 | |||
bcdf74562b | |||
3a5ee1aed0 | |||
d8c4b9c4fb | |||
6ae7884786 | |||
41834d16d6 | |||
1ee51f2afa | |||
65ee7aa372 | |||
ac38ee82f4 | |||
5fcc7f2328 | |||
3bcc2aad80 | |||
6165b6ae77 | |||
e335e4fddc | |||
5ab4199d71 | |||
f075e2459d | |||
94a26abf21 | |||
bcbdc33049 | |||
21ef3895b3 | |||
3e99dc01b0 | |||
3e325a1974 | |||
2b92e3e8a7 | |||
cb90b90cbf | |||
9776a252ee | |||
751de20f93 | |||
28388b4e3a | |||
4fdbf30308 | |||
722f191e82 | |||
20f6114617 | |||
3075e2cfbf | |||
e2973d2176 | |||
0ff08bb63a | |||
08c0bf52bc | |||
d0229cb96e | |||
0612e5ccfb | |||
1b4f7b34c8 | |||
86e6fcd309 | |||
dc9cd7d8b9 | |||
c0cc9ce7cd | |||
be2f66397b | |||
07760b4129 | |||
d79a3130b8 | |||
440a589f9e | |||
f5fcf9d635 | |||
9b8b1bad57 | |||
874ecd6c88 | |||
57e2fec497 | |||
0905a2c3a2 | |||
3aa00b78f9 | |||
6769d46dbb | |||
efac712f62 | |||
2bb23c57df | |||
bc699a2cc1 | |||
758c128147 | |||
3795c2a39d | |||
311c0e3f50 | |||
25a8caa9b0 | |||
c80a9585b0 | |||
e73491441a | |||
b93b80ccaa | |||
48128c9db6 | |||
6dafaa197d | |||
1634d8e087 | |||
7a583083b8 | |||
75156ab0c9 | |||
9fd6923821 | |||
91a929b2a9 | |||
0f8e31af06 | |||
bd71c2f34d | |||
001123dbd6 | |||
cfee151d4e | |||
fc59291191 | |||
4fc05cac56 | |||
cc4616f25b | |||
e82fbb7bcf | |||
8cd639f6a2 | |||
a8f555856a | |||
3792562046 | |||
d05c48a1d7 | |||
36cc5eb933 | |||
f9f74a0f7d | |||
77f42931ff | |||
73f62266c6 | |||
df2f3d25b0 | |||
599c43ce04 | |||
5c2199e7f4 | |||
3ad4e0348f | |||
02d5729941 | |||
ce35689d2e | |||
da81e21bf2 | |||
3b2ed7631f | |||
1a46e70dfb | |||
0fc9b6cfa2 | |||
61768aa2fd | |||
ea5bf9db36 | |||
9d24afcfe3 | |||
033df9457b | |||
d8e105fe34 | |||
d34068da18 | |||
611103d211 | |||
528c1c5fd8 | |||
f73732bf1e | |||
fd7875e572 | |||
e8bc319f08 | |||
a92ff57270 | |||
004230d02d | |||
a148c640b2 | |||
ea0205f2ff | |||
005649b6fc | |||
e09e3b01d6 | |||
fc15e0e27d | |||
b2fe5fabb1 | |||
52d69bb021 | |||
5f550a355b | |||
dbecbdccd4 | |||
734877338d | |||
2e439ca77f | |||
a853880e07 | |||
93f3ed98e1 | |||
a131eddf54 | |||
b19a7aa8a6 | |||
f5aa53c530 | |||
80f5e14512 | |||
41390cd963 | |||
0b5e131410 | |||
556596bce8 | |||
b791d1ab0d | |||
ac070ae942 | |||
111ad868a7 | |||
a7274115d0 | |||
81160bcefb | |||
2880109f31 | |||
09a1f5acb9 | |||
5fcf11fcb0 | |||
42fac722bb | |||
073e5727c6 | |||
ad1c4f5e39 | |||
dc8a68c98f | |||
e5621dea58 | |||
00acf22f5f | |||
4c09716ad8 | |||
1c941557c3 | |||
28e1a7915d | |||
4bc9d9fd3b | |||
e278ca61d1 | |||
2146ede15d | |||
e737222a5d | |||
f03f1949bf | |||
0fe6c7c558 | |||
b13202bbfc | |||
90fae903ce | |||
06b154f4b2 | |||
419a0665c8 | |||
387098fc87 | |||
c42b588782 | |||
4faaa5310e | |||
c448abd44e | |||
2517588d7d | |||
8fc8fc89aa | |||
b243b3ee1d | |||
28e08afada | |||
7e184b58b2 | |||
589fc0b8ad | |||
f0c7c1b500 | |||
840bd98e01 | |||
a5cdd22bfe | |||
0c7bcae9b1 | |||
ab666c170c | |||
d2213d18fa | |||
82b6300dcb | |||
b69cda9e07 | |||
56adc7c3c6 | |||
2ace20fade | |||
c13fe83784 | |||
6cf8df8685 | |||
86a89404be | |||
0d305d7c3e | |||
ee5bd2b4b3 | |||
22ae962b57 | |||
864139d67f | |||
1dc7e00d20 | |||
49a9107e0f | |||
7b8c2c232f | |||
15e1e6376b | |||
06d9d9ed08 | |||
74e10d6f72 | |||
d43489a6a0 | |||
983de8974b | |||
c91a1ec08d | |||
507de45d40 | |||
fe0fc8d5e1 | |||
e4a8db56f9 | |||
1d1ec4727a | |||
0b71e45072 | |||
9c375b33a6 | |||
28a6a5ea57 | |||
f83ff0e47d | |||
079e575cac | |||
6b2327f231 | |||
596608aa0c | |||
120e80d1b6 | |||
aa6c6120f6 | |||
19d5f782cc | |||
84169a91ff | |||
d1c48cdcf9 | |||
dfe95d3ae6 | |||
57ebec385f | |||
7a77910720 | |||
23d8dc959c | |||
7f303a856e | |||
e834e617f3 | |||
2c89a228d5 | |||
803826cdcd | |||
42d18d2294 | |||
b5ae024cc8 | |||
5968811441 | |||
fc59c87606 | |||
7dc1d6a350 | |||
deff1aa63b | |||
08e7d0dfb6 | |||
892aae267d | |||
11a9144e84 | |||
039f223b53 | |||
e1cb026184 | |||
2a96152a43 | |||
0795d56c1c | |||
48a90fea70 | |||
b202951c1d | |||
c3d2c61729 | |||
d7b707939f | |||
991ac6eb77 | |||
011b7c4a07 | |||
617341f8d5 | |||
abd2632977 | |||
5481db4079 | |||
041086d22a | |||
aa564f5072 | |||
8367f2001c | |||
1cfb228924 | |||
b403fb1275 | |||
3443ca40c5 | |||
96f95653a6 | |||
7f7e8465da | |||
e3a273cf73 | |||
233161d56e | |||
d883ab250a | |||
ef4e3f907c | |||
debeadbf3f | |||
d66baaceb9 | |||
85329f9a81 | |||
a5fefaf78b | |||
6f17662a4e | |||
c83aea3c89 | |||
67aaf4cb2d | |||
3083346884 | |||
d07789677f | |||
fb1846120d | |||
da1e1295ea | |||
ecaea57263 | |||
fa928bd25d | |||
c1981dfc26 | |||
fd41fa31d5 | |||
2c52144f41 | |||
87c7898b65 | |||
44e088c6fe | |||
7b4cbd7ce9 | |||
b052d524da | |||
47c4b8e88a | |||
d0a2a02eea | |||
b1e1dab4cb | |||
388973e9ab | |||
2129ec7558 | |||
82f122525c | |||
7c4c00f1e6 | |||
fe6c7dc10a | |||
9bc24e3b12 | |||
833baca66e | |||
9fd92512a2 | |||
b692ca7896 | |||
52dc04a35a | |||
42b1287759 | |||
5a471aa1d0 | |||
a4b8d4a098 | |||
a3be6affa4 | |||
71b99edd48 | |||
64553ddcb7 | |||
2a42482ae9 | |||
11f345a8ae | |||
fec50d8cfe | |||
05e42381df | |||
b435075e09 | |||
430da53f0b | |||
2e6d836dd1 | |||
899d324a9c | |||
576ed6a906 | |||
d744cf8437 | |||
088e662285 | |||
f9b0b81eb2 | |||
c5485c6501 | |||
d8ed01400f | |||
ebc4694e05 | |||
a9441d670e | |||
495d2ebd70 | |||
ad26adc3e3 | |||
63a62e19f9 | |||
4f2ae34df9 | |||
a636f161a4 | |||
dfb1e22559 | |||
dff85a7f70 | |||
3be198d2f5 | |||
d19314fe3a | |||
d06f457b2a | |||
7d07881d96 | |||
3e6e3a207c | |||
481c6d4511 | |||
231a445809 | |||
93e8f6c05e | |||
9de2144fc4 | |||
363dc51ba0 | |||
99117ff2ef | |||
5356cb9fbd | |||
0e13d9fbaa | |||
2dcb16870b | |||
ac9909112f | |||
eb3c2c9e76 | |||
3d29e3efbf | |||
f410fb6689 | |||
eb62fd466e | |||
b50cdd6de8 | |||
f38e2b5c6d | |||
455915ec9e | |||
2333158256 | |||
3ffa804088 | |||
98810d22b1 | |||
5e72b2a797 | |||
7e4e7fa4a6 | |||
d297199d7c | |||
17a433996e | |||
b9bb4692a4 | |||
d05dcdda02 | |||
27fe356214 | |||
fc44df1e45 | |||
77f915befe | |||
a5f7600f6f | |||
7eb8634ad7 | |||
452d8c06e9 | |||
48f535f02e | |||
43c10b0625 | |||
328b09fe04 | |||
15d49e4096 | |||
3ef53fe2cd | |||
7d8e759e98 | |||
69b3be61a4 | |||
79476a5cb2 | |||
f449baf8de | |||
5ff4bcfb7a | |||
98537ce8b7 | |||
d2a00a2daa | |||
f22938fc4a | |||
1e67ae8e94 | |||
c012d648fb | |||
67acaae53c | |||
e3da546e23 | |||
e5b136f70d | |||
058ef69da3 | |||
2a483531a4 | |||
05202671db | |||
8509873043 | |||
57a2d695e2 | |||
0b5ab1ef22 | |||
2eac79569c | |||
ac578b8491 | |||
5183fd25bb | |||
10f5a8ef78 | |||
a30837298d | |||
f377a3a7b4 | |||
83c874666a | |||
e000ed47cd | |||
af2f064f42 | |||
9c7b25134b | |||
2d15df9e6c | |||
d2ab287756 | |||
e73278990c | |||
12bc92df35 | |||
f19a801022 | |||
b193303aa3 | |||
e299e76fcf | |||
c857e18c4a | |||
5fb3df4054 | |||
8b597187fc | |||
930f9f0063 | |||
63d4df9810 | |||
13ba533fc4 | |||
6d60bab2fd | |||
5be774b2e5 | |||
b412ff92c0 | |||
5a75e11b0e | |||
e66bf70589 | |||
3924e9d50a | |||
8df748463d | |||
0113661c81 | |||
0ee054b14d | |||
80b39454ff | |||
97f3671e2c | |||
b674cee9d2 | |||
cb8491cfee | |||
8196b031f8 | |||
50dd56d3c4 | |||
0f7e1d4d01 | |||
ec77c572b9 | |||
f97561c416 | |||
5faa82e323 | |||
4e17292a12 | |||
666fbbb0d1 | |||
c6fe58467b | |||
46d1938f5c | |||
8229af7591 | |||
ee76523507 | |||
c283db373b | |||
1b0ed30516 | |||
a6fdee4a51 | |||
6951fb440c | |||
502c9ea706 | |||
22f67be461 | |||
77ffd06715 | |||
1d833ef972 | |||
0d8064ed2d | |||
cc06ea4d87 | |||
3cf7652e86 | |||
1eb28c6cb6 | |||
db590369a8 | |||
f4d654d2a2 | |||
5725e55abb | |||
b6d19cc9fa | |||
bc6c884a14 | |||
cb78bf8fd6 | |||
400bc97e35 | |||
2fd464bf7b | |||
e626522b3a | |||
791e07650d | |||
bf2363947b | |||
a2cc2259e7 | |||
808fe496a6 | |||
2fb48bd6ac | |||
2df8775b48 | |||
e02b4f1443 | |||
194782215f | |||
df17d28c0f | |||
5f43c8f024 | |||
1a18734f9a | |||
4a70c1ff4f | |||
770e5d89f2 | |||
cfac8e84dd | |||
43d90c1745 | |||
38bdb053d2 | |||
95e61773a5 | |||
4e931fa73f | |||
2573441e28 | |||
5770b15270 | |||
6817b472d0 | |||
2b076369e0 | |||
973a8ee8f3 | |||
1159d3365a | |||
152ba32eb7 | |||
153320ef33 | |||
ff236da72c | |||
54326869e4 | |||
f14f4e39c5 | |||
a18b2702ca | |||
93410c470e | |||
5d945ef869 | |||
df07be6a42 | |||
3c32d4947c | |||
2ea5235aea | |||
c096f031ce | |||
ae1d4bdb4c | |||
0adf2accdd | |||
4201f48be5 | |||
b076e375ca | |||
2f1016d44f | |||
ddf9d61346 | |||
f0b7ab5ecc | |||
e4c6336bd4 | |||
66061192f8 | |||
b7bc4c1f80 | |||
a56abb6502 | |||
892a416211 | |||
f45adecd01 | |||
bd015e82dc | |||
cf43b74f26 | |||
18909ec14a | |||
ed243c88d2 | |||
cb7723f423 | |||
9dc88f8a95 | |||
0a439fe52f | |||
a8b65e35ec | |||
bd9e598bf0 | |||
75f8247af1 | |||
e8ec5027ff |
@ -1,82 +0,0 @@
|
||||
trigger:
|
||||
- main
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
linux-stable:
|
||||
image: ubuntu-18.04
|
||||
style: 'unflagged'
|
||||
linux-minimal:
|
||||
image: ubuntu-18.04
|
||||
style: 'minimal'
|
||||
linux-extra:
|
||||
image: ubuntu-18.04
|
||||
style: 'extra'
|
||||
linux-wasm:
|
||||
image: ubuntu-18.04
|
||||
style: 'wasm'
|
||||
macos-stable:
|
||||
image: macos-10.14
|
||||
style: 'unflagged'
|
||||
windows-stable:
|
||||
image: windows-2019
|
||||
style: 'unflagged'
|
||||
linux-nightly-canary:
|
||||
image: ubuntu-18.04
|
||||
style: 'canary'
|
||||
macos-nightly-canary:
|
||||
image: macos-10.14
|
||||
style: 'canary'
|
||||
windows-nightly-canary:
|
||||
image: windows-2019
|
||||
style: 'canary'
|
||||
fmt:
|
||||
image: ubuntu-18.04
|
||||
style: 'fmt'
|
||||
|
||||
pool:
|
||||
vmImage: $(image)
|
||||
|
||||
steps:
|
||||
- bash: |
|
||||
set -e
|
||||
if [ -e /etc/debian_version ]
|
||||
then
|
||||
sudo apt-get -y install libxcb-composite0-dev libx11-dev
|
||||
sudo npm install -g wasm-pack
|
||||
fi
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y --no-modify-path --default-toolchain "stable"
|
||||
echo "Installing clippy"
|
||||
rustup component add clippy --toolchain stable-x86_64-apple-darwin
|
||||
export PATH=$HOME/.cargo/bin:$PATH
|
||||
fi
|
||||
# rustup update
|
||||
# rustc -Vv
|
||||
# echo "##vso[task.prependpath]$HOME/.cargo/bin"
|
||||
# rustup component add rustfmt
|
||||
displayName: Install Rust
|
||||
- bash: RUSTFLAGS="-D warnings" cargo test --all
|
||||
condition: eq(variables['style'], 'unflagged')
|
||||
displayName: Run tests
|
||||
- bash: RUSTFLAGS="-D warnings" cargo clippy --all -- -D clippy::unwrap_used
|
||||
condition: eq(variables['style'], 'unflagged')
|
||||
displayName: Check clippy lints
|
||||
- bash: RUSTFLAGS="-D warnings" cargo test --all
|
||||
condition: eq(variables['style'], 'canary')
|
||||
displayName: Run tests
|
||||
- bash: cd samples/wasm && wasm-pack build
|
||||
condition: eq(variables['style'], 'wasm')
|
||||
displayName: Wasm build
|
||||
- bash: RUSTFLAGS="-D warnings" cargo clippy --all -- -D clippy::unwrap_used
|
||||
condition: eq(variables['style'], 'canary')
|
||||
displayName: Check clippy lints
|
||||
- bash: RUSTFLAGS="-D warnings" cargo test --all --no-default-features --features=rustyline-support
|
||||
condition: eq(variables['style'], 'minimal')
|
||||
displayName: Run tests
|
||||
- bash: RUSTFLAGS="-D warnings" cargo test --all --features=extra
|
||||
condition: eq(variables['style'], 'extra')
|
||||
displayName: Run tests
|
||||
- bash: cargo fmt --all -- --check
|
||||
condition: eq(variables['style'], 'fmt')
|
||||
displayName: Lint
|
13
.cargo/config.toml
Normal file
@ -0,0 +1,13 @@
|
||||
# increase the default windows stack size
|
||||
[target.x86_64-pc-windows-msvc]
|
||||
rustflags = ["-C", "link-args=-stack:10000000"]
|
||||
|
||||
# keeping this but commentting out in case we need them in the future
|
||||
|
||||
# set a 2 gb stack size (0x80000000 = 2147483648 bytes = 2 GB)
|
||||
# [target.x86_64-unknown-linux-gnu]
|
||||
# rustflags = ["-C", "link-args=-Wl,-z stack-size=0x80000000"]
|
||||
|
||||
# set a 2 gb stack size (0x80000000 = 2147483648 bytes = 2 GB)
|
||||
# [target.x86_64-apple-darwin]
|
||||
# rustflags = ["-C", "link-args=-Wl,-stack_size,0x80000000"]
|
@ -1,165 +0,0 @@
|
||||
# CircleCI 2.0 configuration file
|
||||
#
|
||||
# Check https://circleci.com/docs/2.0/configuration-reference/ for more details
|
||||
# See https://circleci.com/docs/2.0/config-intro/#section=configuration for spec
|
||||
#
|
||||
version: 2.1
|
||||
|
||||
# Commands
|
||||
|
||||
commands:
|
||||
|
||||
pull_cache:
|
||||
description: Pulls Quay.io docker images (latest) for our cache
|
||||
parameters:
|
||||
tag:
|
||||
type: string
|
||||
default: "devel"
|
||||
steps:
|
||||
- run: echo "Tag is << parameters.tag >>"
|
||||
- run: docker pull quay.io/nushell/nu:<< parameters.tag >>
|
||||
- run: docker pull quay.io/nushell/nu-base:<< parameters.tag >>
|
||||
|
||||
orbs:
|
||||
# https://circleci.com/orbs/registry/orb/circleci/docker
|
||||
docker: circleci/docker@0.5.13
|
||||
|
||||
workflows:
|
||||
version: 2.0
|
||||
|
||||
# This builds on all pull requests to test, and ignores main
|
||||
build_without_deploy:
|
||||
jobs:
|
||||
- docker/publish:
|
||||
deploy: false
|
||||
image: nushell/nu-base
|
||||
tag: latest
|
||||
dockerfile: docker/Dockerfile.nu-base
|
||||
extra_build_args: --cache-from=quay.io/nushell/nu-base:devel
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- main
|
||||
before_build:
|
||||
- pull_cache
|
||||
after_build:
|
||||
- run:
|
||||
name: Build Multistage (smaller) container
|
||||
command: |
|
||||
docker build -f docker/Dockerfile -t quay.io/nushell/nu .
|
||||
- run:
|
||||
name: Preview Docker Tag for Nushell Build
|
||||
command: |
|
||||
DOCKER_TAG=$(docker run quay.io/nushell/nu --version | cut -d' ' -f2)
|
||||
echo "Version that would be used for Docker tag is v${DOCKER_TAG}"
|
||||
- run:
|
||||
name: Test Executable
|
||||
command: |
|
||||
docker run --rm quay.io/nushell/nu-base --help
|
||||
docker run --rm quay.io/nushell/nu --help
|
||||
|
||||
# workflow publishes to Docker Hub, with each job having different triggers
|
||||
build_with_deploy:
|
||||
jobs:
|
||||
|
||||
# Deploy versioned and latest images on tags (releases) only - builds --release.
|
||||
- docker/publish:
|
||||
image: nushell/nu-base
|
||||
registry: quay.io
|
||||
tag: latest
|
||||
dockerfile: docker/Dockerfile.nu-base
|
||||
extra_build_args: --cache-from=quay.io/nushell/nu-base:latest,quay.io/nushell/nu:latest --build-arg RELEASE=true
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /^\d+\.\d+\.\d+$/
|
||||
before_build:
|
||||
- run: docker pull quay.io/nushell/nu:latest
|
||||
- run: docker pull quay.io/nushell/nu-base:latest
|
||||
after_build:
|
||||
- run:
|
||||
name: Build Multistage (smaller) container
|
||||
command: |
|
||||
docker build -f docker/Dockerfile -t quay.io/nushell/nu .
|
||||
- run:
|
||||
name: Test Executable
|
||||
command: |
|
||||
docker run --rm quay.io/nushell/nu --help
|
||||
docker run --rm quay.io/nushell/nu-base --help
|
||||
- run:
|
||||
name: Publish Docker Tag with Nushell Version
|
||||
command: |
|
||||
DOCKER_TAG=$(docker run quay.io/nushell/nu --version | cut -d' ' -f2)
|
||||
echo "Version for Docker tag is ${DOCKER_TAG}"
|
||||
docker tag quay.io/nushell/nu-base:latest quay.io/nushell/nu-base:${DOCKER_TAG}
|
||||
docker tag quay.io/nushell/nu:latest quay.io/nushell/nu:${DOCKER_TAG}
|
||||
docker push quay.io/nushell/nu-base
|
||||
docker push quay.io/nushell/nu
|
||||
|
||||
|
||||
# publish devel to Docker Hub on merge to main (doesn't build --release)
|
||||
build_with_deploy_devel:
|
||||
jobs:
|
||||
|
||||
# Deploy devel tag on merge to main
|
||||
- docker/publish:
|
||||
image: nushell/nu-base
|
||||
registry: quay.io
|
||||
tag: devel
|
||||
dockerfile: docker/Dockerfile.nu-base
|
||||
extra_build_args: --cache-from=quay.io/nushell/nu-base:devel
|
||||
before_build:
|
||||
- pull_cache
|
||||
filters:
|
||||
branches:
|
||||
only: main
|
||||
after_build:
|
||||
- run:
|
||||
name: Build Multistage (smaller) container
|
||||
command: |
|
||||
docker build --build-arg FROMTAG=devel -f docker/Dockerfile -t quay.io/nushell/nu:devel .
|
||||
- run:
|
||||
name: Test Executable
|
||||
command: |
|
||||
docker run --rm quay.io/nushell/nu:devel --help
|
||||
docker run --rm quay.io/nushell/nu-base:devel --help
|
||||
- run:
|
||||
name: Publish Development Docker Tags
|
||||
command: |
|
||||
docker push quay.io/nushell/nu-base:devel
|
||||
docker push quay.io/nushell/nu:devel
|
||||
|
||||
nightly:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "0 0 * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
jobs:
|
||||
- docker/publish:
|
||||
image: nushell/nu-base
|
||||
registry: quay.io
|
||||
tag: nightly
|
||||
dockerfile: docker/Dockerfile.nu-base
|
||||
extra_build_args: --cache-from=quay.io/nushell/nu-base:nightly --build-arg RELEASE=true
|
||||
before_build:
|
||||
- run: docker pull quay.io/nushell/nu:nightly
|
||||
- run: docker pull quay.io/nushell/nu-base:nightly
|
||||
after_build:
|
||||
- run:
|
||||
name: Build Multistage (smaller) container
|
||||
command: |
|
||||
docker build -f docker/Dockerfile -t quay.io/nushell/nu:nightly .
|
||||
- run:
|
||||
name: Test Executable
|
||||
command: |
|
||||
docker run --rm quay.io/nushell/nu:nightly --help
|
||||
docker run --rm quay.io/nushell/nu-base:nightly --help
|
||||
- run:
|
||||
name: Publish Nightly Nushell Containers
|
||||
command: |
|
||||
docker push quay.io/nushell/nu-base:nightly
|
||||
docker push quay.io/nushell/nu:nightly
|
@ -1 +0,0 @@
|
||||
target
|
@ -1,14 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = false
|
||||
end_of_line = lf
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,30 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Configuration (please complete the following information):**
|
||||
- OS (e.g. Windows):
|
||||
- Nu version (you can use the `version` command to find out):
|
||||
- Optional features (if any):
|
||||
|
||||
Add any other context about the problem here.
|
63
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
name: Bug Report
|
||||
description: Create a report to help us improve
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: Thank you for your bug report.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: How to reproduce
|
||||
description: Steps to reproduce the behavior
|
||||
placeholder: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
placeholder: I expected nu to...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: Please add any relevant screenshots here, if any
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: config
|
||||
attributes:
|
||||
label: Configuration
|
||||
description: "Please run `version | transpose key value | to md --pretty` and paste the output to show OS, features, etc."
|
||||
placeholder: |
|
||||
> version | transpose key value | to md --pretty
|
||||
| key | value |
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| version | 0.40.0 |
|
||||
| build_os | linux-x86_64 |
|
||||
| rust_version | rustc 1.56.1 |
|
||||
| cargo_version | cargo 1.56.0 |
|
||||
| pkg_version | 0.40.0 |
|
||||
| build_time | 1980-01-01 00:00:00 +00:00 |
|
||||
| build_rust_channel | release |
|
||||
| features | clipboard-cli, ctrlc, dataframe, default, rustyline, term, trash, uuid, which, zip |
|
||||
| installed_plugins | binaryview, chart bar, chart line, fetch, from bson, from sqlite, inc, match, post, ps, query json, s3, selector, start, sys, textview, to bson, to sqlite, tree, xpath |
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
validations:
|
||||
required: false
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
34
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
name: Feature Request
|
||||
description: "When you want a new feature for something that doesn't already exist"
|
||||
body:
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Related problem
|
||||
description: Thank you for your feature request.
|
||||
placeholder: |
|
||||
A clear and concise description of what the problem is.
|
||||
Example: I am trying to do [...] but [...]
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: desired
|
||||
attributes:
|
||||
label: "Describe the solution you'd like"
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: "Describe alternatives you've considered"
|
||||
description: "A clear and concise description of any alternative solutions or features you've considered."
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context and details
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
validations:
|
||||
required: false
|
11
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# Description
|
||||
|
||||
(description of your pull request here)
|
||||
|
||||
# Tests
|
||||
|
||||
Make sure you've run and fixed any issues with these commands:
|
||||
|
||||
- [ ] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes)
|
||||
- [ ] `cargo clippy --all --all-features -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style
|
||||
- [ ] `cargo build; cargo test --all --all-features` to check that all the tests pass
|
114
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
on: [pull_request]
|
||||
|
||||
name: Continuous integration
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [windows-latest, macos-latest, ubuntu-latest]
|
||||
style: [all, default, minimal]
|
||||
rust:
|
||||
- stable
|
||||
include:
|
||||
- style: all
|
||||
flags: '--all-features'
|
||||
- style: default
|
||||
flags: ''
|
||||
- style: minimal
|
||||
flags: '--no-default-features'
|
||||
exclude:
|
||||
- platform: windows-latest
|
||||
style: default
|
||||
- platform: windows-latest
|
||||
style: minimal
|
||||
- platform: macos-latest
|
||||
style: default
|
||||
- platform: macos-latest
|
||||
style: minimal
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Rustfmt
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --all ${{ matrix.flags }} -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
|
||||
|
||||
- name: Build Nushell
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: ${{ matrix.flags }}
|
||||
|
||||
- name: Tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all ${{ matrix.flags }}
|
||||
|
||||
|
||||
python-virtualenv:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||
rust:
|
||||
- stable
|
||||
py:
|
||||
- py
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install Nushell
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: install
|
||||
args: --path=. --no-default-features
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- run: python -m pip install tox
|
||||
|
||||
- name: Install virtualenv
|
||||
run: |
|
||||
git clone https://github.com/kubouch/virtualenv.git && \
|
||||
cd virtualenv && \
|
||||
git checkout engine-q-update
|
||||
shell: bash
|
||||
|
||||
- name: Test Nushell in virtualenv
|
||||
run: cd virtualenv && tox -e ${{ matrix.py }} -- -k nushell
|
||||
shell: bash
|
118
.github/workflows/docker-publish.yml
vendored
@ -1,118 +0,0 @@
|
||||
name: Publish consumable Docker images
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ['v?[0-9]+.[0-9]+.[0-9]+*']
|
||||
|
||||
jobs:
|
||||
compile:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- x86_64-unknown-linux-musl
|
||||
- x86_64-unknown-linux-gnu
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install rust-embedded/cross
|
||||
env: { VERSION: v0.1.16 }
|
||||
run: >-
|
||||
wget -nv https://github.com/rust-embedded/cross/releases/download/${VERSION}/cross-${VERSION}-x86_64-unknown-linux-gnu.tar.gz
|
||||
-O- | sudo tar xz -C /usr/local/bin/
|
||||
- name: compile for specific target
|
||||
env: { arch: '${{ matrix.arch }}' }
|
||||
run: |
|
||||
cross build --target ${{ matrix.arch }} --release
|
||||
# leave only the executable file
|
||||
rm -frd target/${{ matrix.arch }}/release/{*/*,*.d,*.rlib,.fingerprint}
|
||||
find . -empty -delete
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ${{ matrix.arch }}
|
||||
path: target/${{ matrix.arch }}/release
|
||||
|
||||
docker:
|
||||
name: Build and publish docker images
|
||||
needs: compile
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_REGISTRY: quay.io/nushell
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_REGISTRY }}
|
||||
DOCKER_USER: ${{ secrets.DOCKER_USER }}
|
||||
strategy:
|
||||
matrix:
|
||||
tag:
|
||||
- alpine
|
||||
- slim
|
||||
- debian
|
||||
- glibc-busybox
|
||||
- musl-busybox
|
||||
- musl-distroless
|
||||
- glibc-distroless
|
||||
- glibc
|
||||
- musl
|
||||
include:
|
||||
- { tag: alpine, base-image: alpine, arch: x86_64-unknown-linux-musl, plugin: true, use-patch: false}
|
||||
- { tag: slim, base-image: 'debian:stable-slim', arch: x86_64-unknown-linux-gnu, plugin: true, use-patch: false}
|
||||
- { tag: debian, base-image: debian, arch: x86_64-unknown-linux-gnu, plugin: true, use-patch: false}
|
||||
- { tag: glibc-busybox, base-image: 'busybox:glibc', arch: x86_64-unknown-linux-gnu, plugin: false, use-patch: true }
|
||||
- { tag: musl-busybox, base-image: 'busybox:musl', arch: x86_64-unknown-linux-musl, plugin: false, use-patch: false}
|
||||
- { tag: musl-distroless, base-image: 'gcr.io/distroless/static', arch: x86_64-unknown-linux-musl, plugin: false, use-patch: false}
|
||||
- { tag: glibc-distroless, base-image: 'gcr.io/distroless/cc', arch: x86_64-unknown-linux-gnu, plugin: false, use-patch: true }
|
||||
- { tag: glibc, base-image: scratch, arch: x86_64-unknown-linux-gnu, plugin: false, use-patch: false}
|
||||
- { tag: musl, base-image: scratch, arch: x86_64-unknown-linux-musl, plugin: false, use-patch: false}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@master
|
||||
with: { name: '${{ matrix.arch }}', path: target/release }
|
||||
- name: Build and publish exact version
|
||||
run: |-
|
||||
export DOCKER_TAG=${GITHUB_REF##*/}-${{ matrix.tag }}
|
||||
export NU_BINS=target/release/$( [ ${{ matrix.plugin }} = true ] && echo nu* || echo nu )
|
||||
export PATCH=$([ ${{ matrix.use-patch }} = true ] && echo .${{ matrix.tag }} || echo '')
|
||||
chmod +x $NU_BINS
|
||||
|
||||
echo ${DOCKER_PASSWORD} | docker login ${DOCKER_REGISTRY} -u ${DOCKER_USER} --password-stdin
|
||||
docker-compose --file docker/docker-compose.package.yml build
|
||||
docker-compose --file docker/docker-compose.package.yml push # exact version
|
||||
env:
|
||||
BASE_IMAGE: ${{ matrix.base-image }}
|
||||
|
||||
#region semantics tagging
|
||||
- name: Retag and push with suffixed version
|
||||
run: |-
|
||||
VERSION=${GITHUB_REF##*/}
|
||||
|
||||
latest_version=${VERSION%%%.*}-${{ matrix.tag }}
|
||||
latest_feature=${VERSION%%.*}-${{ matrix.tag }}
|
||||
latest_patch=${VERSION%.*}-${{ matrix.tag }}
|
||||
exact_version=${VERSION}-${{ matrix.tag }}
|
||||
|
||||
tags=( ${latest_version} ${latest_feature} ${latest_patch} ${exact_version} )
|
||||
|
||||
for tag in ${tags[@]}; do
|
||||
docker tag ${DOCKER_REGISTRY}/nu:${VERSION}-${{ matrix.tag }} ${DOCKER_REGISTRY}/nu:${tag}
|
||||
docker push ${DOCKER_REGISTRY}/nu:${tag}
|
||||
done
|
||||
|
||||
# latest version
|
||||
docker tag ${DOCKER_REGISTRY}/nu:${VERSION}-${{ matrix.tag }} ${DOCKER_REGISTRY}/nu:${{ matrix.tag }}
|
||||
docker push ${DOCKER_REGISTRY}/nu:${{ matrix.tag }}
|
||||
|
||||
- name: Retag and push debian as latest
|
||||
if: matrix.tag == 'debian'
|
||||
run: |-
|
||||
VERSION=${GITHUB_REF##*/}
|
||||
|
||||
# ${latest features} ${latest patch} ${exact version}
|
||||
tags=( ${VERSION%%.*} ${VERSION%.*} ${VERSION} )
|
||||
|
||||
for tag in ${tags[@]}; do
|
||||
docker tag ${DOCKER_REGISTRY}/nu:${VERSION}-${{ matrix.tag }} ${DOCKER_REGISTRY}/nu:${tag}
|
||||
docker push ${DOCKER_REGISTRY}/nu:${tag}
|
||||
done
|
||||
|
||||
# latest version
|
||||
docker tag ${DOCKER_REGISTRY}/nu:${{ matrix.tag }} ${DOCKER_REGISTRY}/nu:latest
|
||||
docker push ${DOCKER_REGISTRY}/nu:latest
|
||||
#endregion semantics tagging
|
177
.github/workflows/release.yml
vendored
@ -1,8 +1,9 @@
|
||||
name: Create Release Draft
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags: ['[0-9]+.[0-9]+.[0-9]+*']
|
||||
tags: ["[0-9]+.[0-9]+.[0-9]+*"]
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
@ -28,6 +29,60 @@ jobs:
|
||||
command: build
|
||||
args: --release --all --features=extra
|
||||
|
||||
# - name: Strip binaries (nu)
|
||||
# run: strip target/release/nu
|
||||
|
||||
# - name: Strip binaries (nu_plugin_inc)
|
||||
# run: strip target/release/nu_plugin_inc
|
||||
|
||||
# - name: Strip binaries (nu_plugin_match)
|
||||
# run: strip target/release/nu_plugin_match
|
||||
|
||||
# - name: Strip binaries (nu_plugin_textview)
|
||||
# run: strip target/release/nu_plugin_textview
|
||||
|
||||
# - name: Strip binaries (nu_plugin_binaryview)
|
||||
# run: strip target/release/nu_plugin_binaryview
|
||||
|
||||
# - name: Strip binaries (nu_plugin_chart_bar)
|
||||
# run: strip target/release/nu_plugin_chart_bar
|
||||
|
||||
# - name: Strip binaries (nu_plugin_chart_line)
|
||||
# run: strip target/release/nu_plugin_chart_line
|
||||
|
||||
# - name: Strip binaries (nu_plugin_from_bson)
|
||||
# run: strip target/release/nu_plugin_from_bson
|
||||
|
||||
# - name: Strip binaries (nu_plugin_from_sqlite)
|
||||
# run: strip target/release/nu_plugin_from_sqlite
|
||||
|
||||
# - name: Strip binaries (nu_plugin_from_mp4)
|
||||
# run: strip target/release/nu_plugin_from_mp4
|
||||
|
||||
# - name: Strip binaries (nu_plugin_query_json)
|
||||
# run: strip target/release/nu_plugin_query_json
|
||||
|
||||
# - name: Strip binaries (nu_plugin_s3)
|
||||
# run: strip target/release/nu_plugin_s3
|
||||
|
||||
# - name: Strip binaries (nu_plugin_selector)
|
||||
# run: strip target/release/nu_plugin_selector
|
||||
|
||||
# - name: Strip binaries (nu_plugin_start)
|
||||
# run: strip target/release/nu_plugin_start
|
||||
|
||||
# - name: Strip binaries (nu_plugin_to_bson)
|
||||
# run: strip target/release/nu_plugin_to_bson
|
||||
|
||||
# - name: Strip binaries (nu_plugin_to_sqlite)
|
||||
# run: strip target/release/nu_plugin_to_sqlite
|
||||
|
||||
# - name: Strip binaries (nu_plugin_tree)
|
||||
# run: strip target/release/nu_plugin_tree
|
||||
|
||||
# - name: Strip binaries (nu_plugin_xpath)
|
||||
# run: strip target/release/nu_plugin_xpath
|
||||
|
||||
- name: Create output directory
|
||||
run: mkdir output
|
||||
|
||||
@ -37,8 +92,6 @@ jobs:
|
||||
cp README.build.txt output/README.txt
|
||||
cp LICENSE output/LICENSE
|
||||
rm output/*.d
|
||||
rm output/nu_plugin_core_*
|
||||
rm output/nu_plugin_extra_*
|
||||
|
||||
# Note: If OpenSSL changes, this path will need to be updated
|
||||
- name: Copy OpenSSL to output
|
||||
@ -70,6 +123,60 @@ jobs:
|
||||
command: build
|
||||
args: --release --all --features=extra
|
||||
|
||||
# - name: Strip binaries (nu)
|
||||
# run: strip target/release/nu
|
||||
|
||||
# - name: Strip binaries (nu_plugin_inc)
|
||||
# run: strip target/release/nu_plugin_inc
|
||||
|
||||
# - name: Strip binaries (nu_plugin_match)
|
||||
# run: strip target/release/nu_plugin_match
|
||||
|
||||
# - name: Strip binaries (nu_plugin_textview)
|
||||
# run: strip target/release/nu_plugin_textview
|
||||
|
||||
# - name: Strip binaries (nu_plugin_binaryview)
|
||||
# run: strip target/release/nu_plugin_binaryview
|
||||
|
||||
# - name: Strip binaries (nu_plugin_chart_bar)
|
||||
# run: strip target/release/nu_plugin_chart_bar
|
||||
|
||||
# - name: Strip binaries (nu_plugin_chart_line)
|
||||
# run: strip target/release/nu_plugin_chart_line
|
||||
|
||||
# - name: Strip binaries (nu_plugin_from_bson)
|
||||
# run: strip target/release/nu_plugin_from_bson
|
||||
|
||||
# - name: Strip binaries (nu_plugin_from_sqlite)
|
||||
# run: strip target/release/nu_plugin_from_sqlite
|
||||
|
||||
# - name: Strip binaries (nu_plugin_from_mp4)
|
||||
# run: strip target/release/nu_plugin_from_mp4
|
||||
|
||||
# - name: Strip binaries (nu_plugin_query_json)
|
||||
# run: strip target/release/nu_plugin_query_json
|
||||
|
||||
# - name: Strip binaries (nu_plugin_s3)
|
||||
# run: strip target/release/nu_plugin_s3
|
||||
|
||||
# - name: Strip binaries (nu_plugin_selector)
|
||||
# run: strip target/release/nu_plugin_selector
|
||||
|
||||
# - name: Strip binaries (nu_plugin_start)
|
||||
# run: strip target/release/nu_plugin_start
|
||||
|
||||
# - name: Strip binaries (nu_plugin_to_bson)
|
||||
# run: strip target/release/nu_plugin_to_bson
|
||||
|
||||
# - name: Strip binaries (nu_plugin_to_sqlite)
|
||||
# run: strip target/release/nu_plugin_to_sqlite
|
||||
|
||||
# - name: Strip binaries (nu_plugin_tree)
|
||||
# run: strip target/release/nu_plugin_tree
|
||||
|
||||
# - name: Strip binaries (nu_plugin_xpath)
|
||||
# run: strip target/release/nu_plugin_xpath
|
||||
|
||||
- name: Create output directory
|
||||
run: mkdir output
|
||||
|
||||
@ -79,8 +186,6 @@ jobs:
|
||||
cp README.build.txt output/README.txt
|
||||
cp LICENSE output/LICENSE
|
||||
rm output/*.d
|
||||
rm output/nu_plugin_core_*
|
||||
rm output/nu_plugin_extra_*
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
@ -106,7 +211,7 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: install
|
||||
args: cargo-wix
|
||||
args: cargo-wix --version 0.3.1
|
||||
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
@ -114,6 +219,60 @@ jobs:
|
||||
command: build
|
||||
args: --release --all --features=extra
|
||||
|
||||
# - name: Strip binaries (nu.exe)
|
||||
# run: strip target/release/nu.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_inc.exe)
|
||||
# run: strip target/release/nu_plugin_inc.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_match.exe)
|
||||
# run: strip target/release/nu_plugin_match.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_textview.exe)
|
||||
# run: strip target/release/nu_plugin_textview.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_binaryview.exe)
|
||||
# run: strip target/release/nu_plugin_binaryview.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_chart_bar.exe)
|
||||
# run: strip target/release/nu_plugin_chart_bar.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_chart_line.exe)
|
||||
# run: strip target/release/nu_plugin_chart_line.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_from_bson.exe)
|
||||
# run: strip target/release/nu_plugin_from_bson.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_from_sqlite.exe)
|
||||
# run: strip target/release/nu_plugin_from_sqlite.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_from_mp4.exe)
|
||||
# run: strip target/release/nu_plugin_from_mp4.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_query_json.exe)
|
||||
# run: strip target/release/nu_plugin_query_json.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_s3.exe)
|
||||
# run: strip target/release/nu_plugin_s3.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_selector.exe)
|
||||
# run: strip target/release/nu_plugin_selector.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_start.exe)
|
||||
# run: strip target/release/nu_plugin_start.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_to_bson.exe)
|
||||
# run: strip target/release/nu_plugin_to_bson.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_to_sqlite.exe)
|
||||
# run: strip target/release/nu_plugin_to_sqlite.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_tree.exe)
|
||||
# run: strip target/release/nu_plugin_tree.exe
|
||||
|
||||
# - name: Strip binaries (nu_plugin_xpath.exe)
|
||||
# run: strip target/release/nu_plugin_xpath.exe
|
||||
|
||||
- name: Create output directory
|
||||
run: mkdir output
|
||||
|
||||
@ -128,8 +287,6 @@ jobs:
|
||||
cp target\release\nu.exe output\
|
||||
cp LICENSE output\
|
||||
cp target\release\LICENSE-for-less.txt output\
|
||||
rm target\release\nu_plugin_core_*.exe
|
||||
rm target\release\nu_plugin_extra_*.exe
|
||||
cp target\release\nu_plugin_*.exe output\
|
||||
cp README.build.txt output\README.txt
|
||||
cp target\release\less.exe output\
|
||||
@ -274,7 +431,7 @@ jobs:
|
||||
with:
|
||||
name: windows-installer
|
||||
path: ./
|
||||
|
||||
|
||||
- name: Upload Windows installer
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
@ -283,4 +440,4 @@ jobs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./nushell-windows.msi
|
||||
asset_name: ${{ steps.info.outputs.windowsdir }}.msi
|
||||
asset_content_type: applictaion/x-msi
|
||||
asset_content_type: application/x-msi
|
||||
|
28
.github/workflows/stale.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
#on: [workflow_dispatch]
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
#debug-only: true
|
||||
ascending: true
|
||||
operations-per-run: 520
|
||||
enable-statistics: true
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
close-issue-message: 'This issue has been marked stale for more than 100000 days without activity. Closing this issue, but if you find that the issue is still valid, please reopen.'
|
||||
close-pr-message: 'This PR has been marked stale for more than 100 days without activity. Closing this PR, but if you are still working on it, please reopen.'
|
||||
days-before-issue-stale: 90
|
||||
days-before-pr-stale: 45
|
||||
days-before-issue-close: 100000
|
||||
days-before-pr-close: 100
|
||||
exempt-issue-labels: 'exempt,keep'
|
19
.github/workflows/winget-submission.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Submit Nushell package to Windows Package Manager Community Repository
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
|
||||
winget:
|
||||
name: Publish winget package
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Submit package to Windows Package Manager Community Repository
|
||||
run: |
|
||||
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||
$github = Get-Content '${{ github.event_path }}' | ConvertFrom-Json
|
||||
$installerUrl = $github.release.assets | Where-Object -Property name -match 'windows.msi' | Select -ExpandProperty browser_download_url -First 1
|
||||
.\wingetcreate.exe update Nushell.Nushell -s -v $github.release.tag_name -u $installerUrl -t ${{ secrets.NUSHELL_PAT }}
|
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
||||
history.txt
|
||||
tests/fixtures/nuplayground
|
||||
crates/*/target
|
||||
.mailmap
|
||||
|
||||
# Debian/Ubuntu
|
||||
debian/.debhelper/
|
||||
|
14
.gitpod.Dockerfile
vendored
@ -1,14 +0,0 @@
|
||||
FROM gitpod/workspace-full
|
||||
|
||||
USER gitpod
|
||||
|
||||
RUN sudo apt-get update && \
|
||||
sudo apt-get install -y \
|
||||
libssl-dev \
|
||||
libxcb-composite0-dev \
|
||||
pkg-config \
|
||||
libpython3.6 \
|
||||
rust-lldb \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV RUST_LLDB=/usr/bin/lldb-8
|
25
.gitpod.yml
@ -1,25 +0,0 @@
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
tasks:
|
||||
- name: Clippy
|
||||
init: cargo clippy --all --features=stable -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
|
||||
- name: Testing
|
||||
init: cargo test --all --features=stable,test-bins
|
||||
- name: Build
|
||||
init: cargo build --features=stable
|
||||
- name: Nu
|
||||
init: cargo install --path . --features=stable
|
||||
command: nu
|
||||
github:
|
||||
prebuilds:
|
||||
branches: true
|
||||
pullRequestsFromForks: true
|
||||
addLabel: prebuilt-in-gitpod
|
||||
vscode:
|
||||
extensions:
|
||||
- hbenl.vscode-test-explorer@2.15.0:koqDUMWDPJzELp/hdS/lWw==
|
||||
- Swellaby.vscode-rust-test-adapter@0.11.0:Xg+YeZZQiVpVUsIkH+uiiw==
|
||||
- serayuzgur.crates@0.4.7:HMkoguLcXp9M3ud7ac3eIw==
|
||||
- belfz.search-crates-io@1.2.1:kSLnyrOhXtYPjQpKnMr4eQ==
|
||||
- bungcip.better-toml@0.3.2:3QfgGxxYtGHfJKQU7H0nEw==
|
||||
- webfreak.debug@0.24.0:1zVcRsAhewYEX3/A9xjMNw==
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "gdb",
|
||||
"request": "launch",
|
||||
"name": "Debug Rust Code",
|
||||
"preLaunchTask": "cargo",
|
||||
"target": "${workspaceFolder}/target/debug/nu",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"valuesFormatting": "parseText"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"command": "cargo",
|
||||
"args": [
|
||||
"build"
|
||||
],
|
||||
"type": "process",
|
||||
"label": "cargo",
|
||||
}
|
||||
],
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
Welcome to nushell!
|
||||
|
||||
*Note: for a more complete guide see [The nu contributor book](https://github.com/nushell/contributor-book)*
|
||||
*Note: for a more complete guide see [The nu contributor book](https://www.nushell.sh/contributor-book/)*
|
||||
|
||||
For speedy contributions open it in Gitpod, nu will be pre-installed with the latest build in a VSCode like editor all from your browser.
|
||||
|
||||
@ -31,6 +31,11 @@ cargo build
|
||||
cargo build --release && cargo run --release
|
||||
```
|
||||
|
||||
- Build and run with extra features:
|
||||
```shell
|
||||
cargo build --release --features=extra && cargo run --release --features=extra
|
||||
```
|
||||
|
||||
- Run Clippy on Nushell:
|
||||
|
||||
```shell
|
||||
@ -60,3 +65,11 @@ cargo build
|
||||
```shell
|
||||
cargo fmt --all
|
||||
```
|
||||
|
||||
### Debugging Tips
|
||||
|
||||
- To view verbose logs when developing, enable the `trace` log level.
|
||||
|
||||
```shell
|
||||
cargo build --release --features=extra && cargo run --release --features=extra -- --log-level trace
|
||||
```
|
||||
|
6349
Cargo.lock
generated
220
Cargo.toml
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
authors = ["The Nu Project Contributors"]
|
||||
authors = ["The Nushell Project Developers"]
|
||||
default-run = "nu"
|
||||
description = "A new type of shell"
|
||||
documentation = "https://www.nushell.sh/book/"
|
||||
@ -10,169 +10,93 @@ license = "MIT"
|
||||
name = "nu"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
version = "0.20.0"
|
||||
|
||||
[workspace]
|
||||
members = ["crates/*/"]
|
||||
rust-version = "1.59"
|
||||
version = "0.61.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/nu-cli",
|
||||
"crates/nu-engine",
|
||||
"crates/nu-parser",
|
||||
"crates/nu-system",
|
||||
"crates/nu-command",
|
||||
"crates/nu-protocol",
|
||||
"crates/nu-plugin",
|
||||
"crates/nu_plugin_inc",
|
||||
"crates/nu_plugin_gstat",
|
||||
"crates/nu_plugin_example",
|
||||
"crates/nu_plugin_query",
|
||||
"crates/nu-utils",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
nu-cli = {version = "0.20.0", path = "./crates/nu-cli"}
|
||||
nu-data = {version = "0.20.0", path = "./crates/nu-data"}
|
||||
nu-errors = {version = "0.20.0", path = "./crates/nu-errors"}
|
||||
nu-parser = {version = "0.20.0", path = "./crates/nu-parser"}
|
||||
nu-plugin = {version = "0.20.0", path = "./crates/nu-plugin"}
|
||||
nu-protocol = {version = "0.20.0", path = "./crates/nu-protocol"}
|
||||
nu-source = {version = "0.20.0", path = "./crates/nu-source"}
|
||||
nu-value-ext = {version = "0.20.0", path = "./crates/nu-value-ext"}
|
||||
|
||||
nu_plugin_binaryview = {version = "0.20.0", path = "./crates/nu_plugin_binaryview", optional = true}
|
||||
nu_plugin_fetch = {version = "0.20.0", path = "./crates/nu_plugin_fetch", optional = true}
|
||||
nu_plugin_from_bson = {version = "0.20.0", path = "./crates/nu_plugin_from_bson", optional = true}
|
||||
nu_plugin_from_sqlite = {version = "0.20.0", path = "./crates/nu_plugin_from_sqlite", optional = true}
|
||||
nu_plugin_inc = {version = "0.20.0", path = "./crates/nu_plugin_inc", optional = true}
|
||||
nu_plugin_match = {version = "0.20.0", path = "./crates/nu_plugin_match", optional = true}
|
||||
nu_plugin_post = {version = "0.20.0", path = "./crates/nu_plugin_post", optional = true}
|
||||
nu_plugin_ps = {version = "0.20.0", path = "./crates/nu_plugin_ps", optional = true}
|
||||
nu_plugin_s3 = {version = "0.20.0", path = "./crates/nu_plugin_s3", optional = true}
|
||||
nu_plugin_start = {version = "0.20.0", path = "./crates/nu_plugin_start", optional = true}
|
||||
nu_plugin_sys = {version = "0.20.0", path = "./crates/nu_plugin_sys", optional = true}
|
||||
nu_plugin_textview = {version = "0.20.0", path = "./crates/nu_plugin_textview", optional = true}
|
||||
nu_plugin_to_bson = {version = "0.20.0", path = "./crates/nu_plugin_to_bson", optional = true}
|
||||
nu_plugin_to_sqlite = {version = "0.20.0", path = "./crates/nu_plugin_to_sqlite", optional = true}
|
||||
nu_plugin_tree = {version = "0.20.0", path = "./crates/nu_plugin_tree", optional = true}
|
||||
|
||||
crossterm = {version = "0.17", optional = true}
|
||||
semver = {version = "0.10.0", optional = true}
|
||||
url = {version = "2.1.1", optional = true}
|
||||
|
||||
clap = "2.33.3"
|
||||
ctrlc = "3.1.6"
|
||||
dunce = "1.0.1"
|
||||
futures = {version = "0.3.5", features = ["compat", "io-compat"]}
|
||||
log = "0.4.11"
|
||||
chrono = "0.4.19"
|
||||
crossterm = "0.23.0"
|
||||
ctrlc = "3.2.1"
|
||||
log = "0.4"
|
||||
miette = "4.1.0"
|
||||
nu-ansi-term = "0.45.1"
|
||||
nu-cli = { path="./crates/nu-cli", version = "0.61.0" }
|
||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.61.0" }
|
||||
nu-command = { path="./crates/nu-command", version = "0.61.0" }
|
||||
nu-engine = { path="./crates/nu-engine", version = "0.61.0" }
|
||||
nu-json = { path="./crates/nu-json", version = "0.61.0" }
|
||||
nu-parser = { path="./crates/nu-parser", version = "0.61.0" }
|
||||
nu-path = { path="./crates/nu-path", version = "0.61.0" }
|
||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.61.0" }
|
||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.61.0" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.61.0" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.61.0" }
|
||||
nu-table = { path = "./crates/nu-table", version = "0.61.0" }
|
||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.61.0" }
|
||||
pretty_env_logger = "0.4.0"
|
||||
quick-xml = "0.18.1"
|
||||
rayon = "1.5.1"
|
||||
reedline = { version = "0.4.0", features = ["bashisms"]}
|
||||
is_executable = "1.0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = {version = "0.20.0", path = "./crates/nu-test-support"}
|
||||
nu-test-support = { path="./crates/nu-test-support", version = "0.61.0" }
|
||||
tempfile = "3.2.0"
|
||||
assert_cmd = "2.0.2"
|
||||
pretty_assertions = "1.0.0"
|
||||
serial_test = "0.5.1"
|
||||
hamcrest2 = "0.3.0"
|
||||
rstest = "0.12.0"
|
||||
itertools = "0.10.3"
|
||||
|
||||
[build-dependencies]
|
||||
serde = {version = "1.0.115", features = ["derive"]}
|
||||
toml = "0.5.6"
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
embed-resource = "1"
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"sys",
|
||||
"ps",
|
||||
"textview",
|
||||
"inc",
|
||||
"git-support",
|
||||
"directories-support",
|
||||
"ctrlc-support",
|
||||
"which-support",
|
||||
"ptree-support",
|
||||
"term-support",
|
||||
"uuid-support",
|
||||
"rustyline-support",
|
||||
"match",
|
||||
"post",
|
||||
"fetch",
|
||||
"rich-benchmark",
|
||||
]
|
||||
extra = ["default", "binaryview", "tree", "clipboard-cli", "trash-support", "start", "bson", "sqlite", "s3"]
|
||||
plugin = ["nu-plugin", "nu-cli/plugin", "nu-parser/plugin", "nu-command/plugin", "nu-protocol/plugin", "nu-engine/plugin"]
|
||||
default = ["plugin", "which-support", "zip-support", "trash-support"]
|
||||
stable = ["default"]
|
||||
extra = ["default", "dataframe"]
|
||||
wasi = []
|
||||
|
||||
# Default
|
||||
inc = ["semver", "nu_plugin_inc"]
|
||||
ps = ["nu_plugin_ps"]
|
||||
sys = ["nu_plugin_sys"]
|
||||
textview = ["crossterm", "url", "nu_plugin_textview"]
|
||||
# Stable (Default)
|
||||
which-support = ["nu-command/which-support"]
|
||||
zip-support = ["nu-command/zip"]
|
||||
trash-support = ["nu-command/trash-support"]
|
||||
|
||||
# Stable
|
||||
binaryview = ["nu_plugin_binaryview"]
|
||||
bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"]
|
||||
fetch = ["nu_plugin_fetch"]
|
||||
match = ["nu_plugin_match"]
|
||||
post = ["nu_plugin_post"]
|
||||
s3 = ["nu_plugin_s3"]
|
||||
sqlite = ["nu_plugin_from_sqlite", "nu_plugin_to_sqlite"]
|
||||
start = ["nu_plugin_start"]
|
||||
trace = ["nu-parser/trace"]
|
||||
tree = ["nu_plugin_tree"]
|
||||
# Extra
|
||||
|
||||
clipboard-cli = ["nu-cli/clipboard-cli"]
|
||||
ctrlc-support = ["nu-cli/ctrlc"]
|
||||
directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-data/directories", "nu-data/dirs"]
|
||||
git-support = ["nu-cli/git2"]
|
||||
ptree-support = ["nu-cli/ptree"]
|
||||
rich-benchmark = ["nu-cli/rich-benchmark"]
|
||||
rustyline-support = ["nu-cli/rustyline-support"]
|
||||
term-support = ["nu-cli/term"]
|
||||
trash-support = ["nu-cli/trash-support"]
|
||||
uuid-support = ["nu-cli/uuid_crate"]
|
||||
which-support = ["nu-cli/ichwh", "nu-cli/which"]
|
||||
# Dataframe feature for nushell
|
||||
dataframe = ["nu-command/dataframe"]
|
||||
|
||||
# Core plugins that ship with `cargo install nu` by default
|
||||
# Currently, Cargo limits us to installing only one binary
|
||||
# unless we use [[bin]], so we use this as a workaround
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_textview"
|
||||
path = "src/plugins/nu_plugin_core_textview.rs"
|
||||
required-features = ["textview"]
|
||||
[profile.release]
|
||||
opt-level = "s" # Optimize for size
|
||||
strip = "debuginfo"
|
||||
lto = "thin"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_inc"
|
||||
path = "src/plugins/nu_plugin_core_inc.rs"
|
||||
required-features = ["inc"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_ps"
|
||||
path = "src/plugins/nu_plugin_core_ps.rs"
|
||||
required-features = ["ps"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_sys"
|
||||
path = "src/plugins/nu_plugin_core_sys.rs"
|
||||
required-features = ["sys"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_fetch"
|
||||
path = "src/plugins/nu_plugin_core_fetch.rs"
|
||||
required-features = ["fetch"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_match"
|
||||
path = "src/plugins/nu_plugin_core_match.rs"
|
||||
required-features = ["match"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_post"
|
||||
path = "src/plugins/nu_plugin_core_post.rs"
|
||||
required-features = ["post"]
|
||||
|
||||
# Extra plugins
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_extra_binaryview"
|
||||
path = "src/plugins/nu_plugin_extra_binaryview.rs"
|
||||
required-features = ["binaryview"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_extra_tree"
|
||||
path = "src/plugins/nu_plugin_extra_tree.rs"
|
||||
required-features = ["tree"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_extra_start"
|
||||
path = "src/plugins/nu_plugin_extra_start.rs"
|
||||
required-features = ["start"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_extra_s3"
|
||||
path = "src/plugins/nu_plugin_extra_s3.rs"
|
||||
required-features = ["s3"]
|
||||
# build with `cargo build --profile profiling`
|
||||
# to analyze performance with tooling like linux perf
|
||||
[profile.profiling]
|
||||
inherits = "release"
|
||||
strip = false
|
||||
debug = true
|
||||
|
||||
# Main nu binary
|
||||
[[bin]]
|
||||
|
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 - 2020 Yehuda Katz, Jonathan Turner
|
||||
Copyright (c) 2019 - 2022 The Nushell Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
199
README.md
@ -1,17 +1,18 @@
|
||||
# README
|
||||
|
||||
[](https://gitpod.io/#https://github.com/nushell/nushell)
|
||||
[](https://crates.io/crates/nu)
|
||||
[](https://dev.azure.com/nushell/nushell/_build/latest?definitionId=2&branchName=master)
|
||||
[](https://github.com/nushell/nushell/actions)
|
||||
[](https://discord.gg/NtAbbGn)
|
||||
[](https://changelog.com/podcast/363)
|
||||
[](https://twitter.com/nu_shell)
|
||||

|
||||

|
||||
|
||||
## Nu Shell
|
||||
## Nushell
|
||||
|
||||
A new type of shell.
|
||||
|
||||

|
||||

|
||||
|
||||
## Status
|
||||
|
||||
@ -34,88 +35,51 @@ There are also [good first issues](https://github.com/nushell/nushell/issues?q=i
|
||||
|
||||
We also have an active [Discord](https://discord.gg/NtAbbGn) and [Twitter](https://twitter.com/nu_shell) if you'd like to come and chat with us.
|
||||
|
||||
You can also find more learning resources in our [documentation](https://www.nushell.sh/documentation.html) site.
|
||||
|
||||
Try it in Gitpod.
|
||||
|
||||
[](https://gitpod.io/#https://github.com/nushell/nushell)
|
||||
You can also find information on more specific topics in our [cookbook](https://www.nushell.sh/cookbook/).
|
||||
|
||||
## Installation
|
||||
|
||||
### Local
|
||||
|
||||
Up-to-date installation instructions can be found in the [installation chapter of the book](https://www.nushell.sh/book/en/installation.html). **Windows users**: please note that Nu works on Windows 10 and does not currently have Windows 7/8.1 support.
|
||||
Up-to-date installation instructions can be found in the [installation chapter of the book](https://www.nushell.sh/book/installation.html). **Windows users**: please note that Nu works on Windows 10 and does not currently have Windows 7/8.1 support.
|
||||
|
||||
To build Nu, you will need to use the **latest stable (1.41 or later)** version of the compiler.
|
||||
To build Nu, you will need to use the **latest stable (1.59 or later)** version of the compiler.
|
||||
|
||||
Required dependencies:
|
||||
|
||||
* pkg-config and libssl (only needed on Linux)
|
||||
* On Debian/Ubuntu: `apt install pkg-config libssl-dev`
|
||||
- pkg-config and libssl (only needed on Linux)
|
||||
- On Debian/Ubuntu: `apt install pkg-config libssl-dev`
|
||||
|
||||
Optional dependencies:
|
||||
|
||||
* To use Nu with all possible optional features enabled, you'll also need the following:
|
||||
* On Linux (on Debian/Ubuntu): `apt install libxcb-composite0-dev libx11-dev`
|
||||
- To use Nu with all possible optional features enabled, you'll also need the following:
|
||||
- On Linux (on Debian/Ubuntu): `apt install libxcb-composite0-dev libx11-dev`
|
||||
|
||||
To install Nu via cargo (make sure you have installed [rustup](https://rustup.rs/) and the latest stable compiler via `rustup install stable`):
|
||||
|
||||
```bash
|
||||
For Windows users, you may also need to install the [Microsoft Visual C++ 2015 Redistributables](https://docs.microsoft.com/cpp/windows/latest-supported-vc-redist).
|
||||
|
||||
```shell
|
||||
cargo install nu
|
||||
```
|
||||
|
||||
You can also build Nu yourself with all the bells and whistles (be sure to have installed the [dependencies](https://www.nushell.sh/book/en/installation.html#dependencies) for your platform), once you have checked out this repo with git:
|
||||
To install Nu via the [Windows Package Manager](https://aka.ms/winget-cli):
|
||||
|
||||
```bash
|
||||
```shell
|
||||
winget install nushell
|
||||
```
|
||||
|
||||
To install Nu via the [Chocolatey](https://chocolatey.org) package manager:
|
||||
|
||||
```shell
|
||||
choco install nushell
|
||||
```
|
||||
|
||||
You can also build Nu yourself with all the bells and whistles (be sure to have installed the [dependencies](https://www.nushell.sh/book/installation.html#dependencies) for your platform), once you have checked out this repo with git:
|
||||
|
||||
```shell
|
||||
cargo build --workspace --features=extra
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
#### Quickstart
|
||||
|
||||
Want to try Nu right away? Execute the following to get started.
|
||||
|
||||
```bash
|
||||
docker run -it quay.io/nushell/nu:latest
|
||||
```
|
||||
|
||||
#### Guide
|
||||
|
||||
If you want to pull a pre-built container, you can browse tags for the [nushell organization](https://quay.io/organization/nushell)
|
||||
on Quay.io. Pulling a container would come down to:
|
||||
|
||||
```bash
|
||||
docker pull quay.io/nushell/nu
|
||||
docker pull quay.io/nushell/nu-base
|
||||
```
|
||||
|
||||
Both "nu-base" and "nu" provide the nu binary, however nu-base also includes the source code at `/code`
|
||||
in the container and all dependencies.
|
||||
|
||||
Optionally, you can also build the containers locally using the [dockerfiles provided](docker):
|
||||
To build the base image:
|
||||
|
||||
```bash
|
||||
docker build -f docker/Dockerfile.nu-base -t nushell/nu-base .
|
||||
```
|
||||
|
||||
And then to build the smaller container (using a Multistage build):
|
||||
|
||||
```bash
|
||||
docker build -f docker/Dockerfile -t nushell/nu .
|
||||
```
|
||||
|
||||
Either way, you can run either container as follows:
|
||||
|
||||
```bash
|
||||
docker run -it nushell/nu-base
|
||||
docker run -it nushell/nu
|
||||
/> exit
|
||||
```
|
||||
|
||||
The second container is a bit smaller if the size is important to you.
|
||||
|
||||
### Packaging status
|
||||
|
||||
[](https://repology.org/project/nushell/versions)
|
||||
@ -135,13 +99,13 @@ These values can be piped through a series of steps, in a series of commands cal
|
||||
|
||||
In Unix, it's common to pipe between commands to split up a sophisticated command over multiple steps.
|
||||
Nu takes this a step further and builds heavily on the idea of _pipelines_.
|
||||
Just as the Unix philosophy, Nu allows commands to output from stdout and read from stdin.
|
||||
Just as the Unix philosophy, Nu allows commands to output to stdout and read from stdin.
|
||||
Additionally, commands can output structured data (you can think of this as a third kind of stream).
|
||||
Commands that work in the pipeline fit into one of three categories:
|
||||
|
||||
* Commands that produce a stream (eg, `ls`)
|
||||
* Commands that filter a stream (eg, `where type == "Dir"`)
|
||||
* Commands that consume the output of the pipeline (eg, `autoview`)
|
||||
- Commands that produce a stream (e.g., `ls`)
|
||||
- Commands that filter a stream (eg, `where type == "Dir"`)
|
||||
- Commands that consume the output of the pipeline (e.g., `autoview`)
|
||||
|
||||
Commands are separated by the pipe symbol (`|`) to denote a pipeline flowing left to right.
|
||||
|
||||
@ -153,12 +117,11 @@ Commands are separated by the pipe symbol (`|`) to denote a pipeline flowing lef
|
||||
0 │ assets │ Dir │ 128 B │ 5 months ago
|
||||
1 │ crates │ Dir │ 704 B │ 50 mins ago
|
||||
2 │ debian │ Dir │ 352 B │ 5 months ago
|
||||
3 │ docker │ Dir │ 288 B │ 3 months ago
|
||||
4 │ docs │ Dir │ 192 B │ 50 mins ago
|
||||
5 │ images │ Dir │ 160 B │ 5 months ago
|
||||
6 │ src │ Dir │ 128 B │ 1 day ago
|
||||
7 │ target │ Dir │ 160 B │ 5 days ago
|
||||
8 │ tests │ Dir │ 192 B │ 3 months ago
|
||||
3 │ docs │ Dir │ 192 B │ 50 mins ago
|
||||
4 │ images │ Dir │ 160 B │ 5 months ago
|
||||
5 │ src │ Dir │ 128 B │ 1 day ago
|
||||
6 │ target │ Dir │ 160 B │ 5 days ago
|
||||
7 │ tests │ Dir │ 192 B │ 3 months ago
|
||||
───┴────────┴──────┴───────┴──────────────
|
||||
```
|
||||
|
||||
@ -170,7 +133,7 @@ We could have also written the above:
|
||||
```
|
||||
|
||||
Being able to use the same commands and compose them differently is an important philosophy in Nu.
|
||||
For example, we could use the built-in `ps` command as well to get a list of the running processes, using the same `where` as above.
|
||||
For example, we could use the built-in `ps` command to get a list of the running processes, using the same `where` as above.
|
||||
|
||||
```shell
|
||||
> ps | where cpu > 0
|
||||
@ -187,7 +150,7 @@ For example, we could use the built-in `ps` command as well to get a list of the
|
||||
|
||||
### Opening files
|
||||
|
||||
Nu can load file and URL contents as raw text or as structured data (if it recognizes the format).
|
||||
Nu can load file and URL contents as raw text or structured data (if it recognizes the format).
|
||||
For example, you can load a .toml file as structured data and explore it:
|
||||
|
||||
```shell
|
||||
@ -219,36 +182,34 @@ We can pipeline this into a command that gets the contents of one of the columns
|
||||
name │ nu
|
||||
readme │ README.md
|
||||
repository │ https://github.com/nushell/nushell
|
||||
version │ 0.15.1
|
||||
version │ 0.32.0
|
||||
───────────────┴────────────────────────────────────
|
||||
```
|
||||
|
||||
Finally, we can use commands outside of Nu once we have the data we want:
|
||||
|
||||
```shell
|
||||
> open Cargo.toml | get package.version | echo $it
|
||||
0.15.1
|
||||
> open Cargo.toml | get package.version
|
||||
0.32.0
|
||||
```
|
||||
|
||||
Here we use the variable `$it` to refer to the value being piped to the external command.
|
||||
|
||||
### Configuration
|
||||
|
||||
Nu has early support for configuring the shell. You can refer to the book for a list of [all supported variables](https://www.nushell.sh/book/en/configuration.html).
|
||||
Nu has early support for configuring the shell. You can refer to the book for a list of [all supported variables](https://www.nushell.sh/book/configuration.html).
|
||||
|
||||
To set one of these variables, you can use `config set`. For example:
|
||||
|
||||
```shell
|
||||
> config set edit_mode "vi"
|
||||
> config set line_editor.edit_mode "vi"
|
||||
> config set path $nu.path
|
||||
```
|
||||
|
||||
### Shells
|
||||
|
||||
Nu will work inside of a single directory and allow you to navigate around your filesystem by default.
|
||||
Nu also offers a way of adding additional working directories that you can jump between, allowing you to work in multiple directories at the same time.
|
||||
Nu also offers a way of adding additional working directories that you can jump between, allowing you to work in multiple directories simultaneously.
|
||||
|
||||
To do so, use the `enter` command, which will allow you create a new "shell" and enter it at the specified path.
|
||||
To do so, use the `enter` command, which will allow you to create a new "shell" and enter it at the specified path.
|
||||
You can toggle between this new shell and the original shell with the `p` (for previous) and `n` (for next), allowing you to navigate around a ring buffer of shells.
|
||||
Once you're done with a shell, you can `exit` it and remove it from the ring buffer.
|
||||
|
||||
@ -262,7 +223,7 @@ This allows you to extend nu for your needs.
|
||||
There are a few examples in the `plugins` directory.
|
||||
|
||||
Plugins are binaries that are available in your path and follow a `nu_plugin_*` naming convention.
|
||||
These binaries interact with nu via a simple JSON-RPC protocol where the command identifies itself and passes along its configuration, which then makes it available for use.
|
||||
These binaries interact with nu via a simple JSON-RPC protocol where the command identifies itself and passes along its configuration, making it available for use.
|
||||
If the plugin is a filter, data streams to it one element at a time, and it can stream data back in return via stdin/stdout.
|
||||
If the plugin is a sink, it is given the full vector of final data and is given free reign over stdin/stdout to use as it pleases.
|
||||
|
||||
@ -270,49 +231,63 @@ If the plugin is a sink, it is given the full vector of final data and is given
|
||||
|
||||
Nu adheres closely to a set of goals that make up its design philosophy. As features are added, they are checked against these goals.
|
||||
|
||||
* First and foremost, Nu is cross-platform. Commands and techniques should carry between platforms and offer first-class consistent support for Windows, macOS, and Linux.
|
||||
- First and foremost, Nu is cross-platform. Commands and techniques should carry between platforms and offer consistent first-class support for Windows, macOS, and Linux.
|
||||
|
||||
* Nu ensures direct compatibility with existing platform-specific executables that make up people's workflows.
|
||||
- Nu ensures direct compatibility with existing platform-specific executables that make up people's workflows.
|
||||
|
||||
* Nu's workflow and tools should have the usability in day-to-day experience of using a shell in 2019 (and beyond).
|
||||
- Nu's workflow and tools should have the usability in day-to-day experience of using a shell in 2019 (and beyond).
|
||||
|
||||
* Nu views data as both structured and unstructured. It is a structured shell like PowerShell.
|
||||
- Nu views data as both structured and unstructured. It is a structured shell like PowerShell.
|
||||
|
||||
* Finally, Nu views data functionally. Rather than using mutation, pipelines act as a means to load, change, and save data without mutable state.
|
||||
- Finally, Nu views data functionally. Rather than using mutation, pipelines act as a means to load, change, and save data without mutable state.
|
||||
|
||||
## Commands
|
||||
|
||||
You can find a list of Nu commands, complete with documentation, in [quick command references](https://www.nushell.sh/documentation.html#quick-command-references).
|
||||
You can find a list of Nu commands, complete with documentation, in [quick command references](https://www.nushell.sh/book/command_reference.html).
|
||||
|
||||
## Progress
|
||||
|
||||
Nu is in heavy development, and will naturally change as it matures and people use it. The chart below isn't meant to be exhaustive, but rather helps give an idea for some of the areas of development and their relative completion:
|
||||
Nu is in heavy development and will naturally change as it matures and people use it. The chart below isn't meant to be exhaustive, but rather helps give an idea for some of the areas of development and their relative completion:
|
||||
|
||||
| Features | Not started | Prototype | MVP | Preview | Mature | Notes
|
||||
| -------- |:-----------:|:---------:|:---:|:-------:|:------:| -----
|
||||
| Aliases | | X | | | | Initial implementation but lacks necessary features
|
||||
| Notebook | | X | | | | Initial jupyter support, but it loses state and lacks features
|
||||
| File ops | | | X | | | cp, mv, rm, mkdir have some support, but lacking others
|
||||
| Environment | | X | | | | Temporary environment, but no session-wide env variables
|
||||
| Shells | | X | | | | Basic value and file shells, but no opt-in/opt-out for commands
|
||||
| Protocol | | | X | | | Streaming protocol is serviceable
|
||||
| Plugins | | X | | | | Plugins work on one row at a time, lack batching and expression eval
|
||||
| Errors | | | X | | | Error reporting works, but could use usability polish
|
||||
| Documentation | | X | | | | Book and related are barebones and lack task-based lessons
|
||||
| Paging | | X | | | | Textview has paging, but we'd like paging for tables
|
||||
| Functions| X | | | | | No functions, yet, only aliases
|
||||
| Variables| X | | | | | Nu doesn't yet support variables
|
||||
| Completions | | X | | | | Completions are currently barebones, at best
|
||||
| Type-checking | | X | | | | Commands check basic types, but input/output isn't checked
|
||||
| Features | Not started | Prototype | MVP | Preview | Mature | Notes |
|
||||
| ------------- | :---------: | :-------: | :-: | :-----: | :----: | -------------------------------------------------------------------- |
|
||||
| Aliases | | | | X | | Aliases allow for shortening large commands, while passing flags |
|
||||
| Notebook | | X | | | | Initial jupyter support, but it loses state and lacks features |
|
||||
| File ops | | | | X | | cp, mv, rm, mkdir have some support, but lacking others |
|
||||
| Environment | | | | X | | Temporary environment and scoped environment variables |
|
||||
| Shells | | | | X | | Basic value and file shells, but no opt-in/opt-out for commands |
|
||||
| Protocol | | | | X | | Streaming protocol is serviceable |
|
||||
| Plugins | | | X | | | Plugins work on one row at a time, lack batching and expression eval |
|
||||
| Errors | | | | X | | Error reporting works, but could use usability polish |
|
||||
| Documentation | | | X | | | Book updated to latest release, including usage examples |
|
||||
| Paging | | | | X | | Textview has paging, but we'd like paging for tables |
|
||||
| Functions | | | | X | | Functions and aliases are supported |
|
||||
| Variables | | | | X | | Nu supports variables and environment variables |
|
||||
| Completions | | | | X | | Completions for filepaths |
|
||||
| Type-checking | | | X | | | Commands check basic types, but input/output isn't checked |
|
||||
|
||||
## Current Roadmap
|
||||
## Officially Supported By
|
||||
|
||||
We've added a `Roadmap Board` to help collaboratively capture the direction we're going for the current release as well as capture some important issues we'd like to see in NuShell. You can find the Roadmap [here](https://github.com/nushell/nushell/projects/2).
|
||||
Please submit an issue or PR to be added to this list.
|
||||
|
||||
### Integrations
|
||||
- [zoxide](https://github.com/ajeetdsouza/zoxide)
|
||||
- [starship](https://github.com/starship/starship)
|
||||
- [oh-my-posh](https://ohmyposh.dev)
|
||||
- [Couchbase Shell](https://couchbase.sh)
|
||||
### Mentions
|
||||
- [The Python Launcher for Unix](https://github.com/brettcannon/python-launcher#how-do-i-get-a-table-of-python-executables-in-nushell)
|
||||
|
||||
## Contributing
|
||||
|
||||
See [Contributing](CONTRIBUTING.md) for details.
|
||||
|
||||
Thanks to all the people who already contributed!
|
||||
|
||||
<a href="https://github.com/nushell/nushell/graphs/contributors">
|
||||
<img src="https://contributors-img.web.app/image?repo=nushell/nushell" />
|
||||
</a>
|
||||
|
||||
## License
|
||||
|
||||
The project is made available under the MIT license. See the `LICENSE` file for more information.
|
||||
|
BIN
assets/icons/black-white.png
Normal file
After Width: | Height: | Size: 166 KiB |
BIN
assets/icons/daniella-eth.png
Normal file
After Width: | Height: | Size: 206 KiB |
BIN
assets/icons/green-black.png
Normal file
After Width: | Height: | Size: 167 KiB |
BIN
assets/icons/green-white-black-circle.png
Normal file
After Width: | Height: | Size: 91 KiB |
BIN
assets/icons/green-white2.png
Normal file
After Width: | Height: | Size: 182 KiB |
BIN
assets/icons/green-white6.png
Normal file
After Width: | Height: | Size: 144 KiB |
BIN
assets/icons/green-white7.png
Normal file
After Width: | Height: | Size: 146 KiB |
BIN
assets/icons/nu-cascadia-tiffany.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/icons/nu-kfarmer.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/icons/nushell-original.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/nushell-round-black.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
assets/icons/nushell-round-black2.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
assets/icons/nushell-round-black4.png
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
assets/nu_logo.ico
Normal file
After Width: | Height: | Size: 6.0 KiB |
49
assets/nushell.rc
Normal file
@ -0,0 +1,49 @@
|
||||
#include <winver.h>
|
||||
|
||||
#define VER_FILEVERSION 0,59,1,0
|
||||
#define VER_FILEVERSION_STR "0.59.1"
|
||||
|
||||
#define VER_PRODUCTVERSION 0,59,1,0
|
||||
#define VER_PRODUCTVERSION_STR "0.59.1"
|
||||
|
||||
#ifdef RC_INVOKED
|
||||
|
||||
#ifdef DEBUG // TODO: Actually define DEBUG
|
||||
#define VER_DEBUG VS_FF_DEBUG
|
||||
#else
|
||||
#define VER_DEBUG 0
|
||||
#endif
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VER_FILEVERSION
|
||||
PRODUCTVERSION VER_PRODUCTVERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
FILEFLAGS VER_DEBUG
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "nushell"
|
||||
VALUE "FileDescription", "Nushell"
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "InternalName", "nu.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2022"
|
||||
VALUE "OriginalFilename", "nu.exe"
|
||||
VALUE "ProductName", "Nushell"
|
||||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#define IDI_ICON 0x101
|
||||
IDI_ICON ICON "assets/nu_logo.ico"
|
||||
#endif
|
23
build-all-maclin.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "---------------------------------------------------------------"
|
||||
echo "Building nushell (nu) with --features=extra and all the plugins"
|
||||
echo "---------------------------------------------------------------"
|
||||
echo ""
|
||||
|
||||
NU_PLUGINS=(
|
||||
'nu_plugin_example'
|
||||
'nu_plugin_gstat'
|
||||
'nu_plugin_inc'
|
||||
'nu_plugin_query'
|
||||
)
|
||||
|
||||
echo "Building nushell"
|
||||
cargo build --features=extra
|
||||
for plugin in "${NU_PLUGINS[@]}"
|
||||
do
|
||||
echo '' && cd crates/$plugin
|
||||
echo "Building $plugin..."
|
||||
echo "-----------------------------"
|
||||
cargo build && cd ../..
|
||||
done
|
32
build-all-windows.cmd
Normal file
@ -0,0 +1,32 @@
|
||||
@echo off
|
||||
@echo -------------------------------------------------------------------
|
||||
@echo Building nushell (nu.exe) with --features=extra and all the plugins
|
||||
@echo -------------------------------------------------------------------
|
||||
@echo.
|
||||
|
||||
echo Building nushell.exe
|
||||
cargo build --features=extra
|
||||
@echo.
|
||||
|
||||
@cd crates\nu_plugin_example
|
||||
echo Building nu_plugin_example.exe
|
||||
cargo build
|
||||
@echo.
|
||||
|
||||
@cd ..\..\crates\nu_plugin_gstat
|
||||
echo Building nu_plugin_gstat.exe
|
||||
cargo build
|
||||
@echo.
|
||||
|
||||
@cd ..\..\crates\nu_plugin_inc
|
||||
echo Building nu_plugin_inc.exe
|
||||
cargo build
|
||||
@echo.
|
||||
|
||||
@cd ..\..\crates\nu_plugin_query
|
||||
|
||||
echo Building nu_plugin_query.exe
|
||||
cargo build
|
||||
@echo.
|
||||
|
||||
@cd ..\..
|
22
build-all.nu
Normal file
@ -0,0 +1,22 @@
|
||||
echo '-------------------------------------------------------------------'
|
||||
echo 'Building nushell (nu) with --features=extra and all the plugins'
|
||||
echo '-------------------------------------------------------------------'
|
||||
|
||||
echo $'(char nl)Building nushell'
|
||||
echo '----------------------------'
|
||||
cargo build --features=extra
|
||||
|
||||
let plugins = [
|
||||
nu_plugin_inc,
|
||||
nu_plugin_gstat,
|
||||
nu_plugin_query,
|
||||
nu_plugin_example,
|
||||
]
|
||||
|
||||
for plugin in $plugins {
|
||||
$'(char nl)Building ($plugin)'
|
||||
'----------------------------'
|
||||
cd $'crates/($plugin)'
|
||||
cargo build
|
||||
ignore
|
||||
}
|
7
build.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#[cfg(windows)]
|
||||
fn main() {
|
||||
embed_resource::compile_for("assets/nushell.rc", &["nu"])
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn main() {}
|
13
crates/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Nushell core libraries and plugins
|
||||
|
||||
These sub-crates form both the foundation for Nu and a set of plugins which extend Nu with additional functionality.
|
||||
|
||||
Foundational libraries are split into two kinds of crates:
|
||||
|
||||
* Core crates - those crates that work together to build the Nushell language engine
|
||||
* Support crates - a set of crates that support the engine with additional features like JSON support, ANSI support, and more.
|
||||
|
||||
Plugins are likewise also split into two types:
|
||||
|
||||
* Core plugins - plugins that provide part of the default experience of Nu, including access to the system properties, processes, and web-connectivity features.
|
||||
* Extra plugins - these plugins run a wide range of different capabilities like working with different file types, charting, viewing binary data, and more.
|
@ -1,128 +1,27 @@
|
||||
[package]
|
||||
authors = ["The Nu Project Contributors"]
|
||||
description = "CLI for nushell"
|
||||
edition = "2018"
|
||||
authors = ["The Nushell Project Developers"]
|
||||
description = "CLI-related functionality for Nushell"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.20.0"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
version = "0.61.0"
|
||||
|
||||
[dependencies]
|
||||
nu-data = {version = "0.20.0", path = "../nu-data"}
|
||||
nu-errors = {version = "0.20.0", path = "../nu-errors"}
|
||||
nu-parser = {version = "0.20.0", path = "../nu-parser"}
|
||||
nu-plugin = {version = "0.20.0", path = "../nu-plugin"}
|
||||
nu-protocol = {version = "0.20.0", path = "../nu-protocol"}
|
||||
nu-source = {version = "0.20.0", path = "../nu-source"}
|
||||
nu-table = {version = "0.20.0", path = "../nu-table"}
|
||||
nu-test-support = {version = "0.20.0", path = "../nu-test-support"}
|
||||
nu-value-ext = {version = "0.20.0", path = "../nu-value-ext"}
|
||||
nu-engine = { path = "../nu-engine", version = "0.61.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.61.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.61.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.61.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.61.0" }
|
||||
nu-ansi-term = "0.45.1"
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.61.0" }
|
||||
|
||||
ansi_term = "0.12.1"
|
||||
async-recursion = "0.3.1"
|
||||
async-trait = "0.1.40"
|
||||
base64 = "0.12.3"
|
||||
bigdecimal = {version = "0.2.0", features = ["serde"]}
|
||||
byte-unit = "4.0.9"
|
||||
bytes = "0.5.6"
|
||||
calamine = "0.16.1"
|
||||
chrono = {version = "0.4.15", features = ["serde"]}
|
||||
clap = "2.33.3"
|
||||
codespan-reporting = "0.9.5"
|
||||
csv = "1.1.3"
|
||||
ctrlc = {version = "3.1.6", optional = true}
|
||||
derive-new = "0.5.8"
|
||||
directories = {version = "3.0.1", optional = true}
|
||||
dirs = {version = "3.0.1", optional = true}
|
||||
dtparse = "1.1.0"
|
||||
dunce = "1.0.1"
|
||||
eml-parser = "0.1.0"
|
||||
filesize = "0.2.0"
|
||||
fs_extra = "1.2.0"
|
||||
futures = {version = "0.3.5", features = ["compat", "io-compat"]}
|
||||
futures-util = "0.3.5"
|
||||
futures_codec = "0.4.1"
|
||||
getset = "0.1.1"
|
||||
git2 = {version = "0.13.11", default_features = false, optional = true}
|
||||
glob = "0.3.0"
|
||||
heim = {version = "0.1.0-beta.3", optional = true}
|
||||
htmlescape = "0.3.1"
|
||||
ical = "0.6.0"
|
||||
ichwh = {version = "0.3.4", optional = true}
|
||||
indexmap = {version = "1.6.0", features = ["serde-1"]}
|
||||
itertools = "0.9.0"
|
||||
log = "0.4.11"
|
||||
meval = "0.2.0"
|
||||
natural = "0.5.0"
|
||||
num-bigint = {version = "0.3.0", features = ["serde"]}
|
||||
num-format = {version = "0.4.0", features = ["with-num-bigint"]}
|
||||
num-traits = "0.2.12"
|
||||
parking_lot = "0.11.0"
|
||||
pin-utils = "0.1.0"
|
||||
pretty-hex = "0.2.0"
|
||||
ptree = {version = "0.3.0", optional = true}
|
||||
query_interface = "0.3.5"
|
||||
rand = "0.7.3"
|
||||
regex = "1.3.9"
|
||||
roxmltree = "0.13.0"
|
||||
rust-embed = "5.6.0"
|
||||
rustyline = {version = "6.3.0", optional = true}
|
||||
serde = {version = "1.0.115", features = ["derive"]}
|
||||
serde-hjson = "0.9.1"
|
||||
serde_bytes = "0.11.5"
|
||||
serde_ini = "0.2.0"
|
||||
serde_json = "1.0.57"
|
||||
serde_urlencoded = "0.7.0"
|
||||
serde_yaml = "0.8.13"
|
||||
sha2 = "0.9.1"
|
||||
shellexpand = "2.0.0"
|
||||
strip-ansi-escapes = "0.1.0"
|
||||
tempfile = "3.1.0"
|
||||
term = {version = "0.6.1", optional = true}
|
||||
term_size = "0.3.2"
|
||||
termcolor = "1.1.0"
|
||||
toml = "0.5.6"
|
||||
unicode-segmentation = "1.6.0"
|
||||
uom = {version = "0.28.0", features = ["f64", "try-from"]}
|
||||
uuid_crate = {package = "uuid", version = "0.8.1", features = ["v4"], optional = true}
|
||||
which = {version = "4.0.2", optional = true}
|
||||
zip = {version = "0.5.7", optional = true}
|
||||
crossterm = "0.23.0"
|
||||
miette = { version = "4.4.0", features = ["fancy"] }
|
||||
thiserror = "1.0.29"
|
||||
reedline = { version = "0.4.0", features = ["bashisms"]}
|
||||
|
||||
Inflector = "0.11"
|
||||
clipboard = {version = "0.5.0", optional = true}
|
||||
encoding_rs = "0.8.24"
|
||||
quick-xml = "0.18.1"
|
||||
rayon = "1.4.0"
|
||||
trash = {version = "1.1.1", optional = true}
|
||||
url = "2.1.1"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
umask = "1.0.0"
|
||||
users = "0.10.0"
|
||||
|
||||
# TODO this will be possible with new dependency resolver
|
||||
# (currently on nightly behind -Zfeatures=itarget):
|
||||
# https://github.com/rust-lang/cargo/issues/7914
|
||||
#[target.'cfg(not(windows))'.dependencies]
|
||||
#num-format = {version = "0.4", features = ["with-system-locale"]}
|
||||
|
||||
[dependencies.rusqlite]
|
||||
features = ["bundled", "blob"]
|
||||
optional = true
|
||||
version = "0.24.0"
|
||||
|
||||
[build-dependencies]
|
||||
git2 = {version = "0.13.11", optional = true}
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "0.9.2"
|
||||
quickcheck_macros = "0.9.1"
|
||||
log = "0.4"
|
||||
is_executable = "1.0.1"
|
||||
|
||||
[features]
|
||||
clipboard-cli = ["clipboard"]
|
||||
rich-benchmark = ["heim"]
|
||||
rustyline-support = ["rustyline"]
|
||||
stable = []
|
||||
trash-support = ["trash"]
|
||||
plugin = []
|
||||
|
21
crates/nu-cli/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 - 2022 The Nushell Project Developers
|
||||
|
||||
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.
|
@ -1,36 +0,0 @@
|
||||
use std::path::Path;
|
||||
use std::{env, fs, io};
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
let out_dir = env::var_os("OUT_DIR").expect(
|
||||
"\
|
||||
OUT_DIR environment variable not found. \
|
||||
OUT_DIR is guaranteed to to exist in a build script by cargo - see \
|
||||
https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts\
|
||||
");
|
||||
|
||||
let latest_commit_hash = latest_commit_hash(env::current_dir()?).unwrap_or_default();
|
||||
|
||||
let commit_hash_path = Path::new(&out_dir).join("git_commit_hash");
|
||||
fs::write(commit_hash_path, latest_commit_hash)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn latest_commit_hash<P: AsRef<Path>>(dir: P) -> Result<String, Box<dyn std::error::Error>> {
|
||||
#[cfg(feature = "git2")]
|
||||
{
|
||||
use git2::Repository;
|
||||
let dir = dir.as_ref();
|
||||
Ok(Repository::discover(dir)?
|
||||
.head()?
|
||||
.peel_to_commit()?
|
||||
.id()
|
||||
.to_string())
|
||||
}
|
||||
#[cfg(not(feature = "git2"))]
|
||||
{
|
||||
Ok(String::new())
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
use crate::commands::Command;
|
||||
use indexmap::IndexMap;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::SignatureRegistry;
|
||||
use nu_protocol::Signature;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct CommandRegistry {
|
||||
registry: Arc<Mutex<IndexMap<String, Command>>>,
|
||||
}
|
||||
|
||||
impl SignatureRegistry for CommandRegistry {
|
||||
fn has(&self, name: &str) -> bool {
|
||||
let registry = self.registry.lock();
|
||||
registry.contains_key(name)
|
||||
}
|
||||
fn get(&self, name: &str) -> Option<Signature> {
|
||||
let registry = self.registry.lock();
|
||||
registry.get(name).map(|command| command.signature())
|
||||
}
|
||||
fn clone_box(&self) -> Box<dyn SignatureRegistry> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandRegistry {
|
||||
pub fn new() -> CommandRegistry {
|
||||
CommandRegistry {
|
||||
registry: Arc::new(Mutex::new(IndexMap::default())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandRegistry {
|
||||
pub fn get_command(&self, name: &str) -> Option<Command> {
|
||||
let registry = self.registry.lock();
|
||||
|
||||
registry.get(name).cloned()
|
||||
}
|
||||
|
||||
pub fn expect_command(&self, name: &str) -> Result<Command, ShellError> {
|
||||
self.get_command(name).ok_or_else(|| {
|
||||
ShellError::untagged_runtime_error(format!("Could not load command: {}", name))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn has(&self, name: &str) -> bool {
|
||||
let registry = self.registry.lock();
|
||||
|
||||
registry.contains_key(name)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, name: impl Into<String>, command: Command) {
|
||||
let mut registry = self.registry.lock();
|
||||
registry.insert(name.into(), command);
|
||||
}
|
||||
|
||||
pub fn names(&self) -> Vec<String> {
|
||||
let registry = self.registry.lock();
|
||||
registry.keys().cloned().collect()
|
||||
}
|
||||
}
|
@ -1,270 +1,99 @@
|
||||
#[macro_use]
|
||||
pub(crate) mod macros;
|
||||
use crate::util::report_error;
|
||||
use log::info;
|
||||
use miette::Result;
|
||||
use nu_engine::{convert_env_values, eval_block};
|
||||
use nu_parser::{parse, trim_quotes};
|
||||
use nu_protocol::engine::Stack;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, StateDelta, StateWorkingSet},
|
||||
Config, PipelineData, Spanned,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
mod from_delimited_data;
|
||||
mod to_delimited_data;
|
||||
pub fn evaluate_commands(
|
||||
commands: &Spanned<String>,
|
||||
init_cwd: &Path,
|
||||
engine_state: &mut EngineState,
|
||||
stack: &mut Stack,
|
||||
input: PipelineData,
|
||||
is_perf_true: bool,
|
||||
) -> Result<()> {
|
||||
// Run a command (or commands) given to us by the user
|
||||
let (block, delta) = {
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
pub(crate) mod alias;
|
||||
pub(crate) mod ansi;
|
||||
pub(crate) mod append;
|
||||
pub(crate) mod args;
|
||||
pub(crate) mod autoenv;
|
||||
pub(crate) mod autoenv_trust;
|
||||
pub(crate) mod autoenv_untrust;
|
||||
pub(crate) mod autoview;
|
||||
pub(crate) mod benchmark;
|
||||
pub(crate) mod build_string;
|
||||
pub(crate) mod cal;
|
||||
pub(crate) mod cd;
|
||||
pub(crate) mod char_;
|
||||
pub(crate) mod classified;
|
||||
#[cfg(feature = "clipboard-cli")]
|
||||
pub(crate) mod clip;
|
||||
pub(crate) mod command;
|
||||
pub(crate) mod compact;
|
||||
pub(crate) mod config;
|
||||
pub(crate) mod constants;
|
||||
pub(crate) mod count;
|
||||
pub(crate) mod cp;
|
||||
pub(crate) mod date;
|
||||
pub(crate) mod debug;
|
||||
pub(crate) mod default;
|
||||
pub(crate) mod do_;
|
||||
pub(crate) mod drop;
|
||||
pub(crate) mod du;
|
||||
pub(crate) mod each;
|
||||
pub(crate) mod echo;
|
||||
pub(crate) mod enter;
|
||||
pub(crate) mod every;
|
||||
pub(crate) mod exec;
|
||||
pub(crate) mod exit;
|
||||
pub(crate) mod first;
|
||||
pub(crate) mod format;
|
||||
pub(crate) mod from;
|
||||
pub(crate) mod from_csv;
|
||||
pub(crate) mod from_eml;
|
||||
pub(crate) mod from_ics;
|
||||
pub(crate) mod from_ini;
|
||||
pub(crate) mod from_json;
|
||||
pub(crate) mod from_ods;
|
||||
pub(crate) mod from_ssv;
|
||||
pub(crate) mod from_toml;
|
||||
pub(crate) mod from_tsv;
|
||||
pub(crate) mod from_url;
|
||||
pub(crate) mod from_vcf;
|
||||
pub(crate) mod from_xlsx;
|
||||
pub(crate) mod from_xml;
|
||||
pub(crate) mod from_yaml;
|
||||
pub(crate) mod get;
|
||||
pub(crate) mod group_by;
|
||||
pub(crate) mod group_by_date;
|
||||
pub(crate) mod headers;
|
||||
pub(crate) mod help;
|
||||
pub(crate) mod histogram;
|
||||
pub(crate) mod history;
|
||||
pub(crate) mod if_;
|
||||
pub(crate) mod insert;
|
||||
pub(crate) mod into_int;
|
||||
pub(crate) mod is_empty;
|
||||
pub(crate) mod keep;
|
||||
pub(crate) mod last;
|
||||
pub(crate) mod lines;
|
||||
pub(crate) mod ls;
|
||||
pub(crate) mod math;
|
||||
pub(crate) mod merge;
|
||||
pub(crate) mod mkdir;
|
||||
pub(crate) mod move_;
|
||||
pub(crate) mod next;
|
||||
pub(crate) mod nth;
|
||||
pub(crate) mod nu;
|
||||
pub(crate) mod open;
|
||||
pub(crate) mod parse;
|
||||
pub(crate) mod path;
|
||||
pub(crate) mod pivot;
|
||||
pub(crate) mod prepend;
|
||||
pub(crate) mod prev;
|
||||
pub(crate) mod pwd;
|
||||
pub(crate) mod random;
|
||||
pub(crate) mod range;
|
||||
pub(crate) mod reduce;
|
||||
pub(crate) mod reject;
|
||||
pub(crate) mod rename;
|
||||
pub(crate) mod reverse;
|
||||
pub(crate) mod rm;
|
||||
pub(crate) mod run_alias;
|
||||
pub(crate) mod run_external;
|
||||
pub(crate) mod save;
|
||||
pub(crate) mod select;
|
||||
pub(crate) mod shells;
|
||||
pub(crate) mod shuffle;
|
||||
pub(crate) mod size;
|
||||
pub(crate) mod skip;
|
||||
pub(crate) mod sleep;
|
||||
pub(crate) mod sort_by;
|
||||
pub(crate) mod split;
|
||||
pub(crate) mod split_by;
|
||||
pub(crate) mod str_;
|
||||
pub(crate) mod table;
|
||||
pub(crate) mod tags;
|
||||
pub(crate) mod to;
|
||||
pub(crate) mod to_csv;
|
||||
pub(crate) mod to_html;
|
||||
pub(crate) mod to_json;
|
||||
pub(crate) mod to_md;
|
||||
pub(crate) mod to_toml;
|
||||
pub(crate) mod to_tsv;
|
||||
pub(crate) mod to_url;
|
||||
pub(crate) mod to_xml;
|
||||
pub(crate) mod to_yaml;
|
||||
pub(crate) mod uniq;
|
||||
pub(crate) mod update;
|
||||
pub(crate) mod url_;
|
||||
pub(crate) mod version;
|
||||
pub(crate) mod what;
|
||||
pub(crate) mod where_;
|
||||
pub(crate) mod which_;
|
||||
pub(crate) mod with_env;
|
||||
pub(crate) mod wrap;
|
||||
let (input, _) = if commands.item.starts_with('\'') || commands.item.starts_with('"') {
|
||||
(
|
||||
trim_quotes(commands.item.as_bytes()),
|
||||
commands.span.start + 1,
|
||||
)
|
||||
} else {
|
||||
(commands.item.as_bytes(), commands.span.start)
|
||||
};
|
||||
|
||||
pub(crate) use autoview::Autoview;
|
||||
pub(crate) use cd::Cd;
|
||||
pub(crate) use command::{
|
||||
whole_stream_command, Command, Example, UnevaluatedCallInfo, WholeStreamCommand,
|
||||
};
|
||||
let (output, err) = parse(&mut working_set, None, input, false, &[]);
|
||||
if let Some(err) = err {
|
||||
report_error(&working_set, &err);
|
||||
|
||||
pub(crate) use alias::Alias;
|
||||
pub(crate) use ansi::Ansi;
|
||||
pub(crate) use append::Append;
|
||||
pub(crate) use autoenv::Autoenv;
|
||||
pub(crate) use autoenv_trust::AutoenvTrust;
|
||||
pub(crate) use autoenv_untrust::AutoenvUnTrust;
|
||||
pub(crate) use benchmark::Benchmark;
|
||||
pub(crate) use build_string::BuildString;
|
||||
pub(crate) use cal::Cal;
|
||||
pub(crate) use char_::Char;
|
||||
pub(crate) use compact::Compact;
|
||||
pub(crate) use config::{
|
||||
Config, ConfigClear, ConfigGet, ConfigLoad, ConfigPath, ConfigRemove, ConfigSet, ConfigSetInto,
|
||||
};
|
||||
pub(crate) use count::Count;
|
||||
pub(crate) use cp::Cpy;
|
||||
pub(crate) use date::{Date, DateFormat, DateNow, DateUTC};
|
||||
pub(crate) use debug::Debug;
|
||||
pub(crate) use default::Default;
|
||||
pub(crate) use do_::Do;
|
||||
pub(crate) use drop::Drop;
|
||||
pub(crate) use du::Du;
|
||||
pub(crate) use each::Each;
|
||||
pub(crate) use each::EachGroup;
|
||||
pub(crate) use each::EachWindow;
|
||||
pub(crate) use echo::Echo;
|
||||
pub(crate) use if_::If;
|
||||
pub(crate) use is_empty::IsEmpty;
|
||||
pub(crate) use nu::NuPlugin;
|
||||
pub(crate) use update::Update;
|
||||
pub(crate) mod kill;
|
||||
pub(crate) use kill::Kill;
|
||||
pub(crate) mod clear;
|
||||
pub(crate) use clear::Clear;
|
||||
pub(crate) mod touch;
|
||||
pub(crate) use enter::Enter;
|
||||
pub(crate) use every::Every;
|
||||
pub(crate) use exec::Exec;
|
||||
pub(crate) use exit::Exit;
|
||||
pub(crate) use first::First;
|
||||
pub(crate) use format::Format;
|
||||
pub(crate) use from::From;
|
||||
pub(crate) use from_csv::FromCSV;
|
||||
pub(crate) use from_eml::FromEML;
|
||||
pub(crate) use from_ics::FromIcs;
|
||||
pub(crate) use from_ini::FromINI;
|
||||
pub(crate) use from_json::FromJSON;
|
||||
pub(crate) use from_ods::FromODS;
|
||||
pub(crate) use from_ssv::FromSSV;
|
||||
pub(crate) use from_toml::FromTOML;
|
||||
pub(crate) use from_tsv::FromTSV;
|
||||
pub(crate) use from_url::FromURL;
|
||||
pub(crate) use from_vcf::FromVcf;
|
||||
pub(crate) use from_xlsx::FromXLSX;
|
||||
pub(crate) use from_xml::FromXML;
|
||||
pub(crate) use from_yaml::FromYAML;
|
||||
pub(crate) use from_yaml::FromYML;
|
||||
pub(crate) use get::Get;
|
||||
pub(crate) use group_by::GroupBy;
|
||||
pub(crate) use group_by_date::GroupByDate;
|
||||
pub(crate) use headers::Headers;
|
||||
pub(crate) use help::Help;
|
||||
pub(crate) use histogram::Histogram;
|
||||
pub(crate) use history::History;
|
||||
pub(crate) use insert::Insert;
|
||||
pub(crate) use into_int::IntoInt;
|
||||
pub(crate) use keep::{Keep, KeepUntil, KeepWhile};
|
||||
pub(crate) use last::Last;
|
||||
pub(crate) use lines::Lines;
|
||||
pub(crate) use ls::Ls;
|
||||
pub(crate) use math::{
|
||||
Math, MathAverage, MathEval, MathMaximum, MathMedian, MathMinimum, MathMode, MathProduct,
|
||||
MathStddev, MathSummation, MathVariance,
|
||||
};
|
||||
pub(crate) use merge::Merge;
|
||||
pub(crate) use mkdir::Mkdir;
|
||||
pub(crate) use move_::{Move, MoveColumn, Mv};
|
||||
pub(crate) use next::Next;
|
||||
pub(crate) use nth::Nth;
|
||||
pub(crate) use open::Open;
|
||||
pub(crate) use parse::Parse;
|
||||
pub(crate) use path::{
|
||||
PathBasename, PathCommand, PathDirname, PathExists, PathExpand, PathExtension, PathFilestem,
|
||||
PathType,
|
||||
};
|
||||
pub(crate) use pivot::Pivot;
|
||||
pub(crate) use prepend::Prepend;
|
||||
pub(crate) use prev::Previous;
|
||||
pub(crate) use pwd::Pwd;
|
||||
#[cfg(feature = "uuid_crate")]
|
||||
pub(crate) use random::RandomUUID;
|
||||
pub(crate) use random::{Random, RandomBool, RandomDice, RandomInteger};
|
||||
pub(crate) use range::Range;
|
||||
pub(crate) use reduce::Reduce;
|
||||
pub(crate) use reject::Reject;
|
||||
pub(crate) use rename::Rename;
|
||||
pub(crate) use reverse::Reverse;
|
||||
pub(crate) use rm::Remove;
|
||||
pub(crate) use run_external::RunExternalCommand;
|
||||
pub(crate) use save::Save;
|
||||
pub(crate) use select::Select;
|
||||
pub(crate) use shells::Shells;
|
||||
pub(crate) use shuffle::Shuffle;
|
||||
pub(crate) use size::Size;
|
||||
pub(crate) use skip::{Skip, SkipUntil, SkipWhile};
|
||||
pub(crate) use sleep::Sleep;
|
||||
pub(crate) use sort_by::SortBy;
|
||||
pub(crate) use split::{Split, SplitChars, SplitColumn, SplitRow};
|
||||
pub(crate) use split_by::SplitBy;
|
||||
pub(crate) use str_::{
|
||||
Str, StrCamelCase, StrCapitalize, StrCollect, StrContains, StrDowncase, StrEndsWith,
|
||||
StrFindReplace, StrFrom, StrIndexOf, StrKebabCase, StrLength, StrPascalCase, StrReverse,
|
||||
StrScreamingSnakeCase, StrSet, StrSnakeCase, StrStartsWith, StrSubstring, StrToDatetime,
|
||||
StrToDecimal, StrToInteger, StrTrim, StrTrimLeft, StrTrimRight, StrUpcase,
|
||||
};
|
||||
pub(crate) use table::Table;
|
||||
pub(crate) use tags::Tags;
|
||||
pub(crate) use to::To;
|
||||
pub(crate) use to_csv::ToCSV;
|
||||
pub(crate) use to_html::ToHTML;
|
||||
pub(crate) use to_json::ToJSON;
|
||||
pub(crate) use to_md::ToMarkdown;
|
||||
pub(crate) use to_toml::ToTOML;
|
||||
pub(crate) use to_tsv::ToTSV;
|
||||
pub(crate) use to_url::ToURL;
|
||||
pub(crate) use to_xml::ToXML;
|
||||
pub(crate) use to_yaml::ToYAML;
|
||||
pub(crate) use touch::Touch;
|
||||
pub(crate) use uniq::Uniq;
|
||||
pub(crate) use url_::{UrlCommand, UrlHost, UrlPath, UrlQuery, UrlScheme};
|
||||
pub(crate) use version::Version;
|
||||
pub(crate) use what::What;
|
||||
pub(crate) use where_::Where;
|
||||
pub(crate) use which_::Which;
|
||||
pub(crate) use with_env::WithEnv;
|
||||
pub(crate) use wrap::Wrap;
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
(output, working_set.render())
|
||||
};
|
||||
|
||||
if let Err(err) = engine_state.merge_delta(delta, None, init_cwd) {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(&working_set, &err);
|
||||
}
|
||||
|
||||
let config = match stack.get_config() {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
report_error(&working_set, &e);
|
||||
Config::default()
|
||||
}
|
||||
};
|
||||
|
||||
// Merge the delta in case env vars changed in the config
|
||||
match nu_engine::env::current_dir(engine_state, stack) {
|
||||
Ok(cwd) => {
|
||||
if let Err(e) = engine_state.merge_delta(StateDelta::new(), Some(stack), cwd) {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(&working_set, &e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(&working_set, &e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Translate environment variables from Strings to Values
|
||||
if let Some(e) = convert_env_values(engine_state, stack) {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(&working_set, &e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
match eval_block(engine_state, stack, &block, input, false, false) {
|
||||
Ok(pipeline_data) => {
|
||||
crate::eval_file::print_table_or_error(engine_state, stack, pipeline_data, &config)
|
||||
}
|
||||
Err(err) => {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
report_error(&working_set, &err);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if is_perf_true {
|
||||
info!("evaluate {}:{}:{}", file!(), line!(), column!());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,350 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_data::config;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::SignatureRegistry;
|
||||
use nu_protocol::hir::{ClassifiedCommand, Expression, NamedValue, SpannedExpression, Variable};
|
||||
use nu_protocol::{
|
||||
hir::Block, CommandAction, NamedType, PositionalType, ReturnSuccess, Signature, SyntaxShape,
|
||||
UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct Alias;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct AliasArgs {
|
||||
pub name: Tagged<String>,
|
||||
pub args: Vec<Value>,
|
||||
pub block: Block,
|
||||
pub infer: Option<bool>,
|
||||
pub save: Option<bool>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Alias {
|
||||
fn name(&self) -> &str {
|
||||
"alias"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("alias")
|
||||
.required("name", SyntaxShape::String, "the name of the alias")
|
||||
.required("args", SyntaxShape::Table, "the arguments to the alias")
|
||||
.required(
|
||||
"block",
|
||||
SyntaxShape::Block,
|
||||
"the block to run as the body of the alias",
|
||||
)
|
||||
.switch("infer", "infer argument types (experimental)", Some('i'))
|
||||
.switch("save", "save the alias to your config", Some('s'))
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Define a shortcut for another command."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
alias(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "An alias without parameters",
|
||||
example: "alias say-hi [] { echo 'Hello!' }",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "An alias with a single parameter",
|
||||
example: "alias l [x] { ls $x }",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn alias(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let mut raw_input = args.raw_input.clone();
|
||||
let (
|
||||
AliasArgs {
|
||||
name,
|
||||
args: list,
|
||||
block,
|
||||
infer,
|
||||
save,
|
||||
},
|
||||
_ctx,
|
||||
) = args.process(®istry).await?;
|
||||
let mut processed_args: Vec<String> = vec![];
|
||||
|
||||
if let Some(true) = save {
|
||||
let mut result = nu_data::config::read(name.clone().tag, &None)?;
|
||||
|
||||
// process the alias to remove the --save flag
|
||||
let left_brace = raw_input.find('{').unwrap_or(0);
|
||||
let right_brace = raw_input.rfind('}').unwrap_or_else(|| raw_input.len());
|
||||
let left = raw_input[..left_brace]
|
||||
.replace("--save", "") // TODO using regex (or reconstruct string from AST?)
|
||||
.replace("-si", "-i")
|
||||
.replace("-s ", "")
|
||||
.replace("-is", "-i");
|
||||
let right = raw_input[right_brace..]
|
||||
.replace("--save", "")
|
||||
.replace("-si", "-i")
|
||||
.replace("-s ", "")
|
||||
.replace("-is", "-i");
|
||||
raw_input = format!("{}{}{}", left, &raw_input[left_brace..right_brace], right);
|
||||
|
||||
// create a value from raw_input alias
|
||||
let alias: Value = raw_input.trim().to_string().into();
|
||||
let alias_start = raw_input.find('[').unwrap_or(0); // used to check if the same alias already exists
|
||||
|
||||
// add to startup if alias doesn't exist and replce if it does
|
||||
match result.get_mut("startup") {
|
||||
Some(startup) => {
|
||||
if let UntaggedValue::Table(ref mut commands) = startup.value {
|
||||
if let Some(command) = commands.iter_mut().find(|command| {
|
||||
let cmd_str = command.as_string().unwrap_or_default();
|
||||
cmd_str.starts_with(&raw_input[..alias_start])
|
||||
}) {
|
||||
*command = alias;
|
||||
} else {
|
||||
commands.push(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let table = UntaggedValue::table(&[alias]);
|
||||
result.insert("startup".to_string(), table.into_value(Tag::default()));
|
||||
}
|
||||
}
|
||||
config::write(&result, &None)?;
|
||||
}
|
||||
|
||||
for item in list.iter() {
|
||||
if let Ok(string) = item.as_string() {
|
||||
processed_args.push(format!("${}", string));
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a string",
|
||||
"expected a string",
|
||||
item.tag(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(true) = infer {
|
||||
Ok(OutputStream::one(ReturnSuccess::action(
|
||||
CommandAction::AddAlias(
|
||||
name.to_string(),
|
||||
to_arg_shapes(processed_args, &block, ®istry)?,
|
||||
block,
|
||||
),
|
||||
)))
|
||||
} else {
|
||||
Ok(OutputStream::one(ReturnSuccess::action(
|
||||
CommandAction::AddAlias(
|
||||
name.to_string(),
|
||||
processed_args
|
||||
.into_iter()
|
||||
.map(|arg| (arg, SyntaxShape::Any))
|
||||
.collect(),
|
||||
block,
|
||||
),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn to_arg_shapes(
|
||||
args: Vec<String>,
|
||||
block: &Block,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<Vec<(String, SyntaxShape)>, ShellError> {
|
||||
match find_block_shapes(block, registry) {
|
||||
Ok(found) => Ok(args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
(
|
||||
arg.clone(),
|
||||
match found.get(arg) {
|
||||
None | Some((_, None)) => SyntaxShape::Any,
|
||||
Some((_, Some(shape))) => *shape,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect()),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
type ShapeMap = HashMap<String, (Span, Option<SyntaxShape>)>;
|
||||
|
||||
fn check_insert(
|
||||
existing: &mut ShapeMap,
|
||||
to_add: (String, (Span, Option<SyntaxShape>)),
|
||||
) -> Result<(), ShellError> {
|
||||
match (to_add.1).1 {
|
||||
None => match existing.get(&to_add.0) {
|
||||
None => {
|
||||
existing.insert(to_add.0, to_add.1);
|
||||
Ok(())
|
||||
}
|
||||
Some(_) => Ok(()),
|
||||
},
|
||||
Some(new) => match existing.insert(to_add.0.clone(), ((to_add.1).0, Some(new))) {
|
||||
None => Ok(()),
|
||||
Some(exist) => match exist.1 {
|
||||
None => Ok(()),
|
||||
Some(shape) => match shape {
|
||||
SyntaxShape::Any => Ok(()),
|
||||
shape if shape == new => Ok(()),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Type conflict in alias variable use",
|
||||
format!("{:?}", new),
|
||||
(to_add.1).0,
|
||||
format!("{:?}", shape),
|
||||
exist.0,
|
||||
)),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn check_merge(existing: &mut ShapeMap, new: &ShapeMap) -> Result<(), ShellError> {
|
||||
for (k, v) in new.iter() {
|
||||
check_insert(existing, (k.clone(), *v))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_expr_shapes(
|
||||
spanned_expr: &SpannedExpression,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<ShapeMap, ShellError> {
|
||||
match &spanned_expr.expr {
|
||||
// TODO range will need similar if/when invocations can be parsed within range expression
|
||||
Expression::Binary(bin) => find_expr_shapes(&bin.left, registry).and_then(|mut left| {
|
||||
find_expr_shapes(&bin.right, registry)
|
||||
.and_then(|right| check_merge(&mut left, &right).map(|()| left))
|
||||
}),
|
||||
Expression::Block(b) => find_block_shapes(&b, registry),
|
||||
Expression::Path(path) => match &path.head.expr {
|
||||
Expression::Invocation(b) => find_block_shapes(&b, registry),
|
||||
Expression::Variable(Variable::Other(var, _)) => {
|
||||
let mut result = HashMap::new();
|
||||
result.insert(var.to_string(), (spanned_expr.span, None));
|
||||
Ok(result)
|
||||
}
|
||||
_ => Ok(HashMap::new()),
|
||||
},
|
||||
_ => Ok(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_block_shapes(block: &Block, registry: &CommandRegistry) -> Result<ShapeMap, ShellError> {
|
||||
let apply_shape = |found: ShapeMap, sig_shape: SyntaxShape| -> ShapeMap {
|
||||
found
|
||||
.iter()
|
||||
.map(|(v, sh)| match sh.1 {
|
||||
None => (v.clone(), (sh.0, Some(sig_shape))),
|
||||
Some(shape) => (v.clone(), (sh.0, Some(shape))),
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
let mut arg_shapes = HashMap::new();
|
||||
for pipeline in &block.block {
|
||||
for classified in &pipeline.list {
|
||||
match classified {
|
||||
ClassifiedCommand::Expr(spanned_expr) => {
|
||||
let found = find_expr_shapes(&spanned_expr, registry)?;
|
||||
check_merge(&mut arg_shapes, &found)?
|
||||
}
|
||||
ClassifiedCommand::Internal(internal) => {
|
||||
if let Some(signature) = registry.get(&internal.name) {
|
||||
if let Some(positional) = &internal.args.positional {
|
||||
for (i, spanned_expr) in positional.iter().enumerate() {
|
||||
let found = find_expr_shapes(&spanned_expr, registry)?;
|
||||
if i >= signature.positional.len() {
|
||||
if let Some((sig_shape, _)) = &signature.rest_positional {
|
||||
check_merge(
|
||||
&mut arg_shapes,
|
||||
&apply_shape(found, *sig_shape),
|
||||
)?;
|
||||
} else {
|
||||
unreachable!("should have error'd in parsing");
|
||||
}
|
||||
} else {
|
||||
let (pos_type, _) = &signature.positional[i];
|
||||
match pos_type {
|
||||
// TODO pass on mandatory/optional?
|
||||
PositionalType::Mandatory(_, sig_shape)
|
||||
| PositionalType::Optional(_, sig_shape) => {
|
||||
check_merge(
|
||||
&mut arg_shapes,
|
||||
&apply_shape(found, *sig_shape),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(named) = &internal.args.named {
|
||||
for (name, val) in named.iter() {
|
||||
if let NamedValue::Value(_, spanned_expr) = val {
|
||||
let found = find_expr_shapes(&spanned_expr, registry)?;
|
||||
match signature.named.get(name) {
|
||||
None => {
|
||||
unreachable!("should have error'd in parsing");
|
||||
}
|
||||
Some((named_type, _)) => {
|
||||
if let NamedType::Mandatory(_, sig_shape)
|
||||
| NamedType::Optional(_, sig_shape) = named_type
|
||||
{
|
||||
check_merge(
|
||||
&mut arg_shapes,
|
||||
&apply_shape(found, *sig_shape),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable!("registry has lost name it provided");
|
||||
}
|
||||
}
|
||||
ClassifiedCommand::Dynamic(_) | ClassifiedCommand::Error(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(arg_shapes)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Alias;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Alias {})
|
||||
}
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use ansi_term::Color;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct Ansi;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct AnsiArgs {
|
||||
color: Value,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Ansi {
|
||||
fn name(&self) -> &str {
|
||||
"ansi"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("ansi").required(
|
||||
"color",
|
||||
SyntaxShape::Any,
|
||||
"the name of the color to use or 'reset' to reset the color",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Output ANSI codes to change color"
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Change color to green",
|
||||
example: r#"ansi green"#,
|
||||
result: Some(vec![Value::from("\u{1b}[32m")]),
|
||||
},
|
||||
Example {
|
||||
description: "Reset the color",
|
||||
example: r#"ansi reset"#,
|
||||
result: Some(vec![Value::from("\u{1b}[0m")]),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Use ansi to color text (rb = red bold, gb = green bold, pb = purple bold)",
|
||||
example: r#"echo [$(ansi rb) Hello " " $(ansi gb) Nu " " $(ansi pb) World] | str collect"#,
|
||||
result: Some(vec![Value::from(
|
||||
"\u{1b}[1;31mHello \u{1b}[1;32mNu \u{1b}[1;35mWorld",
|
||||
)]),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let (AnsiArgs { color }, _) = args.process(®istry).await?;
|
||||
|
||||
let color_string = color.as_string()?;
|
||||
|
||||
let ansi_code = str_to_ansi_color(color_string);
|
||||
|
||||
if let Some(output) = ansi_code {
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(output).into_value(color.tag()),
|
||||
)))
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Unknown color",
|
||||
"unknown color",
|
||||
color.tag(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn str_to_ansi_color(s: String) -> Option<String> {
|
||||
match s.as_str() {
|
||||
"g" | "green" => Some(Color::Green.prefix().to_string()),
|
||||
"gb" | "green_bold" => Some(Color::Green.bold().prefix().to_string()),
|
||||
"gu" | "green_underline" => Some(Color::Green.underline().prefix().to_string()),
|
||||
"gi" | "green_italic" => Some(Color::Green.italic().prefix().to_string()),
|
||||
"gd" | "green_dimmed" => Some(Color::Green.dimmed().prefix().to_string()),
|
||||
"gr" | "green_reverse" => Some(Color::Green.reverse().prefix().to_string()),
|
||||
"r" | "red" => Some(Color::Red.prefix().to_string()),
|
||||
"rb" | "red_bold" => Some(Color::Red.bold().prefix().to_string()),
|
||||
"ru" | "red_underline" => Some(Color::Red.underline().prefix().to_string()),
|
||||
"ri" | "red_italic" => Some(Color::Red.italic().prefix().to_string()),
|
||||
"rd" | "red_dimmed" => Some(Color::Red.dimmed().prefix().to_string()),
|
||||
"rr" | "red_reverse" => Some(Color::Red.reverse().prefix().to_string()),
|
||||
"u" | "blue" => Some(Color::Blue.prefix().to_string()),
|
||||
"ub" | "blue_bold" => Some(Color::Blue.bold().prefix().to_string()),
|
||||
"uu" | "blue_underline" => Some(Color::Blue.underline().prefix().to_string()),
|
||||
"ui" | "blue_italic" => Some(Color::Blue.italic().prefix().to_string()),
|
||||
"ud" | "blue_dimmed" => Some(Color::Blue.dimmed().prefix().to_string()),
|
||||
"ur" | "blue_reverse" => Some(Color::Blue.reverse().prefix().to_string()),
|
||||
"b" | "black" => Some(Color::Black.prefix().to_string()),
|
||||
"bb" | "black_bold" => Some(Color::Black.bold().prefix().to_string()),
|
||||
"bu" | "black_underline" => Some(Color::Black.underline().prefix().to_string()),
|
||||
"bi" | "black_italic" => Some(Color::Black.italic().prefix().to_string()),
|
||||
"bd" | "black_dimmed" => Some(Color::Black.dimmed().prefix().to_string()),
|
||||
"br" | "black_reverse" => Some(Color::Black.reverse().prefix().to_string()),
|
||||
"y" | "yellow" => Some(Color::Yellow.prefix().to_string()),
|
||||
"yb" | "yellow_bold" => Some(Color::Yellow.bold().prefix().to_string()),
|
||||
"yu" | "yellow_underline" => Some(Color::Yellow.underline().prefix().to_string()),
|
||||
"yi" | "yellow_italic" => Some(Color::Yellow.italic().prefix().to_string()),
|
||||
"yd" | "yellow_dimmed" => Some(Color::Yellow.dimmed().prefix().to_string()),
|
||||
"yr" | "yellow_reverse" => Some(Color::Yellow.reverse().prefix().to_string()),
|
||||
"p" | "purple" => Some(Color::Purple.prefix().to_string()),
|
||||
"pb" | "purple_bold" => Some(Color::Purple.bold().prefix().to_string()),
|
||||
"pu" | "purple_underline" => Some(Color::Purple.underline().prefix().to_string()),
|
||||
"pi" | "purple_italic" => Some(Color::Purple.italic().prefix().to_string()),
|
||||
"pd" | "purple_dimmed" => Some(Color::Purple.dimmed().prefix().to_string()),
|
||||
"pr" | "purple_reverse" => Some(Color::Purple.reverse().prefix().to_string()),
|
||||
"c" | "cyan" => Some(Color::Cyan.prefix().to_string()),
|
||||
"cb" | "cyan_bold" => Some(Color::Cyan.bold().prefix().to_string()),
|
||||
"cu" | "cyan_underline" => Some(Color::Cyan.underline().prefix().to_string()),
|
||||
"ci" | "cyan_italic" => Some(Color::Cyan.italic().prefix().to_string()),
|
||||
"cd" | "cyan_dimmed" => Some(Color::Cyan.dimmed().prefix().to_string()),
|
||||
"cr" | "cyan_reverse" => Some(Color::Cyan.reverse().prefix().to_string()),
|
||||
"w" | "white" => Some(Color::White.prefix().to_string()),
|
||||
"wb" | "white_bold" => Some(Color::White.bold().prefix().to_string()),
|
||||
"wu" | "white_underline" => Some(Color::White.underline().prefix().to_string()),
|
||||
"wi" | "white_italic" => Some(Color::White.italic().prefix().to_string()),
|
||||
"wd" | "white_dimmed" => Some(Color::White.dimmed().prefix().to_string()),
|
||||
"wr" | "white_reverse" => Some(Color::White.reverse().prefix().to_string()),
|
||||
"reset" => Some("\x1b[0m".to_owned()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Ansi;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Ansi {})
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct AppendArgs {
|
||||
row: Value,
|
||||
}
|
||||
|
||||
pub struct Append;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Append {
|
||||
fn name(&self) -> &str {
|
||||
"append"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("append").required(
|
||||
"row value",
|
||||
SyntaxShape::Any,
|
||||
"the value of the row to append to the table",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Append the given row to the table"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let (AppendArgs { row }, input) = args.process(registry).await?;
|
||||
|
||||
let eos = futures::stream::iter(vec![row]);
|
||||
|
||||
Ok(input.chain(eos).to_output_stream())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Add something to the end of a list or table",
|
||||
example: "echo [1 2 3] | append 4",
|
||||
result: Some(vec![
|
||||
UntaggedValue::int(1).into(),
|
||||
UntaggedValue::int(2).into(),
|
||||
UntaggedValue::int(3).into(),
|
||||
UntaggedValue::int(4).into(),
|
||||
]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Append;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Append {})
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
use nu_protocol::Value;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LogLevel {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LogItem {
|
||||
level: LogLevel,
|
||||
value: Value,
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
pub struct Autoenv;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||
pub struct Trusted {
|
||||
pub files: IndexMap<String, Vec<u8>>,
|
||||
}
|
||||
impl Trusted {
|
||||
pub fn new() -> Self {
|
||||
Trusted {
|
||||
files: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn file_is_trusted(nu_env_file: &PathBuf, content: &[u8]) -> Result<bool, ShellError> {
|
||||
let contentdigest = Sha256::digest(&content).as_slice().to_vec();
|
||||
let nufile = std::fs::canonicalize(nu_env_file)?;
|
||||
|
||||
let trusted = read_trusted()?;
|
||||
Ok(trusted.files.get(&nufile.to_string_lossy().to_string()) == Some(&contentdigest))
|
||||
}
|
||||
|
||||
pub fn read_trusted() -> Result<Trusted, ShellError> {
|
||||
let config_path = config::default_path_for(&Some(PathBuf::from("nu-env.toml")))?;
|
||||
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.create(true)
|
||||
.write(true)
|
||||
.open(config_path)
|
||||
.map_err(|_| ShellError::untagged_runtime_error("Couldn't open nu-env.toml"))?;
|
||||
let mut doc = String::new();
|
||||
file.read_to_string(&mut doc)?;
|
||||
|
||||
let allowed = toml::de::from_str(doc.as_str()).unwrap_or_else(|_| Trusted::new());
|
||||
Ok(allowed)
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Autoenv {
|
||||
fn name(&self) -> &str {
|
||||
"autoenv"
|
||||
}
|
||||
fn usage(&self) -> &str {
|
||||
// "Mark a .nu-env file in a directory as trusted. Needs to be re-run after each change to the file or its filepath."
|
||||
r#"Manage directory specific environment variables and scripts. Create a file called .nu-env in any directory and run 'autoenv trust' to let nushell read it when entering the directory.
|
||||
The file can contain several optional sections:
|
||||
env: environment variables to set when visiting the directory. The variables are unset after leaving the directory and any overwritten values are restored.
|
||||
scriptvars: environment variables that should be set to the return value of a script. After they have been set, they behave in the same way as variables set in the env section.
|
||||
scripts: scripts to run when entering the directory or leaving it."#
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("autoenv")
|
||||
}
|
||||
async fn run(
|
||||
&self,
|
||||
_args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(crate::commands::help::get_help(&Autoenv, ®istry))
|
||||
.into_value(Tag::unknown()),
|
||||
)))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Example .nu-env file",
|
||||
example: r#"cat .nu-env
|
||||
[env]
|
||||
mykey = "myvalue"
|
||||
|
||||
[scriptvars]
|
||||
myscript = "echo myval"
|
||||
|
||||
[scripts]
|
||||
entryscripts = ["touch hello.txt", "touch hello2.txt"]
|
||||
exitscripts = ["touch bye.txt"]"#,
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
use super::autoenv::read_trusted;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::SyntaxShape;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{fs, path::PathBuf};
|
||||
pub struct AutoenvTrust;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for AutoenvTrust {
|
||||
fn name(&self) -> &str {
|
||||
"autoenv trust"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("autoenv trust").optional("dir", SyntaxShape::String, "Directory to allow")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Trust a .nu-env file in the current or given directory"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let file_to_trust = match args.call_info.evaluate(registry).await?.args.nth(0) {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
||||
tag: _,
|
||||
}) => {
|
||||
let mut dir = fs::canonicalize(path)?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
_ => {
|
||||
let mut dir = fs::canonicalize(std::env::current_dir()?)?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
};
|
||||
|
||||
let content = std::fs::read(&file_to_trust)?;
|
||||
|
||||
let filename = file_to_trust.to_string_lossy().to_string();
|
||||
let mut allowed = read_trusted()?;
|
||||
allowed
|
||||
.files
|
||||
.insert(filename, Sha256::digest(&content).as_slice().to_vec());
|
||||
|
||||
let config_path = config::default_path_for(&Some(PathBuf::from("nu-env.toml")))?;
|
||||
let tomlstr = toml::to_string(&allowed).map_err(|_| {
|
||||
ShellError::untagged_runtime_error("Couldn't serialize allowed dirs to nu-env.toml")
|
||||
})?;
|
||||
fs::write(config_path, tomlstr).expect("Couldn't write to toml file");
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(".nu-env trusted!").into_value(tag),
|
||||
)))
|
||||
}
|
||||
fn is_binary(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Allow .nu-env file in current directory",
|
||||
example: "autoenv trust",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Allow .nu-env file in directory foo",
|
||||
example: "autoenv trust foo",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
use super::autoenv::Trusted;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::SyntaxShape;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
use std::io::Read;
|
||||
use std::{fs, path::PathBuf};
|
||||
pub struct AutoenvUnTrust;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for AutoenvUnTrust {
|
||||
fn name(&self) -> &str {
|
||||
"autoenv untrust"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("autoenv untrust").optional(
|
||||
"dir",
|
||||
SyntaxShape::String,
|
||||
"Directory to disallow",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Untrust a .nu-env file in the current or given directory"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let file_to_untrust = match args.call_info.evaluate(registry).await?.args.nth(0) {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
||||
tag: _,
|
||||
}) => {
|
||||
let mut dir = fs::canonicalize(path)?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
_ => {
|
||||
let mut dir = std::env::current_dir()?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
};
|
||||
|
||||
let config_path = config::default_path_for(&Some(PathBuf::from("nu-env.toml")))?;
|
||||
|
||||
let mut file = match std::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.create(true)
|
||||
.write(true)
|
||||
.open(config_path.clone())
|
||||
{
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return Err(ShellError::untagged_runtime_error(
|
||||
"Couldn't open nu-env.toml",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let mut doc = String::new();
|
||||
file.read_to_string(&mut doc)?;
|
||||
|
||||
let mut allowed: Trusted = toml::from_str(doc.as_str()).unwrap_or_else(|_| Trusted::new());
|
||||
|
||||
let file_to_untrust = file_to_untrust.to_string_lossy().to_string();
|
||||
|
||||
if allowed.files.remove(&file_to_untrust).is_none() {
|
||||
return
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"No .nu-env file to untrust in the given directory. Is it missing, or already untrusted?",
|
||||
));
|
||||
}
|
||||
|
||||
let tomlstr = toml::to_string(&allowed).map_err(|_| {
|
||||
ShellError::untagged_runtime_error("Couldn't serialize allowed dirs to nu-env.toml")
|
||||
})?;
|
||||
fs::write(config_path, tomlstr).expect("Couldn't write to toml file");
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(".nu-env untrusted!").into_value(tag),
|
||||
)))
|
||||
}
|
||||
fn is_binary(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Disallow .nu-env file in current directory",
|
||||
example: "autoenv untrust",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Disallow .nu-env file in directory foo",
|
||||
example: "autoenv untrust foo",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
@ -1,336 +0,0 @@
|
||||
use crate::commands::autoview::options::{ConfigExtensions, NuConfig as AutoViewConfiguration};
|
||||
use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand};
|
||||
use crate::prelude::*;
|
||||
use crate::primitive::get_color_config;
|
||||
use nu_data::value::format_leaf;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::{self, Expression, ExternalRedirection, Literal, SpannedExpression};
|
||||
use nu_protocol::{Primitive, Scope, Signature, UntaggedValue, Value};
|
||||
use nu_table::TextStyle;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
pub struct Command;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Command {
|
||||
fn name(&self) -> &str {
|
||||
"autoview"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("autoview")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"View the contents of the pipeline as a table or list."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
autoview(RunnableContext {
|
||||
input: args.input,
|
||||
registry: registry.clone(),
|
||||
shell_manager: args.shell_manager,
|
||||
host: args.host,
|
||||
ctrl_c: args.ctrl_c,
|
||||
current_errors: args.current_errors,
|
||||
name: args.call_info.name_tag,
|
||||
raw_input: args.raw_input,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Automatically view the results",
|
||||
example: "ls | autoview",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Autoview is also implied. The above can be written as",
|
||||
example: "ls",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunnableContextWithoutInput {
|
||||
pub shell_manager: ShellManager,
|
||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
||||
pub ctrl_c: Arc<AtomicBool>,
|
||||
pub registry: CommandRegistry,
|
||||
pub name: Tag,
|
||||
}
|
||||
|
||||
impl RunnableContextWithoutInput {
|
||||
pub fn convert(context: RunnableContext) -> (InputStream, RunnableContextWithoutInput) {
|
||||
let new_context = RunnableContextWithoutInput {
|
||||
shell_manager: context.shell_manager,
|
||||
host: context.host,
|
||||
ctrl_c: context.ctrl_c,
|
||||
current_errors: context.current_errors,
|
||||
registry: context.registry,
|
||||
name: context.name,
|
||||
};
|
||||
(context.input, new_context)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let configuration = AutoViewConfiguration::new();
|
||||
|
||||
let binary = context.get_command("binaryview");
|
||||
let text = context.get_command("textview");
|
||||
let table = context.get_command("table");
|
||||
|
||||
let pivot_mode = configuration.pivot_mode();
|
||||
|
||||
let (mut input_stream, context) = RunnableContextWithoutInput::convert(context);
|
||||
let term_width = context.host.lock().width();
|
||||
let color_hm = get_color_config();
|
||||
|
||||
if let Some(x) = input_stream.next().await {
|
||||
match input_stream.next().await {
|
||||
Some(y) => {
|
||||
let ctrl_c = context.ctrl_c.clone();
|
||||
let xy = vec![x, y];
|
||||
let xy_stream = futures::stream::iter(xy)
|
||||
.chain(input_stream)
|
||||
.interruptible(ctrl_c);
|
||||
|
||||
let stream = InputStream::from_stream(xy_stream);
|
||||
|
||||
if let Some(table) = table {
|
||||
let command_args = create_default_command_args(&context).with_input(stream);
|
||||
let result = table.run(command_args, &context.registry).await?;
|
||||
result.collect::<Vec<_>>().await;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
match x {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(ref s)),
|
||||
tag: Tag { anchor, span },
|
||||
} if anchor.is_some() => {
|
||||
if let Some(text) = text {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(
|
||||
UntaggedValue::string(s).into_value(Tag { anchor, span }),
|
||||
);
|
||||
let command_args =
|
||||
create_default_command_args(&context).with_input(stream);
|
||||
let result = text.run(command_args, &context.registry).await?;
|
||||
result.collect::<Vec<_>>().await;
|
||||
} else {
|
||||
out!("{}", s);
|
||||
}
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||
..
|
||||
} => {
|
||||
out!("{}", s);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Line(ref s)),
|
||||
tag: Tag { anchor, span },
|
||||
} if anchor.is_some() => {
|
||||
if let Some(text) = text {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(
|
||||
UntaggedValue::string(s).into_value(Tag { anchor, span }),
|
||||
);
|
||||
let command_args =
|
||||
create_default_command_args(&context).with_input(stream);
|
||||
let result = text.run(command_args, &context.registry).await?;
|
||||
result.collect::<Vec<_>>().await;
|
||||
} else {
|
||||
out!("{}\n", s);
|
||||
}
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Line(s)),
|
||||
..
|
||||
} => {
|
||||
out!("{}\n", s);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Path(s)),
|
||||
..
|
||||
} => {
|
||||
out!("{}", s.display());
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Int(n)),
|
||||
..
|
||||
} => {
|
||||
out!("{}", n);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Decimal(n)),
|
||||
..
|
||||
} => {
|
||||
// TODO: normalize decimal to remove trailing zeros.
|
||||
// normalization will be available in next release of bigdecimal crate
|
||||
let mut output = n.to_string();
|
||||
if output.contains('.') {
|
||||
output = output.trim_end_matches('0').to_owned();
|
||||
}
|
||||
if output.ends_with('.') {
|
||||
output.push('0');
|
||||
}
|
||||
out!("{}", output);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Boolean(b)),
|
||||
..
|
||||
} => {
|
||||
out!("{}", b);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Duration(_)),
|
||||
..
|
||||
} => {
|
||||
let output = format_leaf(&x).plain_string(100_000);
|
||||
out!("{}", output);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Date(d)),
|
||||
..
|
||||
} => {
|
||||
out!("{}", d);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Range(_)),
|
||||
..
|
||||
} => {
|
||||
let output = format_leaf(&x).plain_string(100_000);
|
||||
out!("{}", output);
|
||||
}
|
||||
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Binary(ref b)),
|
||||
..
|
||||
} => {
|
||||
if let Some(binary) = binary {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(x);
|
||||
let command_args =
|
||||
create_default_command_args(&context).with_input(stream);
|
||||
let result = binary.run(command_args, &context.registry).await?;
|
||||
result.collect::<Vec<_>>().await;
|
||||
} else {
|
||||
use pretty_hex::*;
|
||||
out!("{:?}", b.hex_dump());
|
||||
}
|
||||
}
|
||||
|
||||
Value {
|
||||
value: UntaggedValue::Error(e),
|
||||
..
|
||||
} => {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
Value {
|
||||
value: UntaggedValue::Row(row),
|
||||
..
|
||||
} if pivot_mode.is_always()
|
||||
|| (pivot_mode.is_auto()
|
||||
&& (row
|
||||
.entries
|
||||
.iter()
|
||||
.map(|(_, v)| v.convert_to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.iter()
|
||||
.fold(0usize, |acc, len| acc + len.len())
|
||||
+ row.entries.iter().count() * 2)
|
||||
> term_width) =>
|
||||
{
|
||||
let mut entries = vec![];
|
||||
for (key, value) in row.entries.iter() {
|
||||
entries.push(vec![
|
||||
nu_table::StyledString::new(
|
||||
key.to_string(),
|
||||
TextStyle::new()
|
||||
.alignment(nu_table::Alignment::Left)
|
||||
.fg(ansi_term::Color::Green)
|
||||
.bold(Some(true)),
|
||||
),
|
||||
nu_table::StyledString::new(
|
||||
format_leaf(value).plain_string(100_000),
|
||||
nu_table::TextStyle::basic_left(),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
let table =
|
||||
nu_table::Table::new(vec![], entries, nu_table::Theme::compact());
|
||||
|
||||
nu_table::draw_table(&table, term_width, &color_hm);
|
||||
}
|
||||
|
||||
Value {
|
||||
value: ref item, ..
|
||||
} => {
|
||||
if let Some(table) = table {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(x);
|
||||
let command_args =
|
||||
create_default_command_args(&context).with_input(stream);
|
||||
let result = table.run(command_args, &context.registry).await?;
|
||||
result.collect::<Vec<_>>().await;
|
||||
} else {
|
||||
out!("{:?}", item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
|
||||
fn create_default_command_args(context: &RunnableContextWithoutInput) -> RawCommandArgs {
|
||||
let span = context.name.span;
|
||||
RawCommandArgs {
|
||||
host: context.host.clone(),
|
||||
ctrl_c: context.ctrl_c.clone(),
|
||||
current_errors: context.current_errors.clone(),
|
||||
shell_manager: context.shell_manager.clone(),
|
||||
call_info: UnevaluatedCallInfo {
|
||||
args: hir::Call {
|
||||
head: Box::new(SpannedExpression::new(
|
||||
Expression::Literal(Literal::String(String::new())),
|
||||
span,
|
||||
)),
|
||||
positional: None,
|
||||
named: None,
|
||||
span,
|
||||
external_redirection: ExternalRedirection::Stdout,
|
||||
},
|
||||
name_tag: context.name.clone(),
|
||||
scope: Scope::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Command;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Command {})
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
pub mod command;
|
||||
mod options;
|
||||
|
||||
pub use command::Command as Autoview;
|
@ -1,60 +0,0 @@
|
||||
pub use nu_data::config::NuConfig;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum AutoPivotMode {
|
||||
Auto,
|
||||
Always,
|
||||
Never,
|
||||
}
|
||||
|
||||
impl AutoPivotMode {
|
||||
pub fn is_auto(&self) -> bool {
|
||||
match &self {
|
||||
AutoPivotMode::Auto => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_always(&self) -> bool {
|
||||
match &self {
|
||||
AutoPivotMode::Always => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn is_never(&self) -> bool {
|
||||
match &self {
|
||||
AutoPivotMode::Never => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ConfigExtensions: Debug + Send {
|
||||
fn pivot_mode(&self) -> AutoPivotMode;
|
||||
}
|
||||
|
||||
pub fn pivot_mode(config: &NuConfig) -> AutoPivotMode {
|
||||
let vars = &config.vars;
|
||||
|
||||
if let Some(mode) = vars.get("pivot_mode") {
|
||||
let mode = match mode.as_string() {
|
||||
Ok(m) if m.to_lowercase() == "auto" => AutoPivotMode::Auto,
|
||||
Ok(m) if m.to_lowercase() == "always" => AutoPivotMode::Always,
|
||||
Ok(m) if m.to_lowercase() == "never" => AutoPivotMode::Never,
|
||||
_ => AutoPivotMode::Never,
|
||||
};
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
AutoPivotMode::Never
|
||||
}
|
||||
|
||||
impl ConfigExtensions for NuConfig {
|
||||
fn pivot_mode(&self) -> AutoPivotMode {
|
||||
pivot_mode(self)
|
||||
}
|
||||
}
|
@ -1,202 +0,0 @@
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
#[cfg(feature = "rich-benchmark")]
|
||||
use heim::cpu::time;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
hir::{Block, ClassifiedCommand, Commands, InternalCommand},
|
||||
Dictionary, Scope, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub struct Benchmark;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct BenchmarkArgs {
|
||||
block: Block,
|
||||
passthrough: Option<Block>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Benchmark {
|
||||
fn name(&self) -> &str {
|
||||
"benchmark"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("benchmark")
|
||||
.required(
|
||||
"block",
|
||||
SyntaxShape::Block,
|
||||
"the block to run and benchmark",
|
||||
)
|
||||
.named(
|
||||
"passthrough",
|
||||
SyntaxShape::Block,
|
||||
"Display the benchmark results and pass through the block's output",
|
||||
Some('p'),
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Runs a block and returns the time it took to execute it"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
benchmark(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Benchmarks a command within a block",
|
||||
example: "benchmark { sleep 500ms }",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Benchmarks a command within a block and passes its output through",
|
||||
example: "echo 45 | benchmark { sleep 500ms } --passthrough {}",
|
||||
result: Some(vec![UntaggedValue::int(45).into()]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
async fn benchmark(
|
||||
raw_args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
|
||||
let tag = raw_args.call_info.args.span;
|
||||
let mut context = EvaluationContext::from_raw(&raw_args, ®istry);
|
||||
let scope = raw_args.call_info.scope.clone();
|
||||
let (BenchmarkArgs { block, passthrough }, input) = raw_args.process(®istry).await?;
|
||||
|
||||
let start_time = Instant::now();
|
||||
|
||||
#[cfg(feature = "rich-benchmark")]
|
||||
let start = time().await;
|
||||
|
||||
let result = run_block(
|
||||
&block,
|
||||
&mut context,
|
||||
input,
|
||||
&scope.it,
|
||||
&scope.vars,
|
||||
&scope.env,
|
||||
)
|
||||
.await;
|
||||
let output = result?.into_vec().await;
|
||||
|
||||
#[cfg(feature = "rich-benchmark")]
|
||||
let end = time().await;
|
||||
|
||||
let end_time = Instant::now();
|
||||
context.clear_errors();
|
||||
|
||||
// return basic runtime
|
||||
#[cfg(not(feature = "rich-benchmark"))]
|
||||
{
|
||||
let mut indexmap = IndexMap::with_capacity(1);
|
||||
|
||||
let real_time = into_big_int(end_time - start_time);
|
||||
indexmap.insert("real time".to_string(), real_time);
|
||||
benchmark_output(indexmap, output, passthrough, &tag, &mut context, &scope).await
|
||||
}
|
||||
// return advanced stats
|
||||
#[cfg(feature = "rich-benchmark")]
|
||||
if let (Ok(start), Ok(end)) = (start, end) {
|
||||
let mut indexmap = IndexMap::with_capacity(4);
|
||||
|
||||
let real_time = into_big_int(end_time - start_time);
|
||||
indexmap.insert("real time".to_string(), real_time);
|
||||
|
||||
let user_time = into_big_int(end.user() - start.user());
|
||||
indexmap.insert("user time".to_string(), user_time);
|
||||
|
||||
let system_time = into_big_int(end.system() - start.system());
|
||||
indexmap.insert("system time".to_string(), system_time);
|
||||
|
||||
let idle_time = into_big_int(end.idle() - start.idle());
|
||||
indexmap.insert("idle time".to_string(), idle_time);
|
||||
|
||||
benchmark_output(indexmap, output, passthrough, &tag, &mut context, &scope).await
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Could not retreive CPU time",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
async fn benchmark_output<T, Output>(
|
||||
indexmap: IndexMap<String, BigInt>,
|
||||
block_output: Output,
|
||||
passthrough: Option<Block>,
|
||||
tag: T,
|
||||
context: &mut EvaluationContext,
|
||||
scope: &Scope,
|
||||
) -> Result<OutputStream, ShellError>
|
||||
where
|
||||
T: Into<Tag> + Copy,
|
||||
Output: Into<OutputStream>,
|
||||
{
|
||||
let value = UntaggedValue::Row(Dictionary::from(
|
||||
indexmap
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, UntaggedValue::duration(v).into_value(tag)))
|
||||
.collect::<IndexMap<String, Value>>(),
|
||||
))
|
||||
.into_value(tag);
|
||||
|
||||
if let Some(time_block) = passthrough {
|
||||
let benchmark_output = InputStream::one(value);
|
||||
|
||||
// add autoview for an empty block
|
||||
let time_block = add_implicit_autoview(time_block);
|
||||
|
||||
let _ = run_block(
|
||||
&time_block,
|
||||
context,
|
||||
benchmark_output,
|
||||
&scope.it,
|
||||
&scope.vars,
|
||||
&scope.env,
|
||||
)
|
||||
.await?;
|
||||
context.clear_errors();
|
||||
|
||||
Ok(block_output.into())
|
||||
} else {
|
||||
let benchmark_output = OutputStream::one(value);
|
||||
Ok(benchmark_output)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_implicit_autoview(mut block: Block) -> Block {
|
||||
if block.block.is_empty() {
|
||||
block.push({
|
||||
let mut commands = Commands::new(block.span);
|
||||
commands.push(ClassifiedCommand::Internal(InternalCommand::new(
|
||||
"autoview".to_string(),
|
||||
block.span,
|
||||
block.span,
|
||||
)));
|
||||
commands
|
||||
});
|
||||
}
|
||||
block
|
||||
}
|
||||
|
||||
fn into_big_int<T: TryInto<Duration>>(time: T) -> BigInt {
|
||||
time.try_into()
|
||||
.unwrap_or_else(|_| Duration::new(0, 0))
|
||||
.as_nanos()
|
||||
.into()
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use nu_data::value::format_leaf;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct BuildStringArgs {
|
||||
rest: Vec<Value>,
|
||||
}
|
||||
|
||||
pub struct BuildString;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for BuildString {
|
||||
fn name(&self) -> &str {
|
||||
"build-string"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("build-string")
|
||||
.rest(SyntaxShape::Any, "all values to form into the string")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Builds a string from the arguments"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let (BuildStringArgs { rest }, _) = args.process(®istry).await?;
|
||||
|
||||
let mut output_string = String::new();
|
||||
|
||||
for r in rest {
|
||||
output_string.push_str(&format_leaf(&r).plain_string(100_000))
|
||||
}
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(output_string).into_value(tag),
|
||||
)))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Builds a string from a string and a number, without spaces between them",
|
||||
example: "build-string 'foo' 3",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CdArgs {
|
||||
pub(crate) path: Option<Tagged<PathBuf>>,
|
||||
}
|
||||
|
||||
pub struct Cd;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Cd {
|
||||
fn name(&self) -> &str {
|
||||
"cd"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("cd").optional(
|
||||
"directory",
|
||||
SyntaxShape::Path,
|
||||
"the directory to change to",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Change to a new path."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let shell_manager = args.shell_manager.clone();
|
||||
let (args, _): (CdArgs, _) = args.process(®istry).await?;
|
||||
shell_manager.cd(args, name)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Change to a new directory called 'dirname'",
|
||||
example: "cd dirname",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Change to your home directory",
|
||||
example: "cd",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Change to your home directory (alternate version)",
|
||||
example: "cd ~",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Change to the previous directory",
|
||||
example: "cd -",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Cd;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Cd {})
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct Char;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CharArgs {
|
||||
name: Tagged<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Char {
|
||||
fn name(&self) -> &str {
|
||||
"char"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("ansi").required(
|
||||
"character",
|
||||
SyntaxShape::Any,
|
||||
"the name of the character to output",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Output special characters (eg. 'newline')"
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Output newline",
|
||||
example: r#"char newline"#,
|
||||
result: Some(vec![Value::from("\n")]),
|
||||
},
|
||||
Example {
|
||||
description: "Output prompt character, newline and a hamburger character",
|
||||
example: r#"echo $(char prompt) $(char newline) $(char hamburger)"#,
|
||||
result: Some(vec![
|
||||
UntaggedValue::string("\u{25b6}").into(),
|
||||
UntaggedValue::string("\n").into(),
|
||||
UntaggedValue::string("\u{2261}").into(),
|
||||
]),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let (CharArgs { name }, _) = args.process(®istry).await?;
|
||||
|
||||
let special_character = str_to_character(&name.item);
|
||||
|
||||
if let Some(output) = special_character {
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(output).into_value(name.tag()),
|
||||
)))
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Unknown character",
|
||||
"unknown character",
|
||||
name.tag(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn str_to_character(s: &str) -> Option<String> {
|
||||
match s {
|
||||
"newline" | "enter" | "nl" => Some("\n".into()),
|
||||
"tab" => Some("\t".into()),
|
||||
"sp" | "space" => Some(" ".into()),
|
||||
// Unicode names came from https://www.compart.com/en/unicode
|
||||
// Private Use Area (U+E000-U+F8FF)
|
||||
"branch" => Some('\u{e0a0}'.to_string()), //
|
||||
"segment" => Some('\u{e0b0}'.to_string()), //
|
||||
|
||||
"identical_to" | "hamburger" => Some('\u{2261}'.to_string()), // ≡
|
||||
"not_identical_to" | "branch_untracked" => Some('\u{2262}'.to_string()), // ≢
|
||||
"strictly_equivalent_to" | "branch_identical" => Some('\u{2263}'.to_string()), // ≣
|
||||
|
||||
"upwards_arrow" | "branch_ahead" => Some('\u{2191}'.to_string()), // ↑
|
||||
"downwards_arrow" | "branch_behind" => Some('\u{2193}'.to_string()), // ↓
|
||||
"up_down_arrow" | "branch_ahead_behind" => Some('\u{2195}'.to_string()), // ↕
|
||||
|
||||
"black_right_pointing_triangle" | "prompt" => Some('\u{25b6}'.to_string()), // ▶
|
||||
"vector_or_cross_product" | "failed" => Some('\u{2a2f}'.to_string()), // ⨯
|
||||
"high_voltage_sign" | "elevated" => Some('\u{26a1}'.to_string()), // ⚡
|
||||
"tilde" | "twiddle" | "squiggly" | "home" => Some("~".into()), // ~
|
||||
"hash" | "hashtag" | "pound_sign" | "sharp" | "root" => Some("#".into()), // #
|
||||
|
||||
// Weather symbols
|
||||
"sun" => Some("\x1b[33;1m\u{2600}\x1b[0m".to_string()), // Yellow Bold ☀
|
||||
"moon" => Some("\x1b[36m\u{263d}\x1b[0m".to_string()), // Cyan ☽
|
||||
"clouds" => Some("\x1b[37;1m\u{2601}\x1b[0m".to_string()), // White Bold ☁
|
||||
"rain" => Some("\x1b[37;1m\u{2614}\x1b[0m".to_string()), // White Bold ☔
|
||||
"fog" => Some("\x1b[37;1m\u{2592}\x1b[0m".to_string()), // White Bold ▒
|
||||
"mist" => Some("\x1b[34m\u{2591}\x1b[0m".to_string()), // Blue ░
|
||||
"haze" => Some("\x1b[33m\u{2591}\x1b[0m".to_string()), // Yellow ░
|
||||
"snow" => Some("\x1b[37;1m\u{2744}\x1b[0m".to_string()), // White Bold ❄
|
||||
"thunderstorm" => Some("\x1b[33;1m\u{26a1}\x1b[0m".to_string()), // Yellow Bold ⚡
|
||||
|
||||
// Reference for ansi codes https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
||||
// Another good reference http://ascii-table.com/ansi-escape-sequences.php
|
||||
|
||||
// For setting title like `echo [$(char title) $(pwd) $(char bel)] | str collect`
|
||||
"title" => Some("\x1b]2;".to_string()), // ESC]2; xterm sets window title
|
||||
"bel" => Some('\x07'.to_string()), // Terminal Bell
|
||||
"backspace" => Some('\x08'.to_string()), // Backspace
|
||||
|
||||
// Ansi Erase Sequences
|
||||
"clear_screen" => Some("\x1b[J".to_string()), // clears the screen
|
||||
"clear_screen_from_cursor_to_end" => Some("\x1b[0J".to_string()), // clears from cursor until end of screen
|
||||
"clear_screen_from_cursor_to_beginning" => Some("\x1b[1J".to_string()), // clears from cursor to beginning of screen
|
||||
"cls" | "clear_entire_screen" => Some("\x1b[2J".to_string()), // clears the entire screen
|
||||
"erase_line" => Some("\x1b[K".to_string()), // clears the current line
|
||||
"erase_line_from_cursor_to_end" => Some("\x1b[0K".to_string()), // clears from cursor to end of line
|
||||
"erase_line_from_cursor_to_beginning" => Some("\x1b[1K".to_string()), // clears from cursor to start of line
|
||||
"erase_entire_line" => Some("\x1b[2K".to_string()), // clears entire line
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Char;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Char {})
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
use crate::commands::classified::expr::run_expression_block;
|
||||
use crate::commands::classified::internal::run_internal_command;
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use crate::prelude::*;
|
||||
use crate::stream::InputStream;
|
||||
use futures::stream::TryStreamExt;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::{Block, ClassifiedCommand, Commands};
|
||||
use nu_protocol::{ReturnSuccess, UntaggedValue, Value};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
pub(crate) async fn run_block(
|
||||
block: &Block,
|
||||
ctx: &mut EvaluationContext,
|
||||
mut input: InputStream,
|
||||
it: &Value,
|
||||
vars: &IndexMap<String, Value>,
|
||||
env: &IndexMap<String, String>,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty());
|
||||
for pipeline in &block.block {
|
||||
match output {
|
||||
Ok(inp) if inp.is_empty() => {}
|
||||
Ok(inp) => {
|
||||
let mut output_stream = inp.to_output_stream();
|
||||
|
||||
loop {
|
||||
match output_stream.try_next().await {
|
||||
Ok(Some(ReturnSuccess::Value(Value {
|
||||
value: UntaggedValue::Error(e),
|
||||
..
|
||||
}))) => return Err(e),
|
||||
Ok(Some(_item)) => {
|
||||
if let Some(err) = ctx.get_errors().get(0) {
|
||||
ctx.clear_errors();
|
||||
return Err(err.clone());
|
||||
}
|
||||
if ctx.ctrl_c.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
if let Some(err) = ctx.get_errors().get(0) {
|
||||
ctx.clear_errors();
|
||||
return Err(err.clone());
|
||||
}
|
||||
break;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
output = run_pipeline(pipeline, ctx, input, it, vars, env).await;
|
||||
|
||||
input = InputStream::empty();
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
async fn run_pipeline(
|
||||
commands: &Commands,
|
||||
ctx: &mut EvaluationContext,
|
||||
mut input: InputStream,
|
||||
it: &Value,
|
||||
vars: &IndexMap<String, Value>,
|
||||
env: &IndexMap<String, String>,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
for item in commands.list.clone() {
|
||||
input = match item {
|
||||
ClassifiedCommand::Dynamic(_) => {
|
||||
return Err(ShellError::unimplemented("Dynamic commands"))
|
||||
}
|
||||
|
||||
ClassifiedCommand::Expr(expr) => {
|
||||
run_expression_block(*expr, ctx, it, vars, env).await?
|
||||
}
|
||||
|
||||
ClassifiedCommand::Error(err) => return Err(err.into()),
|
||||
|
||||
ClassifiedCommand::Internal(left) => {
|
||||
run_internal_command(left, ctx, input, it, vars, env).await?
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(input)
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
use derive_new::new;
|
||||
use nu_protocol::hir;
|
||||
|
||||
#[derive(new, Debug)]
|
||||
pub(crate) struct Command {
|
||||
pub(crate) args: hir::Call,
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
use crate::evaluate::evaluate_baseline_expr;
|
||||
use crate::prelude::*;
|
||||
|
||||
use log::{log_enabled, trace};
|
||||
|
||||
use futures::stream::once;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::SpannedExpression;
|
||||
use nu_protocol::Value;
|
||||
|
||||
pub(crate) async fn run_expression_block(
|
||||
expr: SpannedExpression,
|
||||
context: &mut EvaluationContext,
|
||||
it: &Value,
|
||||
vars: &IndexMap<String, Value>,
|
||||
env: &IndexMap<String, String>,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
if log_enabled!(log::Level::Trace) {
|
||||
trace!(target: "nu::run::expr", "->");
|
||||
trace!(target: "nu::run::expr", "{:?}", expr);
|
||||
}
|
||||
|
||||
let registry = context.registry().clone();
|
||||
let output = evaluate_baseline_expr(&expr, ®istry, it, vars, env).await?;
|
||||
|
||||
Ok(once(async { Ok(output) }).to_input_stream())
|
||||
}
|
@ -1,698 +0,0 @@
|
||||
use crate::commands::classified::maybe_text_codec::{MaybeTextCodec, StringOrBinary};
|
||||
use crate::evaluate::evaluate_baseline_expr;
|
||||
use crate::futures::ThreadedReceiver;
|
||||
use crate::prelude::*;
|
||||
|
||||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc;
|
||||
|
||||
use futures::executor::block_on_stream;
|
||||
use futures_codec::FramedRead;
|
||||
use log::trace;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::{ExternalCommand, ExternalRedirection};
|
||||
use nu_protocol::{Primitive, Scope, ShellTypeName, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
|
||||
pub(crate) async fn run_external_command(
|
||||
command: ExternalCommand,
|
||||
context: &mut EvaluationContext,
|
||||
input: InputStream,
|
||||
scope: &Scope,
|
||||
external_redirection: ExternalRedirection,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
trace!(target: "nu::run::external", "-> {}", command.name);
|
||||
|
||||
if !did_find_command(&command.name) {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Command not found",
|
||||
"command not found",
|
||||
&command.name_tag,
|
||||
));
|
||||
}
|
||||
|
||||
run_with_stdin(command, context, input, scope, external_redirection).await
|
||||
}
|
||||
|
||||
async fn run_with_stdin(
|
||||
command: ExternalCommand,
|
||||
context: &mut EvaluationContext,
|
||||
input: InputStream,
|
||||
scope: &Scope,
|
||||
external_redirection: ExternalRedirection,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
let path = context.shell_manager.path();
|
||||
|
||||
let input = trace_stream!(target: "nu::trace_stream::external::stdin", "input" = input);
|
||||
|
||||
let mut command_args = vec![];
|
||||
for arg in command.args.iter() {
|
||||
let value =
|
||||
evaluate_baseline_expr(arg, &context.registry, &scope.it, &scope.vars, &scope.env)
|
||||
.await?;
|
||||
|
||||
// Skip any arguments that don't really exist, treating them as optional
|
||||
// FIXME: we may want to preserve the gap in the future, though it's hard to say
|
||||
// what value we would put in its place.
|
||||
if value.value.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do the cleanup that we need to do on any argument going out:
|
||||
match &value.value {
|
||||
UntaggedValue::Table(table) => {
|
||||
for t in table {
|
||||
match &t.value {
|
||||
UntaggedValue::Primitive(_) => {
|
||||
command_args
|
||||
.push(t.convert_to_string().trim_end_matches('\n').to_string());
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Could not convert to positional arguments",
|
||||
"could not convert to positional arguments",
|
||||
value.tag(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let trimmed_value_string = value.as_string()?.trim_end_matches('\n').to_string();
|
||||
command_args.push(trimmed_value_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let process_args = command_args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
let home_dir;
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
{
|
||||
home_dir = dirs::home_dir;
|
||||
}
|
||||
#[cfg(not(feature = "dirs"))]
|
||||
{
|
||||
home_dir = || Some(std::path::PathBuf::from("/"));
|
||||
}
|
||||
|
||||
let arg = expand_tilde(arg.deref(), home_dir);
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
if argument_contains_whitespace(&arg) && !argument_is_quoted(&arg) {
|
||||
add_quotes(&arg)
|
||||
} else {
|
||||
arg.as_ref().to_string()
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if let Some(unquoted) = remove_quotes(&arg) {
|
||||
unquoted.to_string()
|
||||
} else {
|
||||
arg.as_ref().to_string()
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
spawn(
|
||||
&command,
|
||||
&path,
|
||||
&process_args[..],
|
||||
input,
|
||||
external_redirection,
|
||||
scope,
|
||||
)
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
command: &ExternalCommand,
|
||||
path: &str,
|
||||
args: &[String],
|
||||
input: InputStream,
|
||||
external_redirection: ExternalRedirection,
|
||||
scope: &Scope,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
let command = command.clone();
|
||||
|
||||
let mut process = {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let mut process = Command::new("cmd");
|
||||
process.arg("/c");
|
||||
process.arg(&command.name);
|
||||
for arg in args {
|
||||
// Clean the args before we use them:
|
||||
let arg = arg.replace("|", "\\|");
|
||||
process.arg(&arg);
|
||||
}
|
||||
process
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let cmd_with_args = vec![command.name.clone(), args.join(" ")].join(" ");
|
||||
let mut process = Command::new("sh");
|
||||
process.arg("-c").arg(cmd_with_args);
|
||||
process
|
||||
}
|
||||
};
|
||||
|
||||
process.current_dir(path);
|
||||
trace!(target: "nu::run::external", "cwd = {:?}", &path);
|
||||
|
||||
process.env_clear();
|
||||
process.envs(scope.env.iter());
|
||||
|
||||
// We want stdout regardless of what
|
||||
// we are doing ($it case or pipe stdin)
|
||||
match external_redirection {
|
||||
ExternalRedirection::Stdout => {
|
||||
process.stdout(Stdio::piped());
|
||||
trace!(target: "nu::run::external", "set up stdout pipe");
|
||||
}
|
||||
ExternalRedirection::Stderr => {
|
||||
process.stderr(Stdio::piped());
|
||||
trace!(target: "nu::run::external", "set up stderr pipe");
|
||||
}
|
||||
ExternalRedirection::StdoutAndStderr => {
|
||||
process.stdout(Stdio::piped());
|
||||
trace!(target: "nu::run::external", "set up stdout pipe");
|
||||
process.stderr(Stdio::piped());
|
||||
trace!(target: "nu::run::external", "set up stderr pipe");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// open since we have some contents for stdin
|
||||
if !input.is_empty() {
|
||||
process.stdin(Stdio::piped());
|
||||
trace!(target: "nu::run::external", "set up stdin pipe");
|
||||
}
|
||||
|
||||
trace!(target: "nu::run::external", "built command {:?}", process);
|
||||
|
||||
// TODO Switch to async_std::process once it's stabilized
|
||||
if let Ok(mut child) = process.spawn() {
|
||||
let (tx, rx) = mpsc::sync_channel(0);
|
||||
|
||||
let mut stdin = child.stdin.take();
|
||||
|
||||
let stdin_write_tx = tx.clone();
|
||||
let stdout_read_tx = tx;
|
||||
let stdin_name_tag = command.name_tag.clone();
|
||||
let stdout_name_tag = command.name_tag;
|
||||
|
||||
std::thread::spawn(move || {
|
||||
if !input.is_empty() {
|
||||
let mut stdin_write = stdin
|
||||
.take()
|
||||
.expect("Internal error: could not get stdin pipe for external command");
|
||||
|
||||
for value in block_on_stream(input) {
|
||||
match &value.value {
|
||||
UntaggedValue::Primitive(Primitive::Nothing) => continue,
|
||||
UntaggedValue::Primitive(Primitive::String(s))
|
||||
| UntaggedValue::Primitive(Primitive::Line(s)) => {
|
||||
if let Err(e) = stdin_write.write(s.as_bytes()) {
|
||||
let message = format!("Unable to write to stdin (error = {})", e);
|
||||
|
||||
let _ = stdin_write_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(ShellError::labeled_error(
|
||||
message,
|
||||
"application may have closed before completing pipeline",
|
||||
&stdin_name_tag,
|
||||
)),
|
||||
tag: stdin_name_tag,
|
||||
}));
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
UntaggedValue::Primitive(Primitive::Binary(b)) => {
|
||||
if let Err(e) = stdin_write.write(b) {
|
||||
let message = format!("Unable to write to stdin (error = {})", e);
|
||||
|
||||
let _ = stdin_write_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(ShellError::labeled_error(
|
||||
message,
|
||||
"application may have closed before completing pipeline",
|
||||
&stdin_name_tag,
|
||||
)),
|
||||
tag: stdin_name_tag,
|
||||
}));
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
unsupported => {
|
||||
let _ = stdin_write_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(ShellError::labeled_error(
|
||||
format!(
|
||||
"Received unexpected type from pipeline ({})",
|
||||
unsupported.type_name()
|
||||
),
|
||||
"expected a string",
|
||||
stdin_name_tag.clone(),
|
||||
)),
|
||||
tag: stdin_name_tag,
|
||||
}));
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
std::thread::spawn(move || {
|
||||
if external_redirection == ExternalRedirection::Stdout
|
||||
|| external_redirection == ExternalRedirection::StdoutAndStderr
|
||||
{
|
||||
let stdout = if let Some(stdout) = child.stdout.take() {
|
||||
stdout
|
||||
} else {
|
||||
let _ = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(ShellError::labeled_error(
|
||||
"Can't redirect the stdout for external command",
|
||||
"can't redirect stdout",
|
||||
&stdout_name_tag,
|
||||
)),
|
||||
tag: stdout_name_tag,
|
||||
}));
|
||||
return Err(());
|
||||
};
|
||||
|
||||
let file = futures::io::AllowStdIo::new(stdout);
|
||||
let stream = FramedRead::new(file, MaybeTextCodec::default());
|
||||
|
||||
for line in block_on_stream(stream) {
|
||||
match line {
|
||||
Ok(line) => match line {
|
||||
StringOrBinary::String(s) => {
|
||||
let result = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(s.clone())),
|
||||
tag: stdout_name_tag.clone(),
|
||||
}));
|
||||
|
||||
if result.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
StringOrBinary::Binary(b) => {
|
||||
let result = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Binary(
|
||||
b.into_iter().collect(),
|
||||
)),
|
||||
tag: stdout_name_tag.clone(),
|
||||
}));
|
||||
|
||||
if result.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
// If there's an exit status, it makes sense that we may error when
|
||||
// trying to read from its stdout pipe (likely been closed). In that
|
||||
// case, don't emit an error.
|
||||
let should_error = match child.wait() {
|
||||
Ok(exit_status) => !exit_status.success(),
|
||||
Err(_) => true,
|
||||
};
|
||||
|
||||
if should_error {
|
||||
let _ = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(ShellError::labeled_error(
|
||||
format!("Unable to read from stdout ({})", e),
|
||||
"unable to read from stdout",
|
||||
&stdout_name_tag,
|
||||
)),
|
||||
tag: stdout_name_tag.clone(),
|
||||
}));
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if external_redirection == ExternalRedirection::Stderr
|
||||
|| external_redirection == ExternalRedirection::StdoutAndStderr
|
||||
{
|
||||
let stderr = if let Some(stderr) = child.stderr.take() {
|
||||
stderr
|
||||
} else {
|
||||
let _ = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(ShellError::labeled_error(
|
||||
"Can't redirect the stderr for external command",
|
||||
"can't redirect stderr",
|
||||
&stdout_name_tag,
|
||||
)),
|
||||
tag: stdout_name_tag,
|
||||
}));
|
||||
return Err(());
|
||||
};
|
||||
|
||||
let file = futures::io::AllowStdIo::new(stderr);
|
||||
let stream = FramedRead::new(file, MaybeTextCodec::default());
|
||||
|
||||
for line in block_on_stream(stream) {
|
||||
match line {
|
||||
Ok(line) => match line {
|
||||
StringOrBinary::String(s) => {
|
||||
let result = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(
|
||||
ShellError::untagged_runtime_error(s),
|
||||
),
|
||||
tag: stdout_name_tag.clone(),
|
||||
}));
|
||||
|
||||
if result.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
StringOrBinary::Binary(_) => {
|
||||
let result = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(
|
||||
ShellError::untagged_runtime_error("<binary stderr>"),
|
||||
),
|
||||
tag: stdout_name_tag.clone(),
|
||||
}));
|
||||
|
||||
if result.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
// If there's an exit status, it makes sense that we may error when
|
||||
// trying to read from its stdout pipe (likely been closed). In that
|
||||
// case, don't emit an error.
|
||||
let should_error = match child.wait() {
|
||||
Ok(exit_status) => !exit_status.success(),
|
||||
Err(_) => true,
|
||||
};
|
||||
|
||||
if should_error {
|
||||
let _ = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(ShellError::labeled_error(
|
||||
format!("Unable to read from stdout ({})", e),
|
||||
"unable to read from stdout",
|
||||
&stdout_name_tag,
|
||||
)),
|
||||
tag: stdout_name_tag.clone(),
|
||||
}));
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can give an error when we see a non-zero exit code, but this is different
|
||||
// than what other shells will do.
|
||||
let external_failed = match child.wait() {
|
||||
Err(_) => true,
|
||||
Ok(exit_status) => !exit_status.success(),
|
||||
};
|
||||
|
||||
if external_failed {
|
||||
let cfg = nu_data::config::config(Tag::unknown());
|
||||
if let Ok(cfg) = cfg {
|
||||
if cfg.contains_key("nonzero_exit_errors") {
|
||||
let _ = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(ShellError::labeled_error(
|
||||
"External command failed",
|
||||
"command failed",
|
||||
&stdout_name_tag,
|
||||
)),
|
||||
tag: stdout_name_tag.clone(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
let _ = stdout_read_tx.send(Ok(Value {
|
||||
value: UntaggedValue::Error(ShellError::external_non_zero()),
|
||||
tag: stdout_name_tag,
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let stream = ThreadedReceiver::new(rx);
|
||||
Ok(stream.to_input_stream())
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Failed to spawn process",
|
||||
"failed to spawn",
|
||||
&command.name_tag,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn did_find_command(#[allow(unused)] name: &str) -> bool {
|
||||
#[cfg(not(feature = "which"))]
|
||||
{
|
||||
// we can't perform this check, so just assume it can be found
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "which", unix))]
|
||||
{
|
||||
which::which(name).is_ok()
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "which", windows))]
|
||||
{
|
||||
if which::which(name).is_ok() {
|
||||
true
|
||||
} else {
|
||||
// Reference: https://ss64.com/nt/syntax-internal.html
|
||||
let cmd_builtins = [
|
||||
"assoc", "break", "color", "copy", "date", "del", "dir", "dpath", "echo", "erase",
|
||||
"for", "ftype", "md", "mkdir", "mklink", "move", "path", "ren", "rename", "rd",
|
||||
"rmdir", "set", "start", "time", "title", "type", "ver", "verify", "vol",
|
||||
];
|
||||
|
||||
cmd_builtins.contains(&name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_tilde<SI: ?Sized, P, HD>(input: &SI, home_dir: HD) -> std::borrow::Cow<str>
|
||||
where
|
||||
SI: AsRef<str>,
|
||||
P: AsRef<std::path::Path>,
|
||||
HD: FnOnce() -> Option<P>,
|
||||
{
|
||||
shellexpand::tilde_with_context(input, home_dir)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn argument_contains_whitespace(argument: &str) -> bool {
|
||||
argument.chars().any(|c| c.is_whitespace())
|
||||
}
|
||||
|
||||
fn argument_is_quoted(argument: &str) -> bool {
|
||||
if argument.len() < 2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
(argument.starts_with('"') && argument.ends_with('"'))
|
||||
|| (argument.starts_with('\'') && argument.ends_with('\''))
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn add_quotes(argument: &str) -> String {
|
||||
format!("\"{}\"", argument)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn remove_quotes(argument: &str) -> Option<&str> {
|
||||
if !argument_is_quoted(argument) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let size = argument.len();
|
||||
|
||||
Some(&argument[1..size - 1])
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn shell_os_paths() -> Vec<std::path::PathBuf> {
|
||||
let mut original_paths = vec![];
|
||||
|
||||
if let Some(paths) = std::env::var_os("PATH") {
|
||||
original_paths = std::env::split_paths(&paths).collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
original_paths
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
add_quotes, argument_contains_whitespace, argument_is_quoted, expand_tilde, remove_quotes,
|
||||
};
|
||||
#[cfg(feature = "which")]
|
||||
use super::{run_external_command, EvaluationContext, InputStream};
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
use futures::executor::block_on;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_errors::ShellError;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_protocol::Scope;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_test_support::commands::ExternalBuilder;
|
||||
|
||||
// async fn read(mut stream: OutputStream) -> Option<Value> {
|
||||
// match stream.try_next().await {
|
||||
// Ok(val) => {
|
||||
// if let Some(val) = val {
|
||||
// val.raw_value()
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
// Err(_) => None,
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
async fn non_existent_run() -> Result<(), ShellError> {
|
||||
use nu_protocol::hir::ExternalRedirection;
|
||||
let cmd = ExternalBuilder::for_name("i_dont_exist.exe").build();
|
||||
|
||||
let input = InputStream::empty();
|
||||
let mut ctx =
|
||||
EvaluationContext::basic().expect("There was a problem creating a basic context.");
|
||||
|
||||
assert!(run_external_command(
|
||||
cmd,
|
||||
&mut ctx,
|
||||
input,
|
||||
&Scope::new(),
|
||||
ExternalRedirection::Stdout
|
||||
)
|
||||
.await
|
||||
.is_err());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// async fn failure_run() -> Result<(), ShellError> {
|
||||
// let cmd = ExternalBuilder::for_name("fail").build();
|
||||
|
||||
// let mut ctx = EvaluationContext::basic().expect("There was a problem creating a basic context.");
|
||||
// let stream = run_external_command(cmd, &mut ctx, None, false)
|
||||
// .await?
|
||||
// .expect("There was a problem running the external command.");
|
||||
|
||||
// match read(stream.into()).await {
|
||||
// Some(Value {
|
||||
// value: UntaggedValue::Error(_),
|
||||
// ..
|
||||
// }) => {}
|
||||
// None | _ => panic!("Command didn't fail."),
|
||||
// }
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn identifies_command_failed() -> Result<(), ShellError> {
|
||||
// block_on(failure_run())
|
||||
// }
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
#[test]
|
||||
fn identifies_command_not_found() -> Result<(), ShellError> {
|
||||
block_on(non_existent_run())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checks_contains_whitespace_from_argument_to_be_passed_in() {
|
||||
assert_eq!(argument_contains_whitespace("andrés"), false);
|
||||
assert_eq!(argument_contains_whitespace("and rés"), true);
|
||||
assert_eq!(argument_contains_whitespace(r#"and\ rés"#), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checks_quotes_from_argument_to_be_passed_in() {
|
||||
assert_eq!(argument_is_quoted(""), false);
|
||||
|
||||
assert_eq!(argument_is_quoted("'"), false);
|
||||
assert_eq!(argument_is_quoted("'a"), false);
|
||||
assert_eq!(argument_is_quoted("a"), false);
|
||||
assert_eq!(argument_is_quoted("a'"), false);
|
||||
assert_eq!(argument_is_quoted("''"), true);
|
||||
|
||||
assert_eq!(argument_is_quoted(r#"""#), false);
|
||||
assert_eq!(argument_is_quoted(r#""a"#), false);
|
||||
assert_eq!(argument_is_quoted(r#"a"#), false);
|
||||
assert_eq!(argument_is_quoted(r#"a""#), false);
|
||||
assert_eq!(argument_is_quoted(r#""""#), true);
|
||||
|
||||
assert_eq!(argument_is_quoted("'andrés"), false);
|
||||
assert_eq!(argument_is_quoted("andrés'"), false);
|
||||
assert_eq!(argument_is_quoted(r#""andrés"#), false);
|
||||
assert_eq!(argument_is_quoted(r#"andrés""#), false);
|
||||
assert_eq!(argument_is_quoted("'andrés'"), true);
|
||||
assert_eq!(argument_is_quoted(r#""andrés""#), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adds_quotes_to_argument_to_be_passed_in() {
|
||||
assert_eq!(add_quotes("andrés"), "\"andrés\"");
|
||||
//assert_eq!(add_quotes("\"andrés\""), "\"andrés\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strips_quotes_from_argument_to_be_passed_in() {
|
||||
assert_eq!(remove_quotes(""), None);
|
||||
|
||||
assert_eq!(remove_quotes("'"), None);
|
||||
assert_eq!(remove_quotes("'a"), None);
|
||||
assert_eq!(remove_quotes("a"), None);
|
||||
assert_eq!(remove_quotes("a'"), None);
|
||||
assert_eq!(remove_quotes("''"), Some(""));
|
||||
|
||||
assert_eq!(remove_quotes(r#"""#), None);
|
||||
assert_eq!(remove_quotes(r#""a"#), None);
|
||||
assert_eq!(remove_quotes(r#"a"#), None);
|
||||
assert_eq!(remove_quotes(r#"a""#), None);
|
||||
assert_eq!(remove_quotes(r#""""#), Some(""));
|
||||
|
||||
assert_eq!(remove_quotes("'andrés"), None);
|
||||
assert_eq!(remove_quotes("andrés'"), None);
|
||||
assert_eq!(remove_quotes(r#""andrés"#), None);
|
||||
assert_eq!(remove_quotes(r#"andrés""#), None);
|
||||
assert_eq!(remove_quotes("'andrés'"), Some("andrés"));
|
||||
assert_eq!(remove_quotes(r#""andrés""#), Some("andrés"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expands_tilde_if_starts_with_tilde_character() {
|
||||
assert_eq!(
|
||||
expand_tilde("~", || Some(std::path::Path::new("the_path_to_nu_light"))),
|
||||
"the_path_to_nu_light"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn does_not_expand_tilde_if_tilde_is_not_first_character() {
|
||||
assert_eq!(
|
||||
expand_tilde("1~1", || Some(std::path::Path::new("the_path_to_nu_light"))),
|
||||
"1~1"
|
||||
);
|
||||
}
|
||||
}
|
@ -1,276 +0,0 @@
|
||||
use crate::commands::command::whole_stream_command;
|
||||
use crate::commands::run_alias::AliasCommand;
|
||||
use crate::commands::UnevaluatedCallInfo;
|
||||
use crate::prelude::*;
|
||||
use log::{log_enabled, trace};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::{ExternalRedirection, InternalCommand};
|
||||
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, Scope, UntaggedValue, Value};
|
||||
|
||||
pub(crate) async fn run_internal_command(
|
||||
command: InternalCommand,
|
||||
context: &mut EvaluationContext,
|
||||
input: InputStream,
|
||||
it: &Value,
|
||||
vars: &IndexMap<String, Value>,
|
||||
env: &IndexMap<String, String>,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
if log_enabled!(log::Level::Trace) {
|
||||
trace!(target: "nu::run::internal", "->");
|
||||
trace!(target: "nu::run::internal", "{}", command.name);
|
||||
}
|
||||
|
||||
let scope = Scope {
|
||||
it: it.clone(),
|
||||
vars: vars.clone(),
|
||||
env: env.clone(),
|
||||
};
|
||||
let objects: InputStream = trace_stream!(target: "nu::trace_stream::internal", "input" = input);
|
||||
let internal_command = context.expect_command(&command.name);
|
||||
|
||||
if command.name == "autoenv untrust" {
|
||||
context.user_recently_used_autoenv_untrust = true;
|
||||
}
|
||||
|
||||
let result = {
|
||||
context
|
||||
.run_command(
|
||||
internal_command?,
|
||||
Tag::unknown_anchor(command.name_span),
|
||||
command.args.clone(),
|
||||
&scope,
|
||||
objects,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
let head = Arc::new(command.args.head.clone());
|
||||
//let context = Arc::new(context.clone());
|
||||
let context = context.clone();
|
||||
let command = Arc::new(command);
|
||||
let scope = Arc::new(scope);
|
||||
// let scope = scope.clone();
|
||||
|
||||
Ok(InputStream::from_stream(
|
||||
result
|
||||
.then(move |item| {
|
||||
let head = head.clone();
|
||||
let command = command.clone();
|
||||
let mut context = context.clone();
|
||||
let scope = scope.clone();
|
||||
async move {
|
||||
match item {
|
||||
Ok(ReturnSuccess::Action(action)) => match action {
|
||||
CommandAction::ChangePath(path) => {
|
||||
context.shell_manager.set_path(path);
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
CommandAction::Exit => std::process::exit(0), // TODO: save history.txt
|
||||
CommandAction::Error(err) => {
|
||||
context.error(err.clone());
|
||||
InputStream::one(UntaggedValue::Error(err).into_untagged_value())
|
||||
}
|
||||
CommandAction::AutoConvert(tagged_contents, extension) => {
|
||||
let contents_tag = tagged_contents.tag.clone();
|
||||
let command_name = format!("from {}", extension);
|
||||
let command = command.clone();
|
||||
if let Some(converter) = context.registry.get_command(&command_name)
|
||||
{
|
||||
let new_args = RawCommandArgs {
|
||||
host: context.host.clone(),
|
||||
ctrl_c: context.ctrl_c.clone(),
|
||||
current_errors: context.current_errors.clone(),
|
||||
shell_manager: context.shell_manager.clone(),
|
||||
call_info: UnevaluatedCallInfo {
|
||||
args: nu_protocol::hir::Call {
|
||||
head: (&*head).clone(),
|
||||
positional: None,
|
||||
named: None,
|
||||
span: Span::unknown(),
|
||||
external_redirection: ExternalRedirection::Stdout,
|
||||
},
|
||||
name_tag: Tag::unknown_anchor(command.name_span),
|
||||
scope: (&*scope).clone(),
|
||||
},
|
||||
};
|
||||
let result = converter
|
||||
.run(
|
||||
new_args.with_input(vec![tagged_contents]),
|
||||
&context.registry,
|
||||
)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(mut result) => {
|
||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
|
||||
result.drain_vec().await;
|
||||
|
||||
let mut output = vec![];
|
||||
for res in result_vec {
|
||||
match res {
|
||||
Ok(ReturnSuccess::Value(Value {
|
||||
value: UntaggedValue::Table(list),
|
||||
..
|
||||
})) => {
|
||||
for l in list {
|
||||
output.push(Ok(l));
|
||||
}
|
||||
}
|
||||
Ok(ReturnSuccess::Value(Value {
|
||||
value,
|
||||
..
|
||||
})) => {
|
||||
output
|
||||
.push(Ok(value
|
||||
.into_value(contents_tag.clone())));
|
||||
}
|
||||
Err(e) => output.push(Err(e)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
futures::stream::iter(output).to_input_stream()
|
||||
}
|
||||
Err(e) => {
|
||||
context.add_error(e);
|
||||
InputStream::empty()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
InputStream::one(tagged_contents)
|
||||
}
|
||||
}
|
||||
CommandAction::EnterHelpShell(value) => match value {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(cmd)),
|
||||
tag,
|
||||
} => {
|
||||
context.shell_manager.insert_at_current(Box::new(
|
||||
match HelpShell::for_command(
|
||||
UntaggedValue::string(cmd).into_value(tag),
|
||||
&context.registry(),
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
return InputStream::one(
|
||||
UntaggedValue::Error(err).into_untagged_value(),
|
||||
)
|
||||
}
|
||||
},
|
||||
));
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
_ => {
|
||||
context.shell_manager.insert_at_current(Box::new(
|
||||
match HelpShell::index(&context.registry()) {
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
return InputStream::one(
|
||||
UntaggedValue::Error(err).into_untagged_value(),
|
||||
)
|
||||
}
|
||||
},
|
||||
));
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
},
|
||||
CommandAction::EnterValueShell(value) => {
|
||||
context
|
||||
.shell_manager
|
||||
.insert_at_current(Box::new(ValueShell::new(value)));
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
CommandAction::EnterShell(location) => {
|
||||
context.shell_manager.insert_at_current(Box::new(
|
||||
match FilesystemShell::with_location(location) {
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
return InputStream::one(
|
||||
UntaggedValue::Error(err.into())
|
||||
.into_untagged_value(),
|
||||
)
|
||||
}
|
||||
},
|
||||
));
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
CommandAction::AddAlias(name, args, block) => {
|
||||
context.add_commands(vec![whole_stream_command(
|
||||
AliasCommand::new(name, args, block),
|
||||
)]);
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
CommandAction::AddPlugins(path) => {
|
||||
match crate::plugin::scan(vec![std::path::PathBuf::from(path)]) {
|
||||
Ok(plugins) => {
|
||||
context.add_commands(
|
||||
plugins
|
||||
.into_iter()
|
||||
.filter(|p| {
|
||||
!context.is_command_registered(p.name())
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
Err(reason) => {
|
||||
context.error(reason.clone());
|
||||
InputStream::one(
|
||||
UntaggedValue::Error(reason).into_untagged_value(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandAction::PreviousShell => {
|
||||
context.shell_manager.prev();
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
CommandAction::NextShell => {
|
||||
context.shell_manager.next();
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
CommandAction::LeaveShell => {
|
||||
context.shell_manager.remove_at_current();
|
||||
if context.shell_manager.is_empty() {
|
||||
std::process::exit(0); // TODO: save history.txt
|
||||
}
|
||||
InputStream::from_stream(futures::stream::iter(vec![]))
|
||||
}
|
||||
},
|
||||
|
||||
Ok(ReturnSuccess::Value(Value {
|
||||
value: UntaggedValue::Error(err),
|
||||
tag,
|
||||
})) => {
|
||||
context.error(err.clone());
|
||||
InputStream::one(UntaggedValue::Error(err).into_value(tag))
|
||||
}
|
||||
|
||||
Ok(ReturnSuccess::Value(v)) => InputStream::one(v),
|
||||
|
||||
Ok(ReturnSuccess::DebugValue(v)) => {
|
||||
let doc = PrettyDebug::pretty_doc(&v);
|
||||
let mut buffer = termcolor::Buffer::ansi();
|
||||
|
||||
let _ = doc.render_raw(
|
||||
context.with_host(|host| host.width() - 5),
|
||||
&mut nu_source::TermColored::new(&mut buffer),
|
||||
);
|
||||
|
||||
let value = String::from_utf8_lossy(buffer.as_slice());
|
||||
|
||||
InputStream::one(UntaggedValue::string(value).into_untagged_value())
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
context.error(err.clone());
|
||||
InputStream::one(UntaggedValue::Error(err).into_untagged_value())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.take_while(|x| futures::future::ready(!x.is_error())),
|
||||
))
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
|
||||
extern crate encoding_rs;
|
||||
use encoding_rs::{CoderResult, Decoder, Encoding, UTF_8};
|
||||
|
||||
#[cfg(not(test))]
|
||||
const OUTPUT_BUFFER_SIZE: usize = 8192;
|
||||
#[cfg(test)]
|
||||
const OUTPUT_BUFFER_SIZE: usize = 4;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum StringOrBinary {
|
||||
String(String),
|
||||
Binary(Vec<u8>),
|
||||
}
|
||||
|
||||
pub struct MaybeTextCodec {
|
||||
decoder: Decoder,
|
||||
}
|
||||
|
||||
impl MaybeTextCodec {
|
||||
// The constructor takes an Option<&'static Encoding>, because an absence of an encoding indicates that we want BOM sniffing enabled
|
||||
pub fn new(encoding: Option<&'static Encoding>) -> Self {
|
||||
let decoder = match encoding {
|
||||
Some(e) => e.new_decoder_with_bom_removal(),
|
||||
None => UTF_8.new_decoder(),
|
||||
};
|
||||
MaybeTextCodec { decoder }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MaybeTextCodec {
|
||||
fn default() -> Self {
|
||||
MaybeTextCodec {
|
||||
decoder: UTF_8.new_decoder(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl futures_codec::Encoder for MaybeTextCodec {
|
||||
type Item = StringOrBinary;
|
||||
type Error = std::io::Error;
|
||||
|
||||
fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||
match item {
|
||||
StringOrBinary::String(s) => {
|
||||
dst.reserve(s.len());
|
||||
dst.put(s.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
StringOrBinary::Binary(b) => {
|
||||
dst.reserve(b.len());
|
||||
dst.put(Bytes::from(b));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl futures_codec::Decoder for MaybeTextCodec {
|
||||
type Item = StringOrBinary;
|
||||
type Error = ShellError;
|
||||
|
||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
if src.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut s = String::with_capacity(OUTPUT_BUFFER_SIZE);
|
||||
|
||||
let (res, _read, replacements) = self.decoder.decode_to_string(src, &mut s, false);
|
||||
|
||||
let result = if replacements {
|
||||
// If we had to make replacements when converting to utf8, fall back to binary
|
||||
StringOrBinary::Binary(src.to_vec())
|
||||
} else {
|
||||
// If original buffer size is too small, we continue to allocate new Strings and append
|
||||
// them to the result until the input buffer is smaller than the allocated String
|
||||
if let CoderResult::OutputFull = res {
|
||||
let mut buffer = String::with_capacity(OUTPUT_BUFFER_SIZE);
|
||||
loop {
|
||||
let (res, _read, _replacements) =
|
||||
self.decoder
|
||||
.decode_to_string(&src[s.len()..], &mut buffer, false);
|
||||
s.push_str(&buffer);
|
||||
|
||||
if let CoderResult::InputEmpty = res {
|
||||
break;
|
||||
}
|
||||
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
StringOrBinary::String(s)
|
||||
};
|
||||
|
||||
src.clear();
|
||||
|
||||
Ok(Some(result))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{MaybeTextCodec, StringOrBinary};
|
||||
use bytes::BytesMut;
|
||||
use futures_codec::Decoder;
|
||||
|
||||
// TODO: Write some more tests
|
||||
|
||||
#[test]
|
||||
fn should_consume_all_bytes_from_source_when_temporary_buffer_overflows() {
|
||||
let mut maybe_text = MaybeTextCodec::new(None);
|
||||
let mut bytes = BytesMut::from("0123456789");
|
||||
|
||||
let text = maybe_text.decode(&mut bytes);
|
||||
|
||||
assert_eq!(
|
||||
Ok(Some(StringOrBinary::String("0123456789".to_string()))),
|
||||
text
|
||||
);
|
||||
assert!(bytes.is_empty());
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
pub(crate) mod block;
|
||||
mod dynamic;
|
||||
pub(crate) mod expr;
|
||||
pub(crate) mod external;
|
||||
pub(crate) mod internal;
|
||||
pub(crate) mod maybe_text_codec;
|
||||
pub(crate) mod plugin;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use dynamic::Command as DynamicCommand;
|
@ -1,467 +0,0 @@
|
||||
use crate::commands::command::{whole_stream_command, WholeStreamCommand};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use log::trace;
|
||||
use nu_errors::ShellError;
|
||||
use nu_plugin::jsonrpc::JsonRpc;
|
||||
use nu_protocol::{Primitive, ReturnValue, Signature, UntaggedValue, Value};
|
||||
use serde::{self, Deserialize, Serialize};
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(tag = "method")]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum NuResult {
|
||||
response {
|
||||
params: Result<VecDeque<ReturnValue>, ShellError>,
|
||||
},
|
||||
}
|
||||
|
||||
enum PluginCommand {
|
||||
Filter(PluginFilter),
|
||||
Sink(PluginSink),
|
||||
}
|
||||
|
||||
impl PluginCommand {
|
||||
fn command(self) -> Result<crate::commands::Command, ShellError> {
|
||||
match self {
|
||||
PluginCommand::Filter(cmd) => Ok(whole_stream_command(cmd)),
|
||||
PluginCommand::Sink(cmd) => Ok(whole_stream_command(cmd)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum PluginMode {
|
||||
Filter,
|
||||
Sink,
|
||||
}
|
||||
|
||||
pub struct PluginCommandBuilder {
|
||||
mode: PluginMode,
|
||||
name: String,
|
||||
path: String,
|
||||
config: Signature,
|
||||
}
|
||||
|
||||
impl PluginCommandBuilder {
|
||||
pub fn new(
|
||||
name: impl Into<String>,
|
||||
path: impl Into<String>,
|
||||
config: impl Into<Signature>,
|
||||
) -> Self {
|
||||
let config = config.into();
|
||||
|
||||
PluginCommandBuilder {
|
||||
mode: if config.is_filter {
|
||||
PluginMode::Filter
|
||||
} else {
|
||||
PluginMode::Sink
|
||||
},
|
||||
name: name.into(),
|
||||
path: path.into(),
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&self) -> Result<crate::commands::Command, ShellError> {
|
||||
let mode = &self.mode;
|
||||
|
||||
let name = self.name.clone();
|
||||
let path = self.path.clone();
|
||||
let config = self.config.clone();
|
||||
|
||||
let cmd = match mode {
|
||||
PluginMode::Filter => PluginCommand::Filter(PluginFilter { name, path, config }),
|
||||
PluginMode::Sink => PluginCommand::Sink(PluginSink { name, path, config }),
|
||||
};
|
||||
|
||||
cmd.command()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(new)]
|
||||
pub struct PluginFilter {
|
||||
name: String,
|
||||
path: String,
|
||||
config: Signature,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for PluginFilter {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
self.config.clone()
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
&self.config.usage
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
run_filter(self.path.clone(), args, registry).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_filter(
|
||||
path: String,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
trace!("filter_plugin :: {}", path);
|
||||
let registry = registry.clone();
|
||||
|
||||
let scope = args.call_info.scope.clone();
|
||||
|
||||
let bos = futures::stream::iter(vec![
|
||||
UntaggedValue::Primitive(Primitive::BeginningOfStream).into_untagged_value()
|
||||
]);
|
||||
let eos = futures::stream::iter(vec![
|
||||
UntaggedValue::Primitive(Primitive::EndOfStream).into_untagged_value()
|
||||
]);
|
||||
|
||||
let args = args.evaluate_once_with_scope(®istry, &scope).await?;
|
||||
|
||||
let real_path = Path::new(&path);
|
||||
let ext = real_path.extension();
|
||||
let ps1_file = match ext {
|
||||
Some(ext) => ext == "ps1",
|
||||
None => false,
|
||||
};
|
||||
|
||||
let mut child: Child = if ps1_file {
|
||||
Command::new("pwsh")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.args(&[
|
||||
"-NoLogo",
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
&real_path.to_string_lossy(),
|
||||
])
|
||||
.spawn()
|
||||
.expect("Failed to spawn PowerShell process")
|
||||
} else {
|
||||
Command::new(path)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to spawn child process")
|
||||
};
|
||||
|
||||
let call_info = args.call_info.clone();
|
||||
|
||||
trace!("filtering :: {:?}", call_info);
|
||||
|
||||
Ok(bos
|
||||
.chain(args.input)
|
||||
.chain(eos)
|
||||
.map(move |item| {
|
||||
match item {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::BeginningOfStream),
|
||||
..
|
||||
} => {
|
||||
// Beginning of the stream
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
||||
let mut reader = BufReader::new(stdout);
|
||||
|
||||
let request = JsonRpc::new("begin_filter", call_info.clone());
|
||||
let request_raw = serde_json::to_string(&request);
|
||||
trace!("begin_filter:request {:?}", &request_raw);
|
||||
|
||||
match request_raw {
|
||||
Err(_) => {
|
||||
return OutputStream::one(Err(ShellError::labeled_error(
|
||||
"Could not load json from plugin",
|
||||
"could not load json from plugin",
|
||||
&call_info.name_tag,
|
||||
)));
|
||||
}
|
||||
Ok(request_raw) => {
|
||||
match stdin.write(format!("{}\n", request_raw).as_bytes()) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
return OutputStream::one(Err(ShellError::unexpected(
|
||||
format!("{}", err),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut input = String::new();
|
||||
match reader.read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
let response = serde_json::from_str::<NuResult>(&input);
|
||||
trace!("begin_filter:response {:?}", &response);
|
||||
|
||||
match response {
|
||||
Ok(NuResult::response { params }) => match params {
|
||||
Ok(params) => futures::stream::iter(params).to_output_stream(),
|
||||
Err(e) => futures::stream::iter(vec![ReturnValue::Err(e)])
|
||||
.to_output_stream(),
|
||||
},
|
||||
|
||||
Err(e) => OutputStream::one(Err(
|
||||
ShellError::untagged_runtime_error(format!(
|
||||
"Error while processing begin_filter response: {:?} {}",
|
||||
e, input
|
||||
)),
|
||||
)),
|
||||
}
|
||||
}
|
||||
Err(e) => OutputStream::one(Err(ShellError::untagged_runtime_error(
|
||||
format!("Error while reading begin_filter response: {:?}", e),
|
||||
))),
|
||||
}
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::EndOfStream),
|
||||
..
|
||||
} => {
|
||||
// post stream contents
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
||||
let mut reader = BufReader::new(stdout);
|
||||
|
||||
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("end_filter", vec![]);
|
||||
let request_raw = serde_json::to_string(&request);
|
||||
trace!("end_filter:request {:?}", &request_raw);
|
||||
|
||||
match request_raw {
|
||||
Err(_) => {
|
||||
return OutputStream::one(Err(ShellError::labeled_error(
|
||||
"Could not load json from plugin",
|
||||
"could not load json from plugin",
|
||||
&call_info.name_tag,
|
||||
)));
|
||||
}
|
||||
Ok(request_raw) => {
|
||||
match stdin.write(format!("{}\n", request_raw).as_bytes()) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
return OutputStream::one(Err(ShellError::unexpected(
|
||||
format!("{}", err),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut input = String::new();
|
||||
let stream = match reader.read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
let response = serde_json::from_str::<NuResult>(&input);
|
||||
trace!("end_filter:response {:?}", &response);
|
||||
|
||||
match response {
|
||||
Ok(NuResult::response { params }) => match params {
|
||||
Ok(params) => futures::stream::iter(params).to_output_stream(),
|
||||
Err(e) => futures::stream::iter(vec![ReturnValue::Err(e)])
|
||||
.to_output_stream(),
|
||||
},
|
||||
Err(e) => futures::stream::iter(vec![Err(
|
||||
ShellError::untagged_runtime_error(format!(
|
||||
"Error while processing end_filter response: {:?} {}",
|
||||
e, input
|
||||
)),
|
||||
)])
|
||||
.to_output_stream(),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
futures::stream::iter(vec![Err(ShellError::untagged_runtime_error(
|
||||
format!("Error while reading end_filter response: {:?}", e),
|
||||
))])
|
||||
.to_output_stream()
|
||||
}
|
||||
};
|
||||
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
|
||||
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("quit", vec![]);
|
||||
let request_raw = serde_json::to_string(&request);
|
||||
trace!("quit:request {:?}", &request_raw);
|
||||
|
||||
match request_raw {
|
||||
Ok(request_raw) => {
|
||||
let _ = stdin.write(format!("{}\n", request_raw).as_bytes());
|
||||
// TODO: Handle error
|
||||
}
|
||||
Err(e) => {
|
||||
return OutputStream::one(Err(ShellError::untagged_runtime_error(
|
||||
format!("Error while processing quit response: {:?}", e),
|
||||
)));
|
||||
}
|
||||
}
|
||||
let _ = child.wait();
|
||||
|
||||
stream
|
||||
}
|
||||
|
||||
v => {
|
||||
// Stream contents
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
||||
let mut reader = BufReader::new(stdout);
|
||||
|
||||
let request = JsonRpc::new("filter", v);
|
||||
let request_raw = serde_json::to_string(&request);
|
||||
trace!("filter:request {:?}", &request_raw);
|
||||
|
||||
match request_raw {
|
||||
Ok(request_raw) => {
|
||||
let _ = stdin.write(format!("{}\n", request_raw).as_bytes());
|
||||
// TODO: Handle error
|
||||
}
|
||||
Err(e) => {
|
||||
return OutputStream::one(Err(ShellError::untagged_runtime_error(
|
||||
format!("Error while processing filter response: {:?}", e),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
let mut input = String::new();
|
||||
match reader.read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
let response = serde_json::from_str::<NuResult>(&input);
|
||||
trace!("filter:response {:?}", &response);
|
||||
|
||||
match response {
|
||||
Ok(NuResult::response { params }) => match params {
|
||||
Ok(params) => futures::stream::iter(params).to_output_stream(),
|
||||
Err(e) => futures::stream::iter(vec![ReturnValue::Err(e)])
|
||||
.to_output_stream(),
|
||||
},
|
||||
Err(e) => OutputStream::one(Err(
|
||||
ShellError::untagged_runtime_error(format!(
|
||||
"Error while processing filter response: {:?}\n== input ==\n{}",
|
||||
e, input
|
||||
)),
|
||||
)),
|
||||
}
|
||||
}
|
||||
Err(e) => OutputStream::one(Err(ShellError::untagged_runtime_error(
|
||||
format!("Error while reading filter response: {:?}", e),
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
#[derive(new)]
|
||||
pub struct PluginSink {
|
||||
name: String,
|
||||
path: String,
|
||||
config: Signature,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for PluginSink {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
self.config.clone()
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
&self.config.usage
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
run_sink(self.path.clone(), args, registry).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_sink(
|
||||
path: String,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let args = args.evaluate_once(®istry).await?;
|
||||
let call_info = args.call_info.clone();
|
||||
|
||||
let input: Vec<Value> = args.input.collect().await;
|
||||
|
||||
let request = JsonRpc::new("sink", (call_info.clone(), input));
|
||||
let request_raw = serde_json::to_string(&request);
|
||||
if let Ok(request_raw) = request_raw {
|
||||
if let Ok(mut tmpfile) = tempfile::NamedTempFile::new() {
|
||||
let _ = writeln!(tmpfile, "{}", request_raw);
|
||||
let _ = tmpfile.flush();
|
||||
|
||||
let real_path = Path::new(&path);
|
||||
let ext = real_path.extension();
|
||||
let ps1_file = match ext {
|
||||
Some(ext) => ext == "ps1",
|
||||
None => false,
|
||||
};
|
||||
|
||||
// TODO: This sink may not work in powershell, trying to find
|
||||
// an example of what CallInfo would look like in this temp file
|
||||
let child = if ps1_file {
|
||||
Command::new("pwsh")
|
||||
.args(&[
|
||||
"-NoLogo",
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
&real_path.to_string_lossy(),
|
||||
&tmpfile
|
||||
.path()
|
||||
.to_str()
|
||||
.expect("Failed getting tmpfile path"),
|
||||
])
|
||||
.spawn()
|
||||
} else {
|
||||
Command::new(path).arg(&tmpfile.path()).spawn()
|
||||
};
|
||||
|
||||
if let Ok(mut child) = child {
|
||||
let _ = child.wait();
|
||||
|
||||
Ok(OutputStream::empty())
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Could not create process for sink command",
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Could not open file to send sink command message",
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Could not create message to sink command",
|
||||
))
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::Signature;
|
||||
use std::process::Command;
|
||||
|
||||
pub struct Clear;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Clear {
|
||||
fn name(&self) -> &str {
|
||||
"clear"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("clear")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Clears the terminal"
|
||||
}
|
||||
|
||||
async fn run(&self, _: CommandArgs, _: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
if cfg!(windows) {
|
||||
Command::new("cmd")
|
||||
.args(&["/C", "cls"])
|
||||
.status()
|
||||
.expect("failed to execute process");
|
||||
} else if cfg!(unix) {
|
||||
Command::new("/bin/sh")
|
||||
.args(&["-c", "clear"])
|
||||
.status()
|
||||
.expect("failed to execute process");
|
||||
}
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Clear the screen",
|
||||
example: "clear",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Clear;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Clear {})
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use futures::stream::StreamExt;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, Value};
|
||||
|
||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||
|
||||
pub struct Clip;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Clip {
|
||||
fn name(&self) -> &str {
|
||||
"clip"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("clip")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Copy the contents of the pipeline to the copy/paste buffer"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
clip(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Save text to the clipboard",
|
||||
example: "echo 'secret value' | clip",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clip(
|
||||
args: CommandArgs,
|
||||
_registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let input = args.input;
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let values: Vec<Value> = input.collect().await;
|
||||
|
||||
if let Ok(clip_context) = ClipboardProvider::new() {
|
||||
let mut clip_context: ClipboardContext = clip_context;
|
||||
let mut new_copy_data = String::new();
|
||||
|
||||
if !values.is_empty() {
|
||||
let mut first = true;
|
||||
for i in values.iter() {
|
||||
if !first {
|
||||
new_copy_data.push_str("\n");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
let string: String = match i.as_string() {
|
||||
Ok(string) => string.to_string(),
|
||||
Err(_) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Given non-string data",
|
||||
"expected strings from pipeline",
|
||||
name,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
new_copy_data.push_str(&string);
|
||||
}
|
||||
}
|
||||
|
||||
match clip_context.set_contents(new_copy_data) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Could not set contents of clipboard",
|
||||
"could not set contents of clipboard",
|
||||
name,
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Could not open clipboard",
|
||||
"could not open clipboard",
|
||||
name,
|
||||
));
|
||||
}
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Clip;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Clip {})
|
||||
}
|
||||
}
|
@ -1,449 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::help::get_help;
|
||||
use crate::deserializer::ConfigDeserializer;
|
||||
use crate::evaluate::evaluate_args::evaluate_args;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir;
|
||||
use nu_protocol::{CallInfo, EvaluatedArgs, ReturnSuccess, Scope, Signature, UntaggedValue, Value};
|
||||
use parking_lot::Mutex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct UnevaluatedCallInfo {
|
||||
pub args: hir::Call,
|
||||
pub name_tag: Tag,
|
||||
pub scope: Scope,
|
||||
}
|
||||
|
||||
impl UnevaluatedCallInfo {
|
||||
pub async fn evaluate(self, registry: &CommandRegistry) -> Result<CallInfo, ShellError> {
|
||||
let args = evaluate_args(&self.args, registry, &self.scope).await?;
|
||||
|
||||
Ok(CallInfo {
|
||||
args,
|
||||
name_tag: self.name_tag,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn evaluate_with_new_it(
|
||||
self,
|
||||
registry: &CommandRegistry,
|
||||
it: &Value,
|
||||
) -> Result<CallInfo, ShellError> {
|
||||
let mut scope = self.scope.clone();
|
||||
scope.it = it.clone();
|
||||
let args = evaluate_args(&self.args, registry, &scope).await?;
|
||||
|
||||
Ok(CallInfo {
|
||||
args,
|
||||
name_tag: self.name_tag,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn switch_present(&self, switch: &str) -> bool {
|
||||
self.args.switch_preset(switch)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Getters)]
|
||||
#[get = "pub(crate)"]
|
||||
pub struct CommandArgs {
|
||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
||||
pub ctrl_c: Arc<AtomicBool>,
|
||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub call_info: UnevaluatedCallInfo,
|
||||
pub input: InputStream,
|
||||
pub raw_input: String,
|
||||
}
|
||||
|
||||
#[derive(Getters, Clone)]
|
||||
#[get = "pub(crate)"]
|
||||
pub struct RawCommandArgs {
|
||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
||||
pub ctrl_c: Arc<AtomicBool>,
|
||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub call_info: UnevaluatedCallInfo,
|
||||
}
|
||||
|
||||
impl RawCommandArgs {
|
||||
pub fn with_input(self, input: impl Into<InputStream>) -> CommandArgs {
|
||||
CommandArgs {
|
||||
host: self.host,
|
||||
ctrl_c: self.ctrl_c,
|
||||
current_errors: self.current_errors,
|
||||
shell_manager: self.shell_manager,
|
||||
call_info: self.call_info,
|
||||
input: input.into(),
|
||||
raw_input: String::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for CommandArgs {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.call_info.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandArgs {
|
||||
pub async fn evaluate_once(
|
||||
self,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
|
||||
let host = self.host.clone();
|
||||
let ctrl_c = self.ctrl_c.clone();
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
let input = self.input;
|
||||
let call_info = self.call_info.evaluate(registry).await?;
|
||||
|
||||
Ok(EvaluatedWholeStreamCommandArgs::new(
|
||||
host,
|
||||
ctrl_c,
|
||||
shell_manager,
|
||||
call_info,
|
||||
input,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn evaluate_once_with_scope(
|
||||
self,
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
|
||||
let host = self.host.clone();
|
||||
let ctrl_c = self.ctrl_c.clone();
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
let input = self.input;
|
||||
let call_info = UnevaluatedCallInfo {
|
||||
name_tag: self.call_info.name_tag,
|
||||
args: self.call_info.args,
|
||||
scope: scope.clone(),
|
||||
};
|
||||
let call_info = call_info.evaluate(registry).await?;
|
||||
|
||||
Ok(EvaluatedWholeStreamCommandArgs::new(
|
||||
host,
|
||||
ctrl_c,
|
||||
shell_manager,
|
||||
call_info,
|
||||
input,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn process<'de, T: Deserialize<'de>>(
|
||||
self,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<(T, InputStream), ShellError> {
|
||||
let args = self.evaluate_once(registry).await?;
|
||||
let call_info = args.call_info.clone();
|
||||
|
||||
let mut deserializer = ConfigDeserializer::from_call_info(call_info);
|
||||
|
||||
Ok((T::deserialize(&mut deserializer)?, args.input))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunnableContext {
|
||||
pub input: InputStream,
|
||||
pub shell_manager: ShellManager,
|
||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
||||
pub ctrl_c: Arc<AtomicBool>,
|
||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
||||
pub registry: CommandRegistry,
|
||||
pub name: Tag,
|
||||
pub raw_input: String,
|
||||
}
|
||||
|
||||
impl RunnableContext {
|
||||
pub fn get_command(&self, name: &str) -> Option<Command> {
|
||||
self.registry.get_command(name)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EvaluatedWholeStreamCommandArgs {
|
||||
pub args: EvaluatedCommandArgs,
|
||||
pub input: InputStream,
|
||||
}
|
||||
|
||||
impl Deref for EvaluatedWholeStreamCommandArgs {
|
||||
type Target = EvaluatedCommandArgs;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.args
|
||||
}
|
||||
}
|
||||
|
||||
impl EvaluatedWholeStreamCommandArgs {
|
||||
pub fn new(
|
||||
host: Arc<parking_lot::Mutex<dyn Host>>,
|
||||
ctrl_c: Arc<AtomicBool>,
|
||||
shell_manager: ShellManager,
|
||||
call_info: CallInfo,
|
||||
input: impl Into<InputStream>,
|
||||
) -> EvaluatedWholeStreamCommandArgs {
|
||||
EvaluatedWholeStreamCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
ctrl_c,
|
||||
shell_manager,
|
||||
call_info,
|
||||
},
|
||||
input: input.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_tag(&self) -> Tag {
|
||||
self.args.call_info.name_tag.clone()
|
||||
}
|
||||
|
||||
pub fn parts(self) -> (InputStream, EvaluatedArgs) {
|
||||
let EvaluatedWholeStreamCommandArgs { args, input } = self;
|
||||
|
||||
(input, args.call_info.args)
|
||||
}
|
||||
|
||||
pub fn split(self) -> (InputStream, EvaluatedCommandArgs) {
|
||||
let EvaluatedWholeStreamCommandArgs { args, input } = self;
|
||||
|
||||
(input, args)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Getters)]
|
||||
#[get = "pub"]
|
||||
pub struct EvaluatedFilterCommandArgs {
|
||||
args: EvaluatedCommandArgs,
|
||||
}
|
||||
|
||||
impl Deref for EvaluatedFilterCommandArgs {
|
||||
type Target = EvaluatedCommandArgs;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.args
|
||||
}
|
||||
}
|
||||
|
||||
impl EvaluatedFilterCommandArgs {
|
||||
pub fn new(
|
||||
host: Arc<parking_lot::Mutex<dyn Host>>,
|
||||
ctrl_c: Arc<AtomicBool>,
|
||||
shell_manager: ShellManager,
|
||||
call_info: CallInfo,
|
||||
) -> EvaluatedFilterCommandArgs {
|
||||
EvaluatedFilterCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
ctrl_c,
|
||||
shell_manager,
|
||||
call_info,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Getters, new)]
|
||||
#[get = "pub(crate)"]
|
||||
pub struct EvaluatedCommandArgs {
|
||||
pub host: Arc<parking_lot::Mutex<dyn Host>>,
|
||||
pub ctrl_c: Arc<AtomicBool>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub call_info: CallInfo,
|
||||
}
|
||||
|
||||
impl EvaluatedCommandArgs {
|
||||
pub fn nth(&self, pos: usize) -> Option<&Value> {
|
||||
self.call_info.args.nth(pos)
|
||||
}
|
||||
|
||||
/// Get the nth positional argument, error if not possible
|
||||
pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> {
|
||||
self.call_info
|
||||
.args
|
||||
.nth(pos)
|
||||
.ok_or_else(|| ShellError::unimplemented("Better error: expect_nth"))
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> Option<&Value> {
|
||||
self.call_info.args.get(name)
|
||||
}
|
||||
|
||||
pub fn has(&self, name: &str) -> bool {
|
||||
self.call_info.args.has(name)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Example {
|
||||
pub example: &'static str,
|
||||
pub description: &'static str,
|
||||
pub result: Option<Vec<Value>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait WholeStreamCommand: Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::new(self.name()).desc(self.usage()).filter()
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str;
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError>;
|
||||
|
||||
fn is_binary(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
// Commands that are not meant to be run by users
|
||||
fn is_internal(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Command(Arc<dyn WholeStreamCommand>);
|
||||
|
||||
impl PrettyDebugWithSource for Command {
|
||||
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
||||
b::typed(
|
||||
"whole stream command",
|
||||
b::description(self.name())
|
||||
+ b::space()
|
||||
+ b::equals()
|
||||
+ b::space()
|
||||
+ self.signature().pretty_debug(source),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Command {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Command({})", self.name())
|
||||
}
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn name(&self) -> &str {
|
||||
self.0.name()
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> Signature {
|
||||
self.0.signature()
|
||||
}
|
||||
|
||||
pub fn usage(&self) -> &str {
|
||||
self.0.usage()
|
||||
}
|
||||
|
||||
pub fn examples(&self) -> Vec<Example> {
|
||||
self.0.examples()
|
||||
}
|
||||
|
||||
pub async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
if args.call_info.switch_present("help") {
|
||||
let cl = self.0.clone();
|
||||
let registry = registry.clone();
|
||||
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
|
||||
UntaggedValue::string(get_help(&*cl, ®istry)).into_value(Tag::unknown()),
|
||||
))))
|
||||
} else {
|
||||
self.0.run(args, registry).await
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_binary(&self) -> bool {
|
||||
self.0.is_binary()
|
||||
}
|
||||
|
||||
pub fn is_internal(&self) -> bool {
|
||||
self.0.is_internal()
|
||||
}
|
||||
|
||||
pub fn stream_command(&self) -> &dyn WholeStreamCommand {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FnFilterCommand {
|
||||
name: String,
|
||||
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FnFilterCommand {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"usage"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
CommandArgs {
|
||||
host,
|
||||
ctrl_c,
|
||||
shell_manager,
|
||||
call_info,
|
||||
input,
|
||||
..
|
||||
}: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = Arc::new(registry.clone());
|
||||
let func = self.func;
|
||||
|
||||
Ok(input
|
||||
.then(move |it| {
|
||||
let host = host.clone();
|
||||
let registry = registry.clone();
|
||||
let ctrl_c = ctrl_c.clone();
|
||||
let shell_manager = shell_manager.clone();
|
||||
let call_info = call_info.clone();
|
||||
async move {
|
||||
let call_info = match call_info.evaluate_with_new_it(&*registry, &it).await {
|
||||
Err(err) => {
|
||||
return OutputStream::one(Err(err));
|
||||
}
|
||||
Ok(args) => args,
|
||||
};
|
||||
|
||||
let args = EvaluatedFilterCommandArgs::new(
|
||||
host.clone(),
|
||||
ctrl_c.clone(),
|
||||
shell_manager.clone(),
|
||||
call_info,
|
||||
);
|
||||
|
||||
match func(args) {
|
||||
Err(err) => return OutputStream::one(Err(err)),
|
||||
Ok(stream) => stream,
|
||||
}
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.to_output_stream())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Command {
|
||||
Command(Arc::new(command))
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use futures::future;
|
||||
use futures::stream::StreamExt;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct Compact;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CompactArgs {
|
||||
rest: Vec<Tagged<String>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Compact {
|
||||
fn name(&self) -> &str {
|
||||
"compact"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("compact").rest(SyntaxShape::Any, "the columns to compact from the table")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Creates a table with non-empty rows"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
compact(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Filter out all null entries in a list",
|
||||
example: "echo [1 2 $null 3 $null $null] | compact",
|
||||
result: Some(vec![
|
||||
UntaggedValue::int(1).into(),
|
||||
UntaggedValue::int(2).into(),
|
||||
UntaggedValue::int(3).into(),
|
||||
]),
|
||||
},
|
||||
Example {
|
||||
description: "Filter out all directory entries having no 'target'",
|
||||
example: "ls -la | compact target",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn compact(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let (CompactArgs { rest: columns }, input) = args.process(®istry).await?;
|
||||
Ok(input
|
||||
.filter_map(move |item| {
|
||||
future::ready(if columns.is_empty() {
|
||||
if !item.is_empty() {
|
||||
Some(ReturnSuccess::value(item))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
match item {
|
||||
Value {
|
||||
value: UntaggedValue::Row(ref r),
|
||||
..
|
||||
} => {
|
||||
if columns
|
||||
.iter()
|
||||
.all(|field| r.get_data(field).borrow().is_some())
|
||||
{
|
||||
Some(ReturnSuccess::value(item))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Compact;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Compact {})
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"config clear"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config clear")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"clear the config"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
clear(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Clear the config (be careful!)",
|
||||
example: "config clear",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clear(
|
||||
args: CommandArgs,
|
||||
_registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
|
||||
// NOTE: None because we are not loading a new config file, we just want to read from the
|
||||
// existing config
|
||||
let mut result = nu_data::config::read(name_span, &None)?;
|
||||
|
||||
result.clear();
|
||||
|
||||
config::write(&result, &None)?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(args.call_info.name_tag),
|
||||
)))
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use crate::{CommandArgs, CommandRegistry, OutputStream};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
pub struct Command;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Command {
|
||||
fn name(&self) -> &str {
|
||||
"config"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Configuration management."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
_registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let name = args.call_info.name_tag;
|
||||
let result = nu_data::config::read(name_span, &None)?;
|
||||
|
||||
Ok(futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
)])
|
||||
.to_output_stream())
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetArgs {
|
||||
get: Tagged<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"config get"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config get").required(
|
||||
"get",
|
||||
SyntaxShape::Any,
|
||||
"value to get from the config",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Gets a value from the config"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
get(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Get the current startup commands",
|
||||
example: "config get startup",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let (GetArgs { get }, _) = args.process(®istry).await?;
|
||||
|
||||
// NOTE: None because we are not loading a new config file, we just want to read from the
|
||||
// existing config
|
||||
let result = nu_data::config::read(name_span, &None)?;
|
||||
|
||||
let key = get.to_string();
|
||||
let value = result
|
||||
.get(&key)
|
||||
.ok_or_else(|| ShellError::labeled_error("Missing key in config", "key", get.tag()))?;
|
||||
|
||||
Ok(match value {
|
||||
Value {
|
||||
value: UntaggedValue::Table(list),
|
||||
..
|
||||
} => {
|
||||
let list: Vec<_> = list
|
||||
.iter()
|
||||
.map(|x| ReturnSuccess::value(x.clone()))
|
||||
.collect();
|
||||
|
||||
futures::stream::iter(list).to_output_stream()
|
||||
}
|
||||
x => {
|
||||
let x = x.clone();
|
||||
OutputStream::one(ReturnSuccess::value(x))
|
||||
}
|
||||
})
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct LoadArgs {
|
||||
load: Tagged<PathBuf>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"config load"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config load").required(
|
||||
"load",
|
||||
SyntaxShape::Path,
|
||||
"Path to load the config from",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Loads the config from the path given"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
set(args, registry).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let (LoadArgs { load }, _) = args.process(®istry).await?;
|
||||
|
||||
let configuration = load.item().clone();
|
||||
|
||||
let result = nu_data::config::read(name_span, &Some(configuration))?;
|
||||
|
||||
Ok(futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
)])
|
||||
.to_output_stream())
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
pub mod clear;
|
||||
pub mod command;
|
||||
pub mod get;
|
||||
pub mod load;
|
||||
pub mod path;
|
||||
pub mod remove;
|
||||
pub mod set;
|
||||
pub mod set_into;
|
||||
|
||||
pub use clear::SubCommand as ConfigClear;
|
||||
pub use command::Command as Config;
|
||||
pub use get::SubCommand as ConfigGet;
|
||||
pub use load::SubCommand as ConfigLoad;
|
||||
pub use path::SubCommand as ConfigPath;
|
||||
pub use remove::SubCommand as ConfigRemove;
|
||||
pub use set::SubCommand as ConfigSet;
|
||||
pub use set_into::SubCommand as ConfigSetInto;
|
@ -1,49 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"config path"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config path")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"return the path to the config file"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
path(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Get the path to the current config file",
|
||||
example: "config path",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn path(
|
||||
args: CommandArgs,
|
||||
_registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let path = config::default_path()?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Primitive(Primitive::Path(path)).into_value(args.call_info.name_tag),
|
||||
)))
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct RemoveArgs {
|
||||
remove: Tagged<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"config remove"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config remove").required(
|
||||
"remove",
|
||||
SyntaxShape::Any,
|
||||
"remove a value from the config",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Removes a value from the config"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
remove(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Remove the startup commands",
|
||||
example: "config remove startup",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn remove(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let (RemoveArgs { remove }, _) = args.process(®istry).await?;
|
||||
|
||||
let mut result = nu_data::config::read(name_span, &None)?;
|
||||
|
||||
let key = remove.to_string();
|
||||
|
||||
if result.contains_key(&key) {
|
||||
result.swap_remove(&key);
|
||||
config::write(&result, &None)?;
|
||||
Ok(futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(remove.tag()),
|
||||
)])
|
||||
.to_output_stream())
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Key does not exist in config",
|
||||
"key",
|
||||
remove.tag(),
|
||||
))
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetArgs {
|
||||
key: Tagged<String>,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"config set"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config set")
|
||||
.required("key", SyntaxShape::String, "variable name to set")
|
||||
.required("value", SyntaxShape::Any, "value to use")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Sets a value in the config"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
set(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Set nonzero_exit_errors to true",
|
||||
example: "config set nonzero_exit_errors $true",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let (SetArgs { key, value }, _) = args.process(®istry).await?;
|
||||
|
||||
// NOTE: None because we are not loading a new config file, we just want to read from the
|
||||
// existing config
|
||||
let mut result = nu_data::config::read(name_span, &None)?;
|
||||
|
||||
result.insert(key.to_string(), value.clone());
|
||||
|
||||
config::write(&result, &None)?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(&value.tag),
|
||||
)))
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetIntoArgs {
|
||||
set_into: Tagged<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"config set_into"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config set_into").required(
|
||||
"set_into",
|
||||
SyntaxShape::String,
|
||||
"sets a variable from values in the pipeline",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Sets a value in the config"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
set_into(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Store the contents of the pipeline as a path",
|
||||
example: "echo ['/usr/bin' '/bin'] | config set_into path",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_into(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let name = args.call_info.name_tag.clone();
|
||||
|
||||
let (SetIntoArgs { set_into: v }, input) = args.process(®istry).await?;
|
||||
|
||||
// NOTE: None because we are not loading a new config file, we just want to read from the
|
||||
// existing config
|
||||
let mut result = nu_data::config::read(name_span, &None)?;
|
||||
|
||||
// In the original code, this is set to `Some` if the `load flag is set`
|
||||
let configuration = None;
|
||||
|
||||
let rows: Vec<Value> = input.collect().await;
|
||||
let key = v.to_string();
|
||||
|
||||
Ok(if rows.is_empty() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"No values given for set_into",
|
||||
"needs value(s) from pipeline",
|
||||
v.tag(),
|
||||
));
|
||||
} else if rows.len() == 1 {
|
||||
// A single value
|
||||
let value = &rows[0];
|
||||
|
||||
result.insert(key, value.clone());
|
||||
|
||||
config::write(&result, &configuration)?;
|
||||
|
||||
OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
))
|
||||
} else {
|
||||
// Take in the pipeline as a table
|
||||
let value = UntaggedValue::Table(rows).into_value(name.clone());
|
||||
|
||||
result.insert(key, value);
|
||||
|
||||
config::write(&result, &configuration)?;
|
||||
|
||||
OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
))
|
||||
})
|
||||
}
|
@ -1,358 +0,0 @@
|
||||
pub const BAT_LANGUAGES: &[&str] = &[
|
||||
"as",
|
||||
"csv",
|
||||
"tsv",
|
||||
"applescript",
|
||||
"script editor",
|
||||
"s",
|
||||
"S",
|
||||
"adoc",
|
||||
"asciidoc",
|
||||
"asc",
|
||||
"asa",
|
||||
"yasm",
|
||||
"nasm",
|
||||
"asm",
|
||||
"inc",
|
||||
"mac",
|
||||
"awk",
|
||||
"bat",
|
||||
"cmd",
|
||||
"bib",
|
||||
"sh",
|
||||
"bash",
|
||||
"zsh",
|
||||
".bash_aliases",
|
||||
".bash_completions",
|
||||
".bash_functions",
|
||||
".bash_login",
|
||||
".bash_logout",
|
||||
".bash_profile",
|
||||
".bash_variables",
|
||||
".bashrc",
|
||||
".profile",
|
||||
".textmate_init",
|
||||
".zshrc",
|
||||
"PKGBUILD",
|
||||
".ebuild",
|
||||
".eclass",
|
||||
"c",
|
||||
"h",
|
||||
"cs",
|
||||
"csx",
|
||||
"cpp",
|
||||
"cc",
|
||||
"cp",
|
||||
"cxx",
|
||||
"c++",
|
||||
"C",
|
||||
"h",
|
||||
"hh",
|
||||
"hpp",
|
||||
"hxx",
|
||||
"h++",
|
||||
"inl",
|
||||
"ipp",
|
||||
"cabal",
|
||||
"clj",
|
||||
"cljc",
|
||||
"cljs",
|
||||
"edn",
|
||||
"CMakeLists.txt",
|
||||
"cmake",
|
||||
"h.in",
|
||||
"hh.in",
|
||||
"hpp.in",
|
||||
"hxx.in",
|
||||
"h++.in",
|
||||
"CMakeCache.txt",
|
||||
"cr",
|
||||
"css",
|
||||
"css.erb",
|
||||
"css.liquid",
|
||||
"d",
|
||||
"di",
|
||||
"dart",
|
||||
"diff",
|
||||
"patch",
|
||||
"Dockerfile",
|
||||
"dockerfile",
|
||||
"ex",
|
||||
"exs",
|
||||
"elm",
|
||||
"erl",
|
||||
"hrl",
|
||||
"Emakefile",
|
||||
"emakefile",
|
||||
"fs",
|
||||
"fsi",
|
||||
"fsx",
|
||||
"fs",
|
||||
"fsi",
|
||||
"fsx",
|
||||
"fish",
|
||||
"attributes",
|
||||
"gitattributes",
|
||||
".gitattributes",
|
||||
"COMMIT_EDITMSG",
|
||||
"MERGE_MSG",
|
||||
"TAG_EDITMSG",
|
||||
"gitconfig",
|
||||
".gitconfig",
|
||||
".gitmodules",
|
||||
"exclude",
|
||||
"gitignore",
|
||||
".gitignore",
|
||||
".git",
|
||||
"gitlog",
|
||||
"git-rebase-todo",
|
||||
"go",
|
||||
"dot",
|
||||
"DOT",
|
||||
"gv",
|
||||
"groovy",
|
||||
"gvy",
|
||||
"gradle",
|
||||
"Jenkinsfile",
|
||||
"hs",
|
||||
"hs",
|
||||
"hsc",
|
||||
"show-nonprintable",
|
||||
"html",
|
||||
"htm",
|
||||
"shtml",
|
||||
"xhtml",
|
||||
"asp",
|
||||
"html.eex",
|
||||
"yaws",
|
||||
"rails",
|
||||
"rhtml",
|
||||
"erb",
|
||||
"html.erb",
|
||||
"adp",
|
||||
"twig",
|
||||
"html.twig",
|
||||
"ini",
|
||||
"INI",
|
||||
"INF",
|
||||
"reg",
|
||||
"REG",
|
||||
"lng",
|
||||
"cfg",
|
||||
"CFG",
|
||||
"desktop",
|
||||
"url",
|
||||
"URL",
|
||||
".editorconfig",
|
||||
".hgrc",
|
||||
"hgrc",
|
||||
"java",
|
||||
"bsh",
|
||||
"properties",
|
||||
"jsp",
|
||||
"js",
|
||||
"htc",
|
||||
"js",
|
||||
"jsx",
|
||||
"babel",
|
||||
"es6",
|
||||
"js.erb",
|
||||
"json",
|
||||
"sublime-settings",
|
||||
"sublime-menu",
|
||||
"sublime-keymap",
|
||||
"sublime-mousemap",
|
||||
"sublime-theme",
|
||||
"sublime-build",
|
||||
"sublime-project",
|
||||
"sublime-completions",
|
||||
"sublime-commands",
|
||||
"sublime-macro",
|
||||
"sublime-color-scheme",
|
||||
"ipynb",
|
||||
"Pipfile.lock",
|
||||
"jsonnet",
|
||||
"libsonnet",
|
||||
"libjsonnet",
|
||||
"jl",
|
||||
"kt",
|
||||
"kts",
|
||||
"tex",
|
||||
"ltx",
|
||||
"less",
|
||||
"css.less",
|
||||
"lisp",
|
||||
"cl",
|
||||
"clisp",
|
||||
"l",
|
||||
"mud",
|
||||
"el",
|
||||
"scm",
|
||||
"ss",
|
||||
"lsp",
|
||||
"fasl",
|
||||
"lhs",
|
||||
"lua",
|
||||
"make",
|
||||
"GNUmakefile",
|
||||
"makefile",
|
||||
"Makefile",
|
||||
"makefile.am",
|
||||
"Makefile.am",
|
||||
"makefile.in",
|
||||
"Makefile.in",
|
||||
"OCamlMakefile",
|
||||
"mak",
|
||||
"mk",
|
||||
"md",
|
||||
"mdown",
|
||||
"markdown",
|
||||
"markdn",
|
||||
"matlab",
|
||||
"build",
|
||||
"nix",
|
||||
"m",
|
||||
"h",
|
||||
"mm",
|
||||
"M",
|
||||
"h",
|
||||
"ml",
|
||||
"mli",
|
||||
"mll",
|
||||
"mly",
|
||||
"pas",
|
||||
"p",
|
||||
"dpr",
|
||||
"pl",
|
||||
"pm",
|
||||
"pod",
|
||||
"t",
|
||||
"PL",
|
||||
"php",
|
||||
"php3",
|
||||
"php4",
|
||||
"php5",
|
||||
"php7",
|
||||
"phps",
|
||||
"phpt",
|
||||
"phtml",
|
||||
"txt",
|
||||
"ps1",
|
||||
"psm1",
|
||||
"psd1",
|
||||
"proto",
|
||||
"protodevel",
|
||||
"pb.txt",
|
||||
"proto.text",
|
||||
"textpb",
|
||||
"pbtxt",
|
||||
"prototxt",
|
||||
"pp",
|
||||
"epp",
|
||||
"purs",
|
||||
"py",
|
||||
"py3",
|
||||
"pyw",
|
||||
"pyi",
|
||||
"pyx",
|
||||
"pyx.in",
|
||||
"pxd",
|
||||
"pxd.in",
|
||||
"pxi",
|
||||
"pxi.in",
|
||||
"rpy",
|
||||
"cpy",
|
||||
"SConstruct",
|
||||
"Sconstruct",
|
||||
"sconstruct",
|
||||
"SConscript",
|
||||
"gyp",
|
||||
"gypi",
|
||||
"Snakefile",
|
||||
"wscript",
|
||||
"R",
|
||||
"r",
|
||||
"s",
|
||||
"S",
|
||||
"Rprofile",
|
||||
"rd",
|
||||
"re",
|
||||
"rst",
|
||||
"rest",
|
||||
"robot",
|
||||
"rb",
|
||||
"Appfile",
|
||||
"Appraisals",
|
||||
"Berksfile",
|
||||
"Brewfile",
|
||||
"capfile",
|
||||
"cgi",
|
||||
"Cheffile",
|
||||
"config.ru",
|
||||
"Deliverfile",
|
||||
"Fastfile",
|
||||
"fcgi",
|
||||
"Gemfile",
|
||||
"gemspec",
|
||||
"Guardfile",
|
||||
"irbrc",
|
||||
"jbuilder",
|
||||
"Podfile",
|
||||
"podspec",
|
||||
"prawn",
|
||||
"rabl",
|
||||
"rake",
|
||||
"Rakefile",
|
||||
"Rantfile",
|
||||
"rbx",
|
||||
"rjs",
|
||||
"ruby.rail",
|
||||
"Scanfile",
|
||||
"simplecov",
|
||||
"Snapfile",
|
||||
"thor",
|
||||
"Thorfile",
|
||||
"Vagrantfile",
|
||||
"haml",
|
||||
"sass",
|
||||
"rxml",
|
||||
"builder",
|
||||
"rs",
|
||||
"scala",
|
||||
"sbt",
|
||||
"sql",
|
||||
"ddl",
|
||||
"dml",
|
||||
"erbsql",
|
||||
"sql.erb",
|
||||
"swift",
|
||||
"log",
|
||||
"tcl",
|
||||
"tf",
|
||||
"tfvars",
|
||||
"hcl",
|
||||
"sty",
|
||||
"cls",
|
||||
"textile",
|
||||
"toml",
|
||||
"tml",
|
||||
"Cargo.lock",
|
||||
"Gopkg.lock",
|
||||
"Pipfile",
|
||||
"ts",
|
||||
"tsx",
|
||||
"varlink",
|
||||
"vim",
|
||||
".vimrc",
|
||||
"xml",
|
||||
"xsd",
|
||||
"xslt",
|
||||
"tld",
|
||||
"dtml",
|
||||
"rss",
|
||||
"opml",
|
||||
"svg",
|
||||
"yaml",
|
||||
"yml",
|
||||
"sublime-syntax",
|
||||
];
|
@ -1,90 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use futures::stream::StreamExt;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, UntaggedValue, Value};
|
||||
|
||||
pub struct Count;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CountArgs {
|
||||
column: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Count {
|
||||
fn name(&self) -> &str {
|
||||
"count"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("count").switch(
|
||||
"column",
|
||||
"Calculate number of columns in table",
|
||||
Some('c'),
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Show the total number of rows or items."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let (CountArgs { column }, input) = args.process(®istry).await?;
|
||||
let rows: Vec<Value> = input.collect().await;
|
||||
|
||||
let count = if column {
|
||||
if rows.is_empty() {
|
||||
0
|
||||
} else {
|
||||
match &rows[0].value {
|
||||
UntaggedValue::Row(dictionary) => dictionary.length(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Cannot obtain column count",
|
||||
"cannot obtain column count",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rows.len()
|
||||
};
|
||||
|
||||
Ok(OutputStream::one(UntaggedValue::int(count).into_value(tag)))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Count the number of entries in a list",
|
||||
example: "echo [1 2 3 4 5] | count",
|
||||
result: Some(vec![UntaggedValue::int(5).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Count the number of columns in the calendar table",
|
||||
example: "cal | count -c",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Count;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Count {})
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Cpy;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CopyArgs {
|
||||
pub src: Tagged<PathBuf>,
|
||||
pub dst: Tagged<PathBuf>,
|
||||
pub recursive: Tagged<bool>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Cpy {
|
||||
fn name(&self) -> &str {
|
||||
"cp"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("cp")
|
||||
.required("src", SyntaxShape::Pattern, "the place to copy from")
|
||||
.required("dst", SyntaxShape::Path, "the place to copy to")
|
||||
.switch(
|
||||
"recursive",
|
||||
"copy recursively through subdirectories",
|
||||
Some('r'),
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Copy files."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let shell_manager = args.shell_manager.clone();
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let (args, _) = args.process(®istry).await?;
|
||||
shell_manager.cp(args, name)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Copy myfile to dir_b",
|
||||
example: "cp myfile dir_b",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Recursively copy dir_a to dir_b",
|
||||
example: "cp -r dir_a dir_b",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Cpy;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Cpy {})
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
pub struct Command;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Command {
|
||||
fn name(&self) -> &str {
|
||||
"date"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("date")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Apply date function"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
_args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(crate::commands::help::get_help(&Command, ®istry))
|
||||
.into_value(Tag::unknown()),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Command;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Command {})
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
use chrono::{DateTime, Local};
|
||||
use nu_errors::ShellError;
|
||||
|
||||
use crate::commands::date::utils::{date_to_value, date_to_value_raw};
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct Date;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FormatArgs {
|
||||
format: Tagged<String>,
|
||||
raw: Option<bool>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Date {
|
||||
fn name(&self) -> &str {
|
||||
"date format"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("date format")
|
||||
.required("format", SyntaxShape::String, "strftime format")
|
||||
.switch("raw", "print date without tables", Some('r'))
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"format the current date using the given format string."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
format(args, registry).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn format(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let (FormatArgs { format, raw }, _) = args.process(®istry).await?;
|
||||
|
||||
let dt_fmt = format.to_string();
|
||||
|
||||
let value = {
|
||||
let local: DateTime<Local> = Local::now();
|
||||
if let Some(true) = raw {
|
||||
UntaggedValue::string(date_to_value_raw(local, dt_fmt)).into_untagged_value()
|
||||
} else {
|
||||
date_to_value(local, tag, dt_fmt)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(OutputStream::one(value))
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
pub mod command;
|
||||
pub mod format;
|
||||
pub mod now;
|
||||
pub mod utc;
|
||||
|
||||
mod utils;
|
||||
|
||||
pub use command::Command as Date;
|
||||
pub use format::Date as DateFormat;
|
||||
pub use now::Date as DateNow;
|
||||
pub use utc::Date as DateUTC;
|
@ -1,50 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
use chrono::{DateTime, Local};
|
||||
use nu_errors::ShellError;
|
||||
|
||||
use crate::commands::date::utils::date_to_value;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use nu_protocol::Signature;
|
||||
|
||||
pub struct Date;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Date {
|
||||
fn name(&self) -> &str {
|
||||
"date now"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("date now")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"return the current date."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
now(args, registry).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn now(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let args = args.evaluate_once(®istry).await?;
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let no_fmt = "".to_string();
|
||||
|
||||
let value = {
|
||||
let local: DateTime<Local> = Local::now();
|
||||
date_to_value(local, tag, no_fmt)
|
||||
};
|
||||
|
||||
Ok(OutputStream::one(value))
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
use chrono::{DateTime, Utc};
|
||||
use nu_errors::ShellError;
|
||||
|
||||
use crate::commands::date::utils::date_to_value;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use nu_protocol::Signature;
|
||||
|
||||
pub struct Date;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Date {
|
||||
fn name(&self) -> &str {
|
||||
"date utc"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("date utc")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"return the current date in utc."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
utc(args, registry).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn utc(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let args = args.evaluate_once(®istry).await?;
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
|
||||
let no_fmt = "".to_string();
|
||||
|
||||
let value = {
|
||||
let local: DateTime<Utc> = Utc::now();
|
||||
date_to_value(local, tag, no_fmt)
|
||||
};
|
||||
|
||||
Ok(OutputStream::one(value))
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
use chrono::DateTime;
|
||||
use nu_protocol::{Dictionary, Value};
|
||||
|
||||
use chrono::{Datelike, TimeZone, Timelike};
|
||||
use core::fmt::Display;
|
||||
use indexmap::IndexMap;
|
||||
use nu_protocol::UntaggedValue;
|
||||
|
||||
pub fn date_to_value_raw<T: TimeZone>(dt: DateTime<T>, dt_format: String) -> String
|
||||
where
|
||||
T::Offset: Display,
|
||||
{
|
||||
let result = dt.format(&dt_format);
|
||||
format!("{}", result)
|
||||
}
|
||||
|
||||
pub fn date_to_value<T: TimeZone>(dt: DateTime<T>, tag: Tag, dt_format: String) -> Value
|
||||
where
|
||||
T::Offset: Display,
|
||||
{
|
||||
let mut indexmap = IndexMap::new();
|
||||
|
||||
if dt_format.is_empty() {
|
||||
indexmap.insert(
|
||||
"year".to_string(),
|
||||
UntaggedValue::int(dt.year()).into_value(&tag),
|
||||
);
|
||||
indexmap.insert(
|
||||
"month".to_string(),
|
||||
UntaggedValue::int(dt.month()).into_value(&tag),
|
||||
);
|
||||
indexmap.insert(
|
||||
"day".to_string(),
|
||||
UntaggedValue::int(dt.day()).into_value(&tag),
|
||||
);
|
||||
indexmap.insert(
|
||||
"hour".to_string(),
|
||||
UntaggedValue::int(dt.hour()).into_value(&tag),
|
||||
);
|
||||
indexmap.insert(
|
||||
"minute".to_string(),
|
||||
UntaggedValue::int(dt.minute()).into_value(&tag),
|
||||
);
|
||||
indexmap.insert(
|
||||
"second".to_string(),
|
||||
UntaggedValue::int(dt.second()).into_value(&tag),
|
||||
);
|
||||
|
||||
let tz = dt.offset();
|
||||
indexmap.insert(
|
||||
"timezone".to_string(),
|
||||
UntaggedValue::string(format!("{}", tz)).into_value(&tag),
|
||||
);
|
||||
} else {
|
||||
let result = dt.format(&dt_format);
|
||||
indexmap.insert(
|
||||
"formatted".to_string(),
|
||||
UntaggedValue::string(format!("{}", result)).into_value(&tag),
|
||||
);
|
||||
}
|
||||
|
||||
UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag)
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
pub struct Debug;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DebugArgs {
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Debug {
|
||||
fn name(&self) -> &str {
|
||||
"debug"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("debug").switch("raw", "Prints the raw value representation.", Some('r'))
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Print the Rust debug representation of the values"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
debug_value(args, registry).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn debug_value(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let (DebugArgs { raw }, input) = args.process(®istry).await?;
|
||||
Ok(input
|
||||
.map(move |v| {
|
||||
if raw {
|
||||
ReturnSuccess::value(
|
||||
UntaggedValue::string(format!("{:#?}", v)).into_untagged_value(),
|
||||
)
|
||||
} else {
|
||||
ReturnSuccess::debug_value(v)
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Debug;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Debug {})
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
use nu_value_ext::ValueExt;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DefaultArgs {
|
||||
column: Tagged<String>,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
pub struct Default;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Default {
|
||||
fn name(&self) -> &str {
|
||||
"default"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("default")
|
||||
.required("column name", SyntaxShape::String, "the name of the column")
|
||||
.required(
|
||||
"column value",
|
||||
SyntaxShape::Any,
|
||||
"the value of the column to default",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Sets a default row's column if missing."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
default(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Give a default 'target' to all file entries",
|
||||
example: "ls -la | default target 'nothing'",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
async fn default(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let (DefaultArgs { column, value }, input) = args.process(®istry).await?;
|
||||
|
||||
Ok(input
|
||||
.map(move |item| {
|
||||
let should_add = matches!(
|
||||
item,
|
||||
Value {
|
||||
value: UntaggedValue::Row(ref r),
|
||||
..
|
||||
} if r.get_data(&column.item).borrow().is_none()
|
||||
);
|
||||
|
||||
if should_add {
|
||||
match item.insert_data_at_path(&column.item, value.clone()) {
|
||||
Some(new_value) => ReturnSuccess::value(new_value),
|
||||
None => ReturnSuccess::value(item),
|
||||
}
|
||||
} else {
|
||||
ReturnSuccess::value(item)
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Default;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Default {})
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
hir::Block, hir::ExternalRedirection, ReturnSuccess, Signature, SyntaxShape, Value,
|
||||
};
|
||||
|
||||
pub struct Do;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct DoArgs {
|
||||
block: Block,
|
||||
ignore_errors: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Do {
|
||||
fn name(&self) -> &str {
|
||||
"do"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("do")
|
||||
.required("block", SyntaxShape::Block, "the block to run ")
|
||||
.switch(
|
||||
"ignore_errors",
|
||||
"ignore errors as the block runs",
|
||||
Some('i'),
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Runs a block, optionally ignoring errors"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
do_(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Run the block",
|
||||
example: r#"do { echo hello }"#,
|
||||
result: Some(vec![Value::from("hello")]),
|
||||
},
|
||||
Example {
|
||||
description: "Run the block and ignore errors",
|
||||
example: r#"do -i { thisisnotarealcommand }"#,
|
||||
result: Some(vec![Value::nothing()]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
async fn do_(
|
||||
raw_args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let external_redirection = raw_args.call_info.args.external_redirection;
|
||||
|
||||
let mut context = EvaluationContext::from_raw(&raw_args, ®istry);
|
||||
let scope = raw_args.call_info.scope.clone();
|
||||
let (
|
||||
DoArgs {
|
||||
ignore_errors,
|
||||
mut block,
|
||||
},
|
||||
input,
|
||||
) = raw_args.process(®istry).await?;
|
||||
|
||||
let block_redirection = match external_redirection {
|
||||
ExternalRedirection::None => {
|
||||
if ignore_errors {
|
||||
ExternalRedirection::Stderr
|
||||
} else {
|
||||
ExternalRedirection::None
|
||||
}
|
||||
}
|
||||
ExternalRedirection::Stdout => {
|
||||
if ignore_errors {
|
||||
ExternalRedirection::StdoutAndStderr
|
||||
} else {
|
||||
ExternalRedirection::Stdout
|
||||
}
|
||||
}
|
||||
x => x,
|
||||
};
|
||||
|
||||
block.set_redirect(block_redirection);
|
||||
|
||||
let result = run_block(
|
||||
&block,
|
||||
&mut context,
|
||||
input,
|
||||
&scope.it,
|
||||
&scope.vars,
|
||||
&scope.env,
|
||||
)
|
||||
.await;
|
||||
|
||||
if ignore_errors {
|
||||
// To properly ignore errors we need to redirect stderr, consume it, and remove
|
||||
// any errors we see in the process.
|
||||
|
||||
match result {
|
||||
Ok(mut stream) => {
|
||||
let output = stream.drain_vec().await;
|
||||
context.clear_errors();
|
||||
Ok(futures::stream::iter(output).to_output_stream())
|
||||
}
|
||||
Err(_) => Ok(OutputStream::one(ReturnSuccess::value(Value::nothing()))),
|
||||
}
|
||||
} else {
|
||||
result.map(|x| x.to_output_stream())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Do;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Do {})
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct Drop;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DropArgs {
|
||||
rows: Option<Tagged<u64>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Drop {
|
||||
fn name(&self) -> &str {
|
||||
"drop"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("drop").optional(
|
||||
"rows",
|
||||
SyntaxShape::Number,
|
||||
"starting from the back, the number of rows to remove",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Remove the last number of rows. If you want to remove columns, try 'reject'."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
drop(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Remove the last item of a list/table",
|
||||
example: "echo [1 2 3] | drop",
|
||||
result: Some(vec![
|
||||
UntaggedValue::int(1).into(),
|
||||
UntaggedValue::int(2).into(),
|
||||
]),
|
||||
},
|
||||
Example {
|
||||
description: "Remove the last 2 items of a list/table",
|
||||
example: "echo [1 2 3] | drop 2",
|
||||
result: Some(vec![UntaggedValue::int(1).into()]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
async fn drop(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let (DropArgs { rows }, input) = args.process(®istry).await?;
|
||||
let v: Vec<_> = input.into_vec().await;
|
||||
|
||||
let rows_to_drop = if let Some(quantity) = rows {
|
||||
*quantity as usize
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
Ok(if rows_to_drop == 0 {
|
||||
futures::stream::iter(v).to_output_stream()
|
||||
} else {
|
||||
let k = if v.len() < rows_to_drop {
|
||||
0
|
||||
} else {
|
||||
v.len() - rows_to_drop
|
||||
};
|
||||
|
||||
let iter = v.into_iter().take(k);
|
||||
|
||||
futures::stream::iter(iter).to_output_stream()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Drop;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Drop {})
|
||||
}
|
||||
}
|
@ -1,437 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use filesize::file_real_size_fast;
|
||||
use glob::*;
|
||||
use indexmap::map::IndexMap;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
const NAME: &str = "du";
|
||||
const GLOB_PARAMS: MatchOptions = MatchOptions {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: true,
|
||||
require_literal_leading_dot: false,
|
||||
};
|
||||
|
||||
pub struct Du;
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
pub struct DuArgs {
|
||||
path: Option<Tagged<PathBuf>>,
|
||||
all: bool,
|
||||
deref: bool,
|
||||
exclude: Option<Tagged<String>>,
|
||||
#[serde(rename = "max-depth")]
|
||||
max_depth: Option<Tagged<u64>>,
|
||||
#[serde(rename = "min-size")]
|
||||
min_size: Option<Tagged<u64>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Du {
|
||||
fn name(&self) -> &str {
|
||||
NAME
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(NAME)
|
||||
.optional("path", SyntaxShape::Pattern, "starting directory")
|
||||
.switch(
|
||||
"all",
|
||||
"Output file sizes as well as directory sizes",
|
||||
Some('a'),
|
||||
)
|
||||
.switch(
|
||||
"deref",
|
||||
"Dereference symlinks to their targets for size",
|
||||
Some('r'),
|
||||
)
|
||||
.named(
|
||||
"exclude",
|
||||
SyntaxShape::Pattern,
|
||||
"Exclude these file names",
|
||||
Some('x'),
|
||||
)
|
||||
.named(
|
||||
"max-depth",
|
||||
SyntaxShape::Int,
|
||||
"Directory recursion limit",
|
||||
Some('d'),
|
||||
)
|
||||
.named(
|
||||
"min-size",
|
||||
SyntaxShape::Int,
|
||||
"Exclude files below this size",
|
||||
Some('m'),
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Find disk usage sizes of specified items"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
du(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Disk usage of the current directory",
|
||||
example: "du",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
async fn du(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let ctrl_c = args.ctrl_c.clone();
|
||||
let ctrl_c_copy = ctrl_c.clone();
|
||||
|
||||
let (args, _): (DuArgs, _) = args.process(®istry).await?;
|
||||
let exclude = args.exclude.map_or(Ok(None), move |x| {
|
||||
Pattern::new(&x.item)
|
||||
.map(Option::Some)
|
||||
.map_err(|e| ShellError::labeled_error(e.msg, "glob error", x.tag.clone()))
|
||||
})?;
|
||||
|
||||
let include_files = args.all;
|
||||
let paths = match args.path {
|
||||
Some(p) => {
|
||||
let p = p.item.to_str().expect("Why isn't this encoded properly?");
|
||||
glob::glob_with(p, GLOB_PARAMS)
|
||||
}
|
||||
None => glob::glob_with("*", GLOB_PARAMS),
|
||||
}
|
||||
.map_err(|e| ShellError::labeled_error(e.msg, "glob error", tag.clone()))?
|
||||
.filter(move |p| {
|
||||
if include_files {
|
||||
true
|
||||
} else {
|
||||
match p {
|
||||
Ok(f) if f.is_dir() => true,
|
||||
Err(e) if e.path().is_dir() => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(|v| v.map_err(glob_err_into));
|
||||
|
||||
let all = args.all;
|
||||
let deref = args.deref;
|
||||
let max_depth = args.max_depth.map(|f| f.item);
|
||||
let min_size = args.min_size.map(|f| f.item);
|
||||
|
||||
let params = DirBuilder {
|
||||
tag: tag.clone(),
|
||||
min: min_size,
|
||||
deref,
|
||||
exclude,
|
||||
all,
|
||||
};
|
||||
|
||||
let inp = futures::stream::iter(paths);
|
||||
|
||||
Ok(inp
|
||||
.flat_map(move |path| match path {
|
||||
Ok(p) => {
|
||||
let mut output = vec![];
|
||||
if p.is_dir() {
|
||||
output.push(Ok(ReturnSuccess::Value(
|
||||
DirInfo::new(p, ¶ms, max_depth, ctrl_c.clone()).into(),
|
||||
)));
|
||||
} else {
|
||||
for v in FileInfo::new(p, deref, tag.clone()).into_iter() {
|
||||
output.push(Ok(ReturnSuccess::Value(v.into())));
|
||||
}
|
||||
}
|
||||
futures::stream::iter(output)
|
||||
}
|
||||
Err(e) => futures::stream::iter(vec![Err(e)]),
|
||||
})
|
||||
.interruptible(ctrl_c_copy)
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
pub struct DirBuilder {
|
||||
tag: Tag,
|
||||
min: Option<u64>,
|
||||
deref: bool,
|
||||
exclude: Option<Pattern>,
|
||||
all: bool,
|
||||
}
|
||||
|
||||
impl DirBuilder {
|
||||
pub fn new(
|
||||
tag: Tag,
|
||||
min: Option<u64>,
|
||||
deref: bool,
|
||||
exclude: Option<Pattern>,
|
||||
all: bool,
|
||||
) -> DirBuilder {
|
||||
DirBuilder {
|
||||
tag,
|
||||
min,
|
||||
deref,
|
||||
exclude,
|
||||
all,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DirInfo {
|
||||
dirs: Vec<DirInfo>,
|
||||
files: Vec<FileInfo>,
|
||||
errors: Vec<ShellError>,
|
||||
size: u64,
|
||||
blocks: u64,
|
||||
path: PathBuf,
|
||||
tag: Tag,
|
||||
}
|
||||
|
||||
struct FileInfo {
|
||||
path: PathBuf,
|
||||
size: u64,
|
||||
blocks: Option<u64>,
|
||||
tag: Tag,
|
||||
}
|
||||
|
||||
impl FileInfo {
|
||||
fn new(path: impl Into<PathBuf>, deref: bool, tag: Tag) -> Result<Self, ShellError> {
|
||||
let path = path.into();
|
||||
let m = if deref {
|
||||
std::fs::metadata(&path)
|
||||
} else {
|
||||
std::fs::symlink_metadata(&path)
|
||||
};
|
||||
|
||||
match m {
|
||||
Ok(d) => {
|
||||
let block_size = file_real_size_fast(&path, &d).ok();
|
||||
|
||||
Ok(FileInfo {
|
||||
path,
|
||||
blocks: block_size,
|
||||
size: d.len(),
|
||||
tag,
|
||||
})
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DirInfo {
|
||||
pub fn new(
|
||||
path: impl Into<PathBuf>,
|
||||
params: &DirBuilder,
|
||||
depth: Option<u64>,
|
||||
ctrl_c: Arc<AtomicBool>,
|
||||
) -> Self {
|
||||
let path = path.into();
|
||||
|
||||
let mut s = Self {
|
||||
dirs: Vec::new(),
|
||||
errors: Vec::new(),
|
||||
files: Vec::new(),
|
||||
size: 0,
|
||||
blocks: 0,
|
||||
tag: params.tag.clone(),
|
||||
path,
|
||||
};
|
||||
|
||||
match std::fs::read_dir(&s.path) {
|
||||
Ok(d) => {
|
||||
for f in d {
|
||||
if ctrl_c.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
|
||||
match f {
|
||||
Ok(i) => match i.file_type() {
|
||||
Ok(t) if t.is_dir() => {
|
||||
s = s.add_dir(i.path(), depth, ¶ms, ctrl_c.clone())
|
||||
}
|
||||
Ok(_t) => s = s.add_file(i.path(), ¶ms),
|
||||
Err(e) => s = s.add_error(e.into()),
|
||||
},
|
||||
Err(e) => s = s.add_error(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => s = s.add_error(e.into()),
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
fn add_dir(
|
||||
mut self,
|
||||
path: impl Into<PathBuf>,
|
||||
mut depth: Option<u64>,
|
||||
params: &DirBuilder,
|
||||
ctrl_c: Arc<AtomicBool>,
|
||||
) -> Self {
|
||||
if let Some(current) = depth {
|
||||
if let Some(new) = current.checked_sub(1) {
|
||||
depth = Some(new);
|
||||
} else {
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
let d = DirInfo::new(path, ¶ms, depth, ctrl_c);
|
||||
self.size += d.size;
|
||||
self.blocks += d.blocks;
|
||||
self.dirs.push(d);
|
||||
self
|
||||
}
|
||||
|
||||
fn add_file(mut self, f: impl Into<PathBuf>, params: &DirBuilder) -> Self {
|
||||
let f = f.into();
|
||||
let include = params
|
||||
.exclude
|
||||
.as_ref()
|
||||
.map_or(true, |x| !x.matches_path(&f));
|
||||
if include {
|
||||
match FileInfo::new(f, params.deref, self.tag.clone()) {
|
||||
Ok(file) => {
|
||||
let inc = params.min.map_or(true, |s| file.size >= s);
|
||||
if inc {
|
||||
self.size += file.size;
|
||||
self.blocks += file.blocks.unwrap_or(0);
|
||||
if params.all {
|
||||
self.files.push(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => self = self.add_error(e),
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
fn add_error(mut self, e: ShellError) -> Self {
|
||||
self.errors.push(e);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_size(&self) -> u64 {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
||||
fn glob_err_into(e: GlobError) -> ShellError {
|
||||
let e = e.into_error();
|
||||
ShellError::from(e)
|
||||
}
|
||||
|
||||
fn value_from_vec<V>(vec: Vec<V>, tag: &Tag) -> Value
|
||||
where
|
||||
V: Into<Value>,
|
||||
{
|
||||
if vec.is_empty() {
|
||||
UntaggedValue::nothing()
|
||||
} else {
|
||||
let values = vec.into_iter().map(Into::into).collect::<Vec<Value>>();
|
||||
UntaggedValue::Table(values)
|
||||
}
|
||||
.into_value(tag)
|
||||
}
|
||||
|
||||
impl From<DirInfo> for Value {
|
||||
fn from(d: DirInfo) -> Self {
|
||||
let mut r: IndexMap<String, Value> = IndexMap::new();
|
||||
|
||||
r.insert(
|
||||
"path".to_string(),
|
||||
UntaggedValue::path(d.path).into_value(&d.tag),
|
||||
);
|
||||
|
||||
r.insert(
|
||||
"apparent".to_string(),
|
||||
UntaggedValue::filesize(d.size).into_value(&d.tag),
|
||||
);
|
||||
|
||||
r.insert(
|
||||
"physical".to_string(),
|
||||
UntaggedValue::filesize(d.blocks).into_value(&d.tag),
|
||||
);
|
||||
|
||||
r.insert("directories".to_string(), value_from_vec(d.dirs, &d.tag));
|
||||
|
||||
r.insert("files".to_string(), value_from_vec(d.files, &d.tag));
|
||||
|
||||
if !d.errors.is_empty() {
|
||||
let v = UntaggedValue::Table(
|
||||
d.errors
|
||||
.into_iter()
|
||||
.map(move |e| UntaggedValue::Error(e).into_untagged_value())
|
||||
.collect::<Vec<Value>>(),
|
||||
)
|
||||
.into_value(&d.tag);
|
||||
|
||||
r.insert("errors".to_string(), v);
|
||||
}
|
||||
|
||||
Value {
|
||||
value: UntaggedValue::row(r),
|
||||
tag: d.tag,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FileInfo> for Value {
|
||||
fn from(f: FileInfo) -> Self {
|
||||
let mut r: IndexMap<String, Value> = IndexMap::new();
|
||||
|
||||
r.insert(
|
||||
"path".to_string(),
|
||||
UntaggedValue::path(f.path).into_value(&f.tag),
|
||||
);
|
||||
|
||||
r.insert(
|
||||
"apparent".to_string(),
|
||||
UntaggedValue::filesize(f.size).into_value(&f.tag),
|
||||
);
|
||||
|
||||
let b = f
|
||||
.blocks
|
||||
.map(UntaggedValue::filesize)
|
||||
.unwrap_or_else(UntaggedValue::nothing)
|
||||
.into_value(&f.tag);
|
||||
|
||||
r.insert("physical".to_string(), b);
|
||||
|
||||
r.insert(
|
||||
"directories".to_string(),
|
||||
UntaggedValue::nothing().into_value(&f.tag),
|
||||
);
|
||||
|
||||
r.insert(
|
||||
"files".to_string(),
|
||||
UntaggedValue::nothing().into_value(&f.tag),
|
||||
);
|
||||
|
||||
UntaggedValue::row(r).into_value(&f.tag)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Du;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Du {})
|
||||
}
|
||||
}
|