Compare commits
1015 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7400e6ed6b | ||
|
|
93394e7054 | ||
|
|
f030154ef6 | ||
|
|
10a2225aae | ||
|
|
de793e5902 | ||
|
|
1fc1884017 | ||
|
|
75ce386b44 | ||
|
|
e60fdafdaa | ||
|
|
d541e0da65 | ||
|
|
59a1729a05 | ||
|
|
112ac54a57 | ||
|
|
0cc2de6179 | ||
|
|
28e268bd26 | ||
|
|
7321febe4f | ||
|
|
96d6c1df9f | ||
|
|
cb058f2e4b | ||
|
|
c564bbc0b7 | ||
|
|
b066a17ebe | ||
|
|
277ce0e226 | ||
|
|
65830dd705 | ||
|
|
53127bf844 | ||
|
|
2ea6dd627e | ||
|
|
db26a28bf9 | ||
|
|
6e9ad1048d | ||
|
|
e98b61f2b5 | ||
|
|
4fa1c0bcfb | ||
|
|
e3dd91d45e | ||
|
|
e768e2c100 | ||
|
|
ac24ec1387 | ||
|
|
3a61289f6c | ||
|
|
9f149a7f35 | ||
|
|
70f83b34ef | ||
|
|
8d3953183a | ||
|
|
2812a8c77a | ||
|
|
3af5ceadc1 | ||
|
|
0d9e402d3e | ||
|
|
dede40bc4e | ||
|
|
3a00956144 | ||
|
|
01add8a34a | ||
|
|
a09712d5d2 | ||
|
|
8074e509ba | ||
|
|
af10774aec | ||
|
|
d54c7e090e | ||
|
|
3937f1efb0 | ||
|
|
3e8190831c | ||
|
|
3c2b74a36f | ||
|
|
0558b6c7aa | ||
|
|
774f6df210 | ||
|
|
1e1c0e8f04 | ||
|
|
caf0f9db3e | ||
|
|
da43078eba | ||
|
|
6fae705b43 | ||
|
|
e4f1e05c1d | ||
|
|
4559287d07 | ||
|
|
2d4776586d | ||
|
|
ed4b932530 | ||
|
|
f0f704fc99 | ||
|
|
403c44b1fa | ||
|
|
493f36ecdd | ||
|
|
5d8f8dac35 | ||
|
|
f5dce013ce | ||
|
|
531881f651 | ||
|
|
7de681aa3b | ||
|
|
04ef785eea | ||
|
|
e1cfb91d42 | ||
|
|
72930708ec | ||
|
|
58763fd49f | ||
|
|
a89c875c49 | ||
|
|
e0f598f91c | ||
|
|
a696b6b155 | ||
|
|
d8770133f0 | ||
|
|
5c32372d42 | ||
|
|
4d7c7531d0 | ||
|
|
c99dab0dae | ||
|
|
3dee86c997 | ||
|
|
df75d1ce43 | ||
|
|
2469943c98 | ||
|
|
072b38d326 | ||
|
|
dc81bf5fb5 | ||
|
|
8e7401d2f4 | ||
|
|
6a79e614da | ||
|
|
4287b33796 | ||
|
|
3b37dc2480 | ||
|
|
dec99b0deb | ||
|
|
3840c4e768 | ||
|
|
793b23411a | ||
|
|
fd549c764b | ||
|
|
339a4ddb51 | ||
|
|
3dbad09f72 | ||
|
|
d480f6a0db | ||
|
|
e21ae0d7d8 | ||
|
|
f6d9837b07 | ||
|
|
d5a026d91a | ||
|
|
1d4baca0d9 | ||
|
|
887b04f7f4 | ||
|
|
d4a9ce614b | ||
|
|
db76a15ba5 | ||
|
|
64ea936d7f | ||
|
|
c010855bac | ||
|
|
2f47226f91 | ||
|
|
d26f79a458 | ||
|
|
ce6ff451b0 | ||
|
|
5466f19441 | ||
|
|
0db0ab1b3c | ||
|
|
fd34737330 | ||
|
|
f48f89fbd9 | ||
|
|
7de0a3afa4 | ||
|
|
c5aba94233 | ||
|
|
b7500776fe | ||
|
|
d29ddec34f | ||
|
|
83f71520d2 | ||
|
|
ee15bfa1db | ||
|
|
f2abee3606 | ||
|
|
c6ec416e30 | ||
|
|
9a193e26ec | ||
|
|
2657880ff3 | ||
|
|
497262d23c | ||
|
|
1b745bc505 | ||
|
|
2620714b43 | ||
|
|
4ebf611b91 | ||
|
|
862ae0b969 | ||
|
|
b634dea7ab | ||
|
|
2931be613b | ||
|
|
6d2ecaa15c | ||
|
|
a8c215774b | ||
|
|
0ae2f2a5fd | ||
|
|
9f5a38df60 | ||
|
|
5e30a65689 | ||
|
|
c1de01d594 | ||
|
|
2dd21de678 | ||
|
|
b0c17d1163 | ||
|
|
36d13508d4 | ||
|
|
fdc290c546 | ||
|
|
cd1d42bc9d | ||
|
|
643166a337 | ||
|
|
4c714e10a3 | ||
|
|
b6910b9428 | ||
|
|
4f14b8923f | ||
|
|
1417be626f | ||
|
|
cad9a4f834 | ||
|
|
ca1e2a5a6b | ||
|
|
79e076c3c0 | ||
|
|
7d567c3ac9 | ||
|
|
351965a87b | ||
|
|
d1b867f7b5 | ||
|
|
52c49169b4 | ||
|
|
720c561b75 | ||
|
|
041248e7cc | ||
|
|
3855ba9136 | ||
|
|
4729876714 | ||
|
|
4ae73ba871 | ||
|
|
10b64adb58 | ||
|
|
cf45f28cc0 | ||
|
|
64243e6ec1 | ||
|
|
e186d375dc | ||
|
|
04bc1a7998 | ||
|
|
82ed5d35b7 | ||
|
|
e1998346e1 | ||
|
|
f04d66e10b | ||
|
|
da49dbdd84 | ||
|
|
ac97523275 | ||
|
|
fb97883bef | ||
|
|
415ce36861 | ||
|
|
18395a8dc0 | ||
|
|
2ac1787dae | ||
|
|
62944f3c7d | ||
|
|
f06eb12d10 | ||
|
|
0e58226f3b | ||
|
|
2821c5ac44 | ||
|
|
b0c9bf6c8d | ||
|
|
b87703eb39 | ||
|
|
863038905c | ||
|
|
2eb488359d | ||
|
|
9030d90894 | ||
|
|
473eb628bc | ||
|
|
672611435a | ||
|
|
3c73af7964 | ||
|
|
e8f183b403 | ||
|
|
3313e1f6cc | ||
|
|
9fd12498ed | ||
|
|
49a5937ace | ||
|
|
bf8fa9a504 | ||
|
|
a6405e8935 | ||
|
|
d457bca59a | ||
|
|
8f8a04fdb5 | ||
|
|
a4ce40add4 | ||
|
|
b8347821c4 | ||
|
|
3f97a034c7 | ||
|
|
74949bb049 | ||
|
|
9e7f259d03 | ||
|
|
b8b06e6680 | ||
|
|
928befeea2 | ||
|
|
e171c0aa9b | ||
|
|
2140298af2 | ||
|
|
adece30891 | ||
|
|
012430cfb6 | ||
|
|
0b20a7eef8 | ||
|
|
82102f59ba | ||
|
|
539dae2148 | ||
|
|
d3d7055103 | ||
|
|
ea2c4d96b4 | ||
|
|
9518cdc1e9 | ||
|
|
290fb4380c | ||
|
|
420892d7a9 | ||
|
|
7153a03a5f | ||
|
|
53b5e5c8ee | ||
|
|
d748650691 | ||
|
|
e850823809 | ||
|
|
d19b3aa837 | ||
|
|
534303795a | ||
|
|
d543b4c625 | ||
|
|
4fdb042ad4 | ||
|
|
276039cf35 | ||
|
|
0ef837bc19 | ||
|
|
f6e7ac2e5e | ||
|
|
cf9f6e958c | ||
|
|
c2e1a9216d | ||
|
|
a1b3cfece4 | ||
|
|
b5cf4ca56e | ||
|
|
a071694324 | ||
|
|
3c4b27608e | ||
|
|
493bbadb18 | ||
|
|
df70bb0173 | ||
|
|
78033ea2d3 | ||
|
|
08d985f40c | ||
|
|
376d336525 | ||
|
|
edfa8ed4ea | ||
|
|
09f9b9e625 | ||
|
|
27055ea1b9 | ||
|
|
9fefe4a378 | ||
|
|
c5ac2e2d00 | ||
|
|
75ad38f244 | ||
|
|
1133f02df7 | ||
|
|
ce924349c1 | ||
|
|
24a68b2ad8 | ||
|
|
06521a1b55 | ||
|
|
3594e1886f | ||
|
|
aacf75d414 | ||
|
|
511a235215 | ||
|
|
6f19a3fbae | ||
|
|
c6267c526d | ||
|
|
90cc2a441d | ||
|
|
286fca3935 | ||
|
|
9bfc8c2ff6 | ||
|
|
e3dab66ad1 | ||
|
|
eabda340ef | ||
|
|
d0bbe2a0e8 | ||
|
|
7441e6cf74 | ||
|
|
a87dfe62ad | ||
|
|
02470c5647 | ||
|
|
c7edf914e1 | ||
|
|
f98084bbd3 | ||
|
|
ef538ef9da | ||
|
|
f492d423dd | ||
|
|
abc00ab6ca | ||
|
|
243f613444 | ||
|
|
8fdd18f897 | ||
|
|
822909d046 | ||
|
|
95becc4f6f | ||
|
|
11a281b862 | ||
|
|
b97e1400e6 | ||
|
|
a8c0646d18 | ||
|
|
98175bac4b | ||
|
|
81e65b43bf | ||
|
|
23d63ccb44 | ||
|
|
59342bc10f | ||
|
|
ea81976ee9 | ||
|
|
53088dae65 | ||
|
|
2623d101e7 | ||
|
|
4f7ca3f2d1 | ||
|
|
0411fd1ddc | ||
|
|
eed9664173 | ||
|
|
7410b01cad | ||
|
|
a9a60c4f9c | ||
|
|
3a79bd908a | ||
|
|
573ad560b6 | ||
|
|
e09699a029 | ||
|
|
a6833c62f8 | ||
|
|
3585d21a41 | ||
|
|
f34b2e23cb | ||
|
|
0e38cdc4a9 | ||
|
|
683141d14a | ||
|
|
36fac4efe1 | ||
|
|
ea4a23654f | ||
|
|
cf42496970 | ||
|
|
6db06524b1 | ||
|
|
a4c72238d0 | ||
|
|
ae27a1b343 | ||
|
|
c7f2739dda | ||
|
|
3d7c681ed0 | ||
|
|
0086a51311 | ||
|
|
ea26369f80 | ||
|
|
49dedfbc86 | ||
|
|
2c89688b46 | ||
|
|
d5a0b616e1 | ||
|
|
e0dbf4b691 | ||
|
|
41491843de | ||
|
|
34c5a68635 | ||
|
|
7be5b86618 | ||
|
|
1ea9721e90 | ||
|
|
0ffadafe3c | ||
|
|
a9adf06d98 | ||
|
|
540484f92f | ||
|
|
238f81f621 | ||
|
|
20508c45f2 | ||
|
|
ef58767834 | ||
|
|
0ef1166b0b | ||
|
|
6e3c556d0b | ||
|
|
02f786694e | ||
|
|
4b485ad570 | ||
|
|
3df06e6482 | ||
|
|
c94f481f2a | ||
|
|
41f2133693 | ||
|
|
2872b44b45 | ||
|
|
5c9d96d5a8 | ||
|
|
3d8be2119e | ||
|
|
569522b007 | ||
|
|
dccb8081bc | ||
|
|
df5cf4ff9c | ||
|
|
03ede837e4 | ||
|
|
e6fd4efd08 | ||
|
|
1cd810f8f6 | ||
|
|
ce1c98ec52 | ||
|
|
42a9352f48 | ||
|
|
a7b915299a | ||
|
|
4819584714 | ||
|
|
d58184efa1 | ||
|
|
1f833dcae2 | ||
|
|
c66e8917c8 | ||
|
|
247355f15b | ||
|
|
5112479372 | ||
|
|
5dd5de0d76 | ||
|
|
0339feecda | ||
|
|
2098b0166f | ||
|
|
28d60d8b10 | ||
|
|
a730a482c3 | ||
|
|
bd836d763c | ||
|
|
a7d75c9071 | ||
|
|
fdc045a230 | ||
|
|
faf6ecceda | ||
|
|
3a2b5df05d | ||
|
|
6c4e861eac | ||
|
|
a21a523896 | ||
|
|
4b77ee5c25 | ||
|
|
8badebca26 | ||
|
|
b5388cb3a4 | ||
|
|
4b75865e47 | ||
|
|
9640f5a02b | ||
|
|
881c38e301 | ||
|
|
20b9ead82a | ||
|
|
fb62263871 | ||
|
|
c5f24f6481 | ||
|
|
c2fad1fa90 | ||
|
|
02f3ce74d7 | ||
|
|
489515968c | ||
|
|
76b7dc3820 | ||
|
|
7f23fe3f64 | ||
|
|
e269626982 | ||
|
|
92adb55c7a | ||
|
|
8e01baa49a | ||
|
|
375294a56c | ||
|
|
765c12a2d1 | ||
|
|
5d08b64c23 | ||
|
|
86f260672b | ||
|
|
98f02b62b2 | ||
|
|
44a94b0b50 | ||
|
|
12171e3318 | ||
|
|
cafe1478e6 | ||
|
|
bbc9c0bb47 | ||
|
|
df7967c6f8 | ||
|
|
7c5dca0553 | ||
|
|
b3aa531f4a | ||
|
|
e830176d13 | ||
|
|
23cc9b23e3 | ||
|
|
dbf76874b9 | ||
|
|
cf1395afd8 | ||
|
|
7b2e45692e | ||
|
|
0e2cb5866c | ||
|
|
c44a6433fd | ||
|
|
a66fe6de73 | ||
|
|
026ac59326 | ||
|
|
4e9267eed2 | ||
|
|
0daaf05782 | ||
|
|
9244828618 | ||
|
|
3d1a430b62 | ||
|
|
4f08212415 | ||
|
|
58ff0e74f4 | ||
|
|
61a377cc29 | ||
|
|
a3bf98deff | ||
|
|
083efc265b | ||
|
|
bbb00ac7ef | ||
|
|
78c2c1c2da | ||
|
|
7123784734 | ||
|
|
47ef45ee38 | ||
|
|
ead5322340 | ||
|
|
67c5bc97ce | ||
|
|
5301e98942 | ||
|
|
cece9201bb | ||
|
|
1857882d9e | ||
|
|
e1fda18164 | ||
|
|
977e2a3c35 | ||
|
|
92ecc4d7fd | ||
|
|
a432cec468 | ||
|
|
f27ddea013 | ||
|
|
e2ffcbd3d6 | ||
|
|
e65f1ecffe | ||
|
|
51241c5a95 | ||
|
|
9925b4e3a9 | ||
|
|
cdb1326219 | ||
|
|
d8bd32aee8 | ||
|
|
7b3d2e5cd6 | ||
|
|
58dce57b7e | ||
|
|
c0281b21f0 | ||
|
|
a43ec0189a | ||
|
|
f6d2fe6093 | ||
|
|
d56487e509 | ||
|
|
4763b1da6e | ||
|
|
8eec5c82c2 | ||
|
|
2854aba5e3 | ||
|
|
b1a593d27e | ||
|
|
61d4cb2a6e | ||
|
|
72383a7d7f | ||
|
|
1fc7dc3951 | ||
|
|
8e87f3f969 | ||
|
|
bc90b9a4e1 | ||
|
|
ff02cf8613 | ||
|
|
7361431799 | ||
|
|
bd41582b97 | ||
|
|
d4edf577eb | ||
|
|
12865e3b85 | ||
|
|
f2e725b3c9 | ||
|
|
f1049b4a7a | ||
|
|
fe93e72f0b | ||
|
|
8d1f66cd41 | ||
|
|
06734487ee | ||
|
|
aefe06b296 | ||
|
|
3576e8f784 | ||
|
|
5cf7c12dc9 | ||
|
|
fc418d1195 | ||
|
|
b942cae98e | ||
|
|
3987828294 | ||
|
|
e25a64af9b | ||
|
|
4ce0113395 | ||
|
|
efff69bc49 | ||
|
|
487d504486 | ||
|
|
47e9aa9abb | ||
|
|
4ad3c48f2d | ||
|
|
bfcb3eac49 | ||
|
|
b30e19b23c | ||
|
|
3f14491e31 | ||
|
|
798cd5b658 | ||
|
|
f24ea5e56c | ||
|
|
216d4d63bc | ||
|
|
018770e894 | ||
|
|
2e2bdb0d0d | ||
|
|
3ad683a370 | ||
|
|
ad21e86f06 | ||
|
|
4e80d5d5fd | ||
|
|
f7dc21d24d | ||
|
|
5e93134ea4 | ||
|
|
8baf544040 | ||
|
|
ec31b93447 | ||
|
|
aefe16a6e2 | ||
|
|
9d26327ae4 | ||
|
|
f767ef2f19 | ||
|
|
3b46553f47 | ||
|
|
b3192b94b4 | ||
|
|
878256306c | ||
|
|
87bcbeda37 | ||
|
|
7465410c5a | ||
|
|
d987c9f5cd | ||
|
|
bb8092a5e4 | ||
|
|
f10d1432f3 | ||
|
|
1f8eae0071 | ||
|
|
9c5e3750c4 | ||
|
|
3c1157fe5d | ||
|
|
de0b54cfb6 | ||
|
|
7fc6d7c5bf | ||
|
|
bbd764d249 | ||
|
|
4c53da5be1 | ||
|
|
eba68ac2ff | ||
|
|
0742e5fbbd | ||
|
|
8bbc35560f | ||
|
|
0ea3215e7a | ||
|
|
d5a7769b4f | ||
|
|
ba372e106f | ||
|
|
f6566838f6 | ||
|
|
ee3e8c46dc | ||
|
|
4afe912f84 | ||
|
|
ac392561c1 | ||
|
|
a1bdb8f99d | ||
|
|
5e52acf63a | ||
|
|
d6930e89ef | ||
|
|
be594918a9 | ||
|
|
d81fb1d17f | ||
|
|
66e3dc8218 | ||
|
|
5a1b069b73 | ||
|
|
71ca9e8c4c | ||
|
|
9078ce5976 | ||
|
|
91b45925e9 | ||
|
|
45dda0c9fd | ||
|
|
79fc4f2d47 | ||
|
|
0d6fee4053 | ||
|
|
1bb34cb165 | ||
|
|
fdc37c037f | ||
|
|
7490663d9e | ||
|
|
0b4fa9472d | ||
|
|
203ee9f1c2 | ||
|
|
3b97209663 | ||
|
|
2929c46d68 | ||
|
|
f640dbb34e | ||
|
|
315c455314 | ||
|
|
9295fa49e4 | ||
|
|
8f2059a4c4 | ||
|
|
129fea0a76 | ||
|
|
dd1633f453 | ||
|
|
a9ff077046 | ||
|
|
2949a7e86a | ||
|
|
b9699bb93e | ||
|
|
1f9bd897a7 | ||
|
|
c1445b3859 | ||
|
|
44b3082234 | ||
|
|
3442e17f83 | ||
|
|
5d3f97819b | ||
|
|
9218462477 | ||
|
|
4c802a6ff7 | ||
|
|
35f4681929 | ||
|
|
943b73b287 | ||
|
|
15da5fc702 | ||
|
|
717e8c3be5 | ||
|
|
d6b989c837 | ||
|
|
6703992cf3 | ||
|
|
412e804b93 | ||
|
|
b162748e26 | ||
|
|
b6d65a434b | ||
|
|
78922d8433 | ||
|
|
14474170f0 | ||
|
|
23c6950692 | ||
|
|
55ba3b11cb | ||
|
|
67dc65a67d | ||
|
|
70ce4eef7e | ||
|
|
82935c585a | ||
|
|
60fc24ce2b | ||
|
|
b3c1d94e75 | ||
|
|
2dba81e460 | ||
|
|
99f92beac9 | ||
|
|
f06ca50df9 | ||
|
|
2485efa5f3 | ||
|
|
2e1e295ba4 | ||
|
|
ec3e14c8f6 | ||
|
|
9841ce1107 | ||
|
|
5c56f9008c | ||
|
|
6009e20aa4 | ||
|
|
850ef84b0b | ||
|
|
0143ced07c | ||
|
|
ce7f2e799e | ||
|
|
f030333766 | ||
|
|
1039320a9c | ||
|
|
d8526a388d | ||
|
|
06a78e1aff | ||
|
|
d6bbdb90b9 | ||
|
|
2e34d9ffd4 | ||
|
|
8269a3a235 | ||
|
|
c4b41734a9 | ||
|
|
23569ad5e7 | ||
|
|
d390b02be5 | ||
|
|
fa71f846ae | ||
|
|
8f3d6c575d | ||
|
|
d424a885bd | ||
|
|
f2483538d2 | ||
|
|
15ceb61d96 | ||
|
|
c5f5b4a1f0 | ||
|
|
c488e1d45c | ||
|
|
6f727d3a39 | ||
|
|
dfde9ba4b8 | ||
|
|
1571981b57 | ||
|
|
e20fb95a43 | ||
|
|
3421f5bc18 | ||
|
|
88968af20b | ||
|
|
42e0c17de7 | ||
|
|
4cbbaec833 | ||
|
|
180e018a36 | ||
|
|
113358fa50 | ||
|
|
37d65a6296 | ||
|
|
ecd0646f41 | ||
|
|
eb6cc1fa77 | ||
|
|
6dffdaa471 | ||
|
|
4dab89f7e6 | ||
|
|
16ac2c70ab | ||
|
|
e7d9aaec4e | ||
|
|
2297b2d3a1 | ||
|
|
de8d9d88ff | ||
|
|
e2e9725812 | ||
|
|
60e5c488ac | ||
|
|
146a72b331 | ||
|
|
65c351f50e | ||
|
|
18c8b41f3f | ||
|
|
f28b68661d | ||
|
|
1751bbaea6 | ||
|
|
b57a734625 | ||
|
|
00bbca275c | ||
|
|
e2271f9a03 | ||
|
|
3eff3d2704 | ||
|
|
bc517cecf3 | ||
|
|
2210528581 | ||
|
|
e458c17f4f | ||
|
|
3a69609ffd | ||
|
|
6641ca13a1 | ||
|
|
6d1857c253 | ||
|
|
29ec7d6bf3 | ||
|
|
fd45b7f93f | ||
|
|
3fb591714a | ||
|
|
c5e0577aee | ||
|
|
95ca400826 | ||
|
|
5125bb840d | ||
|
|
89fffbb4da | ||
|
|
a190fb447d | ||
|
|
06f91ed4b9 | ||
|
|
187ae4b938 | ||
|
|
a1abc46138 | ||
|
|
5c243b6c4c | ||
|
|
4f28f26626 | ||
|
|
0907fbf906 | ||
|
|
4a27ba8bce | ||
|
|
f2177e1254 | ||
|
|
be4ca80842 | ||
|
|
18001a9d2d | ||
|
|
7d2ce304c4 | ||
|
|
24538da200 | ||
|
|
0a2f6caba0 | ||
|
|
eb6af955c3 | ||
|
|
dbfab0a535 | ||
|
|
d2a1b9f18e | ||
|
|
80a3f74852 | ||
|
|
e934065cf8 | ||
|
|
7ef0287467 | ||
|
|
5b42cb37c7 | ||
|
|
a5d7f1093e | ||
|
|
01c095cac7 | ||
|
|
fa654473c9 | ||
|
|
1f0df70ac3 | ||
|
|
c5024ddea4 | ||
|
|
2e0c7418e4 | ||
|
|
a598dc4d3f | ||
|
|
77077fb5f4 | ||
|
|
84f371ca51 | ||
|
|
dd92f7004d | ||
|
|
adea891229 | ||
|
|
c4f060413e | ||
|
|
29f2bce64d | ||
|
|
5915d3834d | ||
|
|
8f7ec80666 | ||
|
|
0a6d606342 | ||
|
|
24882e4ce5 | ||
|
|
595fcef9bb | ||
|
|
98fd46549c | ||
|
|
45ecb72c16 | ||
|
|
b5aadd0899 | ||
|
|
acd61f14fd | ||
|
|
613911dc10 | ||
|
|
24d5be3e14 | ||
|
|
cd4e406dc9 | ||
|
|
6671861e54 | ||
|
|
bc2b8cca52 | ||
|
|
0aa7b4c3e3 | ||
|
|
9e28c62730 | ||
|
|
5806cddfd3 | ||
|
|
6828ce30f5 | ||
|
|
8ea7a88281 | ||
|
|
a206d9405b | ||
|
|
4a0c6995ed | ||
|
|
396e923f22 | ||
|
|
cefc287986 | ||
|
|
fe24e078a4 | ||
|
|
b2beb34e9a | ||
|
|
087cee5425 | ||
|
|
91132a42c8 | ||
|
|
9bf0bf7a39 | ||
|
|
4f6c3afa3e | ||
|
|
f337bb6458 | ||
|
|
e99786e726 | ||
|
|
819dbc5285 | ||
|
|
02efddca75 | ||
|
|
809a1ff357 | ||
|
|
952a299914 | ||
|
|
67af4137af | ||
|
|
9a88084edc | ||
|
|
95bac8b612 | ||
|
|
7894e16e43 | ||
|
|
0c19c3cde1 | ||
|
|
b2188abb5d | ||
|
|
8ace57bbef | ||
|
|
8b766894b7 | ||
|
|
5ecb00fe0e | ||
|
|
04453f5f24 | ||
|
|
dd54c26f9a | ||
|
|
fa3abfad2e | ||
|
|
28948fc7b2 | ||
|
|
792a4e1445 | ||
|
|
dc7efab0ab | ||
|
|
899547dcc8 | ||
|
|
728390b6e5 | ||
|
|
ffb7f94e2a | ||
|
|
e8517e748d | ||
|
|
02fde10c12 | ||
|
|
b0c60f1c08 | ||
|
|
9ccb83be57 | ||
|
|
424592b873 | ||
|
|
d772eb6add | ||
|
|
a9651883cd | ||
|
|
ff67f8c791 | ||
|
|
c690a3d58d | ||
|
|
3e7958619a | ||
|
|
54c1ca0786 | ||
|
|
241fbe0581 | ||
|
|
5ff5a5c1ae | ||
|
|
a60c373caf | ||
|
|
8dcf0d0c72 | ||
|
|
ce97fd5901 | ||
|
|
e71be41e72 | ||
|
|
ee49ce3165 | ||
|
|
b21e0baa47 | ||
|
|
444e16fdd2 | ||
|
|
5e98ac943b | ||
|
|
116d192584 | ||
|
|
3ec14a8844 | ||
|
|
bdd5bc90c4 | ||
|
|
e096462005 | ||
|
|
24ae19b8e5 | ||
|
|
61685714c6 | ||
|
|
53310d1ea0 | ||
|
|
12e30bf969 | ||
|
|
264cc7e2fe | ||
|
|
14e047e7c4 | ||
|
|
f5bcec66e5 | ||
|
|
9dd2365485 | ||
|
|
bb45ed3fce | ||
|
|
a951332367 | ||
|
|
f8578ecc28 | ||
|
|
8c0bfb030a | ||
|
|
04043d267f | ||
|
|
7e629ef30a | ||
|
|
fab2979b87 | ||
|
|
6c9660aee8 | ||
|
|
fdcb084df6 | ||
|
|
5fb7b24011 | ||
|
|
1fa467aa9f | ||
|
|
0fc6b46c4c | ||
|
|
e18b4b2063 | ||
|
|
f4b2589149 | ||
|
|
d99eb3c970 | ||
|
|
3fa0e7c1ad | ||
|
|
92e289cb3d | ||
|
|
0e4f11afc5 | ||
|
|
49d5a16db3 | ||
|
|
33d7ea6569 | ||
|
|
b55ef724f6 | ||
|
|
6057ecc83a | ||
|
|
0150df0b05 | ||
|
|
df8e951324 | ||
|
|
e2d9ae379b | ||
|
|
a2684a6a12 | ||
|
|
b8641d7d5e | ||
|
|
14b632f1a5 | ||
|
|
7470af24a9 | ||
|
|
b45e226db9 | ||
|
|
e1e21f30fe | ||
|
|
29e4b21a8b | ||
|
|
19e5ed6313 | ||
|
|
a91cd72829 | ||
|
|
56530a1f24 | ||
|
|
daabfcaf91 | ||
|
|
97400df68d | ||
|
|
79ffa53ace | ||
|
|
25e326c55c | ||
|
|
5dfc367420 | ||
|
|
e1deef327f | ||
|
|
7747cf07e7 | ||
|
|
5fc5fbc8e7 | ||
|
|
8470763c31 | ||
|
|
546357662f | ||
|
|
5f8de9fd2c | ||
|
|
1264ffa4b4 | ||
|
|
35421403cf | ||
|
|
13b8283666 | ||
|
|
1016dd4a40 | ||
|
|
88516acdaa | ||
|
|
ea0fa20579 | ||
|
|
778d2af36e | ||
|
|
934f6aeada | ||
|
|
72463f414c | ||
|
|
a67ce9db0e | ||
|
|
55854907a2 | ||
|
|
304a6f7a33 | ||
|
|
41234c4f97 | ||
|
|
40b8aab7d4 | ||
|
|
44522b11bc | ||
|
|
3c879e868a | ||
|
|
c64e019f29 | ||
|
|
afe6bdbfb3 | ||
|
|
73e373527f | ||
|
|
d8d5b14e66 | ||
|
|
70ad78d234 | ||
|
|
57f6e0c1a5 | ||
|
|
d455d2b9bf | ||
|
|
af4222d7d2 | ||
|
|
e15bf5105c | ||
|
|
c3d47f02d3 | ||
|
|
4c8456a86d | ||
|
|
29300ea9e1 | ||
|
|
cdac253556 | ||
|
|
7001e38c30 | ||
|
|
6c90de1974 | ||
|
|
17fc9e5a91 | ||
|
|
cc438b4411 | ||
|
|
d8d5a15321 | ||
|
|
9be1494357 | ||
|
|
2c07858bd3 | ||
|
|
74e50359b5 | ||
|
|
31eb477a0e | ||
|
|
142d097ef0 | ||
|
|
c69dfba6bb | ||
|
|
c1d4cea638 | ||
|
|
245b0c58c6 | ||
|
|
9042477415 | ||
|
|
d551dff4cf | ||
|
|
2ec89e68ba | ||
|
|
ff6dcee84c | ||
|
|
8db15d143b | ||
|
|
a4c2ec0440 | ||
|
|
cd2fe40a59 | ||
|
|
7a0707342b | ||
|
|
624ccd12fc | ||
|
|
a79e1d65a7 | ||
|
|
0721aae353 | ||
|
|
abac5bdf48 | ||
|
|
b463c56c93 | ||
|
|
2fb589b131 | ||
|
|
b53a585756 | ||
|
|
6b55c54af9 | ||
|
|
86d3ec5cee | ||
|
|
d26fa9b04b | ||
|
|
0467637500 | ||
|
|
1a4db03d5e | ||
|
|
28bcb7e491 | ||
|
|
c0c476e53d | ||
|
|
26aa2761c0 | ||
|
|
cf4bd29d44 | ||
|
|
12459e8c8b | ||
|
|
43d49d17d0 | ||
|
|
b344f95e97 | ||
|
|
6bfb3fab3c | ||
|
|
c571f6b4fb | ||
|
|
f684e821d4 | ||
|
|
06f177534d | ||
|
|
a6c8303839 | ||
|
|
ec84d0f372 | ||
|
|
026a8aa9a1 | ||
|
|
b4e4727887 | ||
|
|
14e3038571 | ||
|
|
9ae171f57c | ||
|
|
b9f55997ae | ||
|
|
ecd0ae1b16 | ||
|
|
98278eff2a | ||
|
|
f0988b52d0 | ||
|
|
4232f1a599 | ||
|
|
8462120c0a | ||
|
|
a79d4cb803 | ||
|
|
8c35f0a4ce | ||
|
|
232d266fb5 | ||
|
|
db0f8d33e1 | ||
|
|
f99fc16e14 | ||
|
|
4bbb5fadb3 | ||
|
|
488673ea9a | ||
|
|
060787a5db | ||
|
|
8a43f4902d | ||
|
|
0e56abd0f9 | ||
|
|
2e06bb6561 | ||
|
|
3d3ad553a6 | ||
|
|
a821c886b3 | ||
|
|
b323069419 | ||
|
|
992b41b82a | ||
|
|
3be7803d30 | ||
|
|
80ea2bb51d | ||
|
|
764ada3a17 | ||
|
|
570cd3d810 | ||
|
|
197f130593 | ||
|
|
e3d006f867 | ||
|
|
ae128f587d | ||
|
|
ff36a87551 | ||
|
|
14f1002680 | ||
|
|
89b8c9f198 | ||
|
|
c7cb2f26ff | ||
|
|
0849501ef5 | ||
|
|
ced7490df6 | ||
|
|
d5cb31922e | ||
|
|
d9c72e8f58 | ||
|
|
a50dc97332 | ||
|
|
c4909ac657 | ||
|
|
e1adf6766b | ||
|
|
772c68ff62 | ||
|
|
952171337c | ||
|
|
660cd61da7 | ||
|
|
cf66c2a191 | ||
|
|
9a85c45bf7 | ||
|
|
7ab0e9c722 | ||
|
|
4079fb2326 | ||
|
|
6bf05083bd | ||
|
|
a9061dc299 | ||
|
|
161ebc1166 | ||
|
|
6345b0c7de | ||
|
|
6ad736346f | ||
|
|
4792bc8c3a | ||
|
|
6c62617fd0 | ||
|
|
67feb5bab7 | ||
|
|
814d7d69fa | ||
|
|
35e518cbc2 | ||
|
|
99a7cfceac | ||
|
|
1ebf75e7d0 | ||
|
|
b3fe15dc41 | ||
|
|
67d4510e9b | ||
|
|
7ad546504c | ||
|
|
d9b528351c | ||
|
|
4f003cdb60 | ||
|
|
f04cc0c9e6 | ||
|
|
1fad357f26 | ||
|
|
43e1a2c991 | ||
|
|
2e11c3c104 | ||
|
|
b7e71a1c3c | ||
|
|
c5d32c58f9 | ||
|
|
98611888af | ||
|
|
e0aea4a5f5 | ||
|
|
1f2c5bfed7 | ||
|
|
04c068e514 | ||
|
|
555dc98f5b | ||
|
|
61763f278f | ||
|
|
b6ef010595 | ||
|
|
5de313272f | ||
|
|
d0251642bc | ||
|
|
1ca91b9e0c | ||
|
|
9a63bd5d6f | ||
|
|
a7900205e5 | ||
|
|
dbb22f506d | ||
|
|
3cf4f337e7 | ||
|
|
22baaecd14 | ||
|
|
db182f4612 | ||
|
|
d33a62ffa6 | ||
|
|
83ddb3f99f | ||
|
|
35ab335cb2 | ||
|
|
395329fb6c | ||
|
|
1efeea3884 | ||
|
|
54aaac9964 | ||
|
|
071adeeba4 | ||
|
|
6358b22289 | ||
|
|
edeac7e6a2 | ||
|
|
62944cdf6f | ||
|
|
8e8e0201f0 | ||
|
|
0820549b4c | ||
|
|
c99754391f | ||
|
|
271d55506a | ||
|
|
bac71c7670 | ||
|
|
0683e14777 | ||
|
|
7d2d06dbcd | ||
|
|
038126d59c | ||
|
|
f29583d81d | ||
|
|
a7153a082f | ||
|
|
079e2f3008 | ||
|
|
c6e190118f | ||
|
|
ea2faa0607 | ||
|
|
4395818e72 | ||
|
|
dde7e6781d | ||
|
|
300e7e125e | ||
|
|
8dfd71ccc6 | ||
|
|
084383a644 | ||
|
|
1ebc8034b4 | ||
|
|
81ac8e2be9 | ||
|
|
c44900bf8f | ||
|
|
ea8a499769 | ||
|
|
7f91e014a0 | ||
|
|
6d6bdebb57 | ||
|
|
1980df89c0 | ||
|
|
c42a73d572 | ||
|
|
8a50d8b6a9 | ||
|
|
75403c0ec1 | ||
|
|
726c31f8de | ||
|
|
dbec3ad33f | ||
|
|
3cb974de49 | ||
|
|
75b220dbc4 | ||
|
|
cae0f15245 | ||
|
|
46a36a10a5 | ||
|
|
2467200a3b | ||
|
|
181f098958 | ||
|
|
3e65c3af5e | ||
|
|
c04bdc48aa | ||
|
|
894eb3ab79 | ||
|
|
58cee899b0 | ||
|
|
1091cc23af | ||
|
|
233d8e3ebf | ||
|
|
ec1a7b4b40 | ||
|
|
ffce61da4b | ||
|
|
909b2e2713 | ||
|
|
70a0e256b0 | ||
|
|
f10a3d6232 | ||
|
|
cbdd04e506 | ||
|
|
bf4b08efd2 | ||
|
|
2980f5d3ce | ||
|
|
677c2e87b5 | ||
|
|
48167f53eb | ||
|
|
9e5a0f0e61 | ||
|
|
abefdd506c | ||
|
|
88bd2fc9e2 | ||
|
|
aa0db81300 | ||
|
|
a12fb177e2 | ||
|
|
2d77ad8aab | ||
|
|
9486eb2fde |
13
.github/workflows/tests.yaml
vendored
13
.github/workflows/tests.yaml
vendored
@@ -9,9 +9,6 @@ jobs:
|
|||||||
- name: "Centos 8"
|
- name: "Centos 8"
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
dockerfile: centos8
|
dockerfile: centos8
|
||||||
- name: "Fedora 31"
|
|
||||||
runner: ubuntu-latest
|
|
||||||
dockerfile: fedora31
|
|
||||||
- name: "Fedora 32"
|
- name: "Fedora 32"
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
dockerfile: fedora32
|
dockerfile: fedora32
|
||||||
@@ -21,6 +18,9 @@ jobs:
|
|||||||
- name: "Fedora 34"
|
- name: "Fedora 34"
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
dockerfile: fedora34
|
dockerfile: fedora34
|
||||||
|
- name: "Fedora 35"
|
||||||
|
runner: ubuntu-latest
|
||||||
|
dockerfile: fedora35
|
||||||
- name: "Debian Testing"
|
- name: "Debian Testing"
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
dockerfile: debiantesting
|
dockerfile: debiantesting
|
||||||
@@ -33,9 +33,12 @@ jobs:
|
|||||||
- name: "Ubuntu 21.04"
|
- name: "Ubuntu 21.04"
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
dockerfile: ubuntu2104
|
dockerfile: ubuntu2104
|
||||||
- name: "OpenSUSE 15.0"
|
- name: "Ubuntu 21.10"
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
dockerfile: opensuse1500
|
dockerfile: ubuntu2110
|
||||||
|
- name: "OpenSUSE 15"
|
||||||
|
runner: ubuntu-latest
|
||||||
|
dockerfile: opensuse15
|
||||||
- name: "Archlinux Base (Rolling)"
|
- name: "Archlinux Base (Rolling)"
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
dockerfile: arch
|
dockerfile: arch
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ set (HAVE_CMAKE true)
|
|||||||
project (task)
|
project (task)
|
||||||
include (CXXSniffer)
|
include (CXXSniffer)
|
||||||
|
|
||||||
set (PROJECT_VERSION "2.6.0")
|
set (PROJECT_VERSION "2.6.2")
|
||||||
|
|
||||||
OPTION (ENABLE_WASM "Enable 'wasm' support" OFF)
|
OPTION (ENABLE_WASM "Enable 'wasm' support" OFF)
|
||||||
|
|
||||||
|
|||||||
48
ChangeLog
48
ChangeLog
@@ -1,4 +1,45 @@
|
|||||||
2.6.0 () -
|
------ current release ---------------------------
|
||||||
|
2.6.2 -
|
||||||
|
|
||||||
|
- TW #502 Sequence of IDs doesn't work with attribute "depends"
|
||||||
|
Thanks to Andreas Kalex and Reg for reporting.
|
||||||
|
- TW #2648 xdg-open is not available on Mac OS-X
|
||||||
|
Thanks to chapterjson for reporting.
|
||||||
|
- TW #2655 The bulk removal of depends: and tags: is ignored
|
||||||
|
Thanks to angelus2014 for reporting.
|
||||||
|
- TW #2664 Tag exclusion should be detected as invalid write context
|
||||||
|
Thanks to bentwitthold for reporting.
|
||||||
|
- TW #2671 The value of soww named date is incorrect
|
||||||
|
Thanks to Lennart Kill for reporting.
|
||||||
|
- TW #2689 Corruption of the depends attribute upon syncing with taskd 1.1.0
|
||||||
|
Thanks to Klaus Ethgen for reporting, Dusting J. Mitchell for
|
||||||
|
contributing.
|
||||||
|
- TW #2707 Assigning dependencies via ID ranges
|
||||||
|
Thanks to jaker-dotcom for reporting.
|
||||||
|
- TW #2748 Recurring report does not include parent tasks
|
||||||
|
Thanks to Klaus Ethgen for reporting.
|
||||||
|
|
||||||
|
2.6.1 (2021-10-19) - a696b6b155f9c8af87a6a496c0d298c58e6fe369
|
||||||
|
|
||||||
|
- TW #2619 Fish autocompletion fails when completing tag removal
|
||||||
|
Thanks to Alexandre Provencio for reporting, Tin Lai and Alexandre
|
||||||
|
Provencio for contributing.
|
||||||
|
- TW #2620 Old-style context definition should only be interpreted as read
|
||||||
|
context.
|
||||||
|
Thanks to bongoman and Tom Dörr for reporting.
|
||||||
|
- TW #2622 Tags and dependencies appear as orphaned UDAs.
|
||||||
|
Thanks to Scott Mcdermott for reporting.
|
||||||
|
- TW #2626 Waiting report lists deleted and/or completed tasks.
|
||||||
|
Thanks to Don Harper for reporting.
|
||||||
|
- TW #2629 New-style context definition should take precedence over old-style
|
||||||
|
even if the new-style is an empty string.
|
||||||
|
Thanks to Denis Kasak for reporting.
|
||||||
|
- TW #2632 Cannot build on Cygwin
|
||||||
|
Thanks to Michael Esemplare for contributing.
|
||||||
|
- TW #2639 Unable to use ranges for some tasks with IDs above 1000.
|
||||||
|
Thanks to Manuel Haussmann for reporting.
|
||||||
|
|
||||||
|
2.6.0 (2021-10-03) - 8174287f917a3b24c19a6601ba36fca9bdaa78c9
|
||||||
|
|
||||||
- TW #1654 "Due" parsing behaviour seems inconsistent
|
- TW #1654 "Due" parsing behaviour seems inconsistent
|
||||||
Thanks to Jim B for reporting.
|
Thanks to Jim B for reporting.
|
||||||
@@ -134,16 +175,13 @@
|
|||||||
Thanks to bharatvaj for contributing.
|
Thanks to bharatvaj for contributing.
|
||||||
- TW #2581 Config entry with a trailing comment cannot be modified
|
- TW #2581 Config entry with a trailing comment cannot be modified
|
||||||
|
|
||||||
|
------ old releases ------------------------------
|
||||||
------ current release ---------------------------
|
|
||||||
|
|
||||||
2.5.3 (2021-01-05) - 2f47226f91f0b02f7617912175274d9eed85924f
|
2.5.3 (2021-01-05) - 2f47226f91f0b02f7617912175274d9eed85924f
|
||||||
|
|
||||||
- #2375 task hangs then dies when certain tasks are present in a report
|
- #2375 task hangs then dies when certain tasks are present in a report
|
||||||
Thanks to Max Rossmannek, Tomáš Janoušek and Chad Phillips.
|
Thanks to Max Rossmannek, Tomáš Janoušek and Chad Phillips.
|
||||||
|
|
||||||
------ old releases ------------------------------
|
|
||||||
|
|
||||||
2.5.2 (2020-12-05) - b0c17d11639dc6e783befd89c8508f2abb9b4287
|
2.5.2 (2020-12-05) - b0c17d11639dc6e783befd89c8508f2abb9b4287
|
||||||
|
|
||||||
- TD-64 sync conflict deleted all annotations of the task
|
- TD-64 sync conflict deleted all annotations of the task
|
||||||
|
|||||||
12
DEVELOPER.md
12
DEVELOPER.md
@@ -11,7 +11,7 @@
|
|||||||
```
|
```
|
||||||
$ git clone --recursive https://github.com/GothenburgBitFactory/taskwarrior taskwarrior.git
|
$ git clone --recursive https://github.com/GothenburgBitFactory/taskwarrior taskwarrior.git
|
||||||
$ cd taskwarrior.git
|
$ cd taskwarrior.git
|
||||||
$ git checkout 2.6.0 # Latest dev branch
|
$ git checkout develop # Latest dev branch
|
||||||
$ git submodule init # This is now done by cmake as a test
|
$ git submodule init # This is now done by cmake as a test
|
||||||
$ git submodule update # Update the libhsared.git submodule
|
$ git submodule update # Update the libhsared.git submodule
|
||||||
$ cmake -DCMAKE_BUILD_TYPE=debug . # debug or release. Default: neither
|
$ cmake -DCMAKE_BUILD_TYPE=debug . # debug or release. Default: neither
|
||||||
@@ -144,13 +144,3 @@
|
|||||||
is possible that a patch may be rejected because it conflicts in some way with
|
is possible that a patch may be rejected because it conflicts in some way with
|
||||||
plans or upcoming changes. Check with us first, before sinking time and effort
|
plans or upcoming changes. Check with us first, before sinking time and effort
|
||||||
into a patch.
|
into a patch.
|
||||||
|
|
||||||
# Current Code Base Condition
|
|
||||||
|
|
||||||
**'master' branch**:
|
|
||||||
* 2.5.3 Current release, locked.
|
|
||||||
|
|
||||||
**'2.6.0' branch**:
|
|
||||||
* Current development branch no plans yet.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|||||||
4
NEWS
4
NEWS
@@ -39,8 +39,8 @@ New Features in Taskwarrior 2.6.0
|
|||||||
whole units like days, e.g. 'add test due:2021-07-17' would not match
|
whole units like days, e.g. 'add test due:2021-07-17' would not match
|
||||||
'due.before:tomorrow' (on the 16th), but would match 'due.by:tomorrow'.
|
'due.before:tomorrow' (on the 16th), but would match 'due.by:tomorrow'.
|
||||||
- Waiting is now an entirely "virtual" concept, based on a task's
|
- Waiting is now an entirely "virtual" concept, based on a task's
|
||||||
'wait' property and the current time. Task is consiered "waiting" if its
|
'wait' property and the current time. Task is considered "waiting" if its
|
||||||
wait attribute is in the future. TaskWarrior no longer explicitly
|
wait attribute is in the future. TaskWarrior no longer explicitly
|
||||||
"unwaits" a task (the wait attribute is not removed once its value is in
|
"unwaits" a task (the wait attribute is not removed once its value is in
|
||||||
the past), so the "unwait' verbosity token is no longer available.
|
the past), so the "unwait' verbosity token is no longer available.
|
||||||
This allows for filtering for tasks that were waiting in the past
|
This allows for filtering for tasks that were waiting in the past
|
||||||
|
|||||||
25
README.md
25
README.md
@@ -1,10 +1,9 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="https://avatars.githubusercontent.com/u/36100920?s=200&u=24da05914c20c4ccfe8485310f7b83049407fa9a&v=4"></br>
|
<img src="https://avatars.githubusercontent.com/u/36100920?s=200&u=24da05914c20c4ccfe8485310f7b83049407fa9a&v=4"></br>
|
||||||
|
|
||||||
[](https://github.com/GothenburgBitFactory/taskwarrior/actions)
|
[](https://github.com/GothenburgBitFactory/taskwarrior/actions)
|
||||||
[](https://github.com/GothenburgBitFactory/taskwarrior/releases/latest)
|
[](https://github.com/GothenburgBitFactory/taskwarrior/releases/latest)
|
||||||
[](https://github.com/GothenburgBitFactory/taskwarrior/releases/latest)
|
[](https://github.com/GothenburgBitFactory/taskwarrior/releases/latest)
|
||||||

|
|
||||||
[](https://github.com/sponsors/GothenburgBitFactory/)
|
[](https://github.com/sponsors/GothenburgBitFactory/)
|
||||||
</br>
|
</br>
|
||||||
[](https://twitter.com/taskwarrior)
|
[](https://twitter.com/taskwarrior)
|
||||||
@@ -64,13 +63,15 @@ For code contributions, please use pull requests, or alternately send your code
|
|||||||
|
|
||||||
We use the following branching model:
|
We use the following branching model:
|
||||||
|
|
||||||
* `master` is the stable branch. Building from here is the same as building
|
* `stable` is a branch containing the content of the latest release. Building
|
||||||
from the latest tarball, or installing a binary package. No development is
|
from here is the same as building from the latest tarball, or installing a
|
||||||
done on the `master` branch.
|
binary package. No development is done on the `stable` branch.
|
||||||
|
|
||||||
* `2.6.0` is the current development branch. All work is done here, and upon
|
* `develop` is the current development branch. All work is done here, and upon
|
||||||
release it will be merged to `master`. This development branch is not stable,
|
release it will be merged to `stable`. While development branch is not
|
||||||
and should be treated accordingly. Make backups.
|
stable, we utilize CI to ensure we're at least not merging improvements that
|
||||||
|
break existing tests, and hence should be relatively safe. We still recommend
|
||||||
|
making backups when using the development branch.
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
@@ -85,13 +86,13 @@ There are many binary packages available, but to install from source requires:
|
|||||||
|
|
||||||
Download the tarball, and expand it:
|
Download the tarball, and expand it:
|
||||||
|
|
||||||
$ curl -O https://taskwarrior.org/download/task-2.6.0.tar.gz
|
$ curl -O https://taskwarrior.org/download/task-2.6.2.tar.gz
|
||||||
$ tar xzf task-2.6.0.tar.gz
|
$ tar xzf task-2.6.2.tar.gz
|
||||||
$ cd task-2.6.0
|
$ cd task-2.6.2
|
||||||
|
|
||||||
Or clone this repository:
|
Or clone this repository:
|
||||||
|
|
||||||
$ git clone --recursive -b 2.6.0 https://github.com/GothenburgBitFactory/taskwarrior.git
|
$ git clone --recursive -b stable https://github.com/GothenburgBitFactory/taskwarrior.git
|
||||||
$ cd taskwarrior
|
$ cd taskwarrior
|
||||||
|
|
||||||
Then build:
|
Then build:
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "GNU")
|
|||||||
set (GNUHURD true)
|
set (GNUHURD true)
|
||||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN")
|
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN")
|
||||||
set (CYGWIN true)
|
set (CYGWIN true)
|
||||||
|
set (_CXX14_FLAGS "-std=gnu++17")
|
||||||
else (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
else (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
set (UNKNOWN true)
|
set (UNKNOWN true)
|
||||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
|
|||||||
@@ -16,14 +16,6 @@ services:
|
|||||||
security_opt:
|
security_opt:
|
||||||
- label=type:container_runtime_t
|
- label=type:container_runtime_t
|
||||||
tty: true
|
tty: true
|
||||||
test-fedora31:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: test/docker/fedora31
|
|
||||||
network_mode: "host"
|
|
||||||
security_opt:
|
|
||||||
- label=type:container_runtime_t
|
|
||||||
tty: true
|
|
||||||
test-fedora32:
|
test-fedora32:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
@@ -48,6 +40,14 @@ services:
|
|||||||
security_opt:
|
security_opt:
|
||||||
- label=type:container_runtime_t
|
- label=type:container_runtime_t
|
||||||
tty: true
|
tty: true
|
||||||
|
test-fedora35:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: test/docker/fedora35
|
||||||
|
network_mode: "host"
|
||||||
|
security_opt:
|
||||||
|
- label=type:container_runtime_t
|
||||||
|
tty: true
|
||||||
test-ubuntu1804:
|
test-ubuntu1804:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
@@ -72,6 +72,14 @@ services:
|
|||||||
security_opt:
|
security_opt:
|
||||||
- label=type:container_runtime_t
|
- label=type:container_runtime_t
|
||||||
tty: true
|
tty: true
|
||||||
|
test-ubuntu2110:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: test/docker/ubuntu2110
|
||||||
|
network_mode: "host"
|
||||||
|
security_opt:
|
||||||
|
- label=type:container_runtime_t
|
||||||
|
tty: true
|
||||||
test-debianstable:
|
test-debianstable:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
@@ -96,10 +104,10 @@ services:
|
|||||||
security_opt:
|
security_opt:
|
||||||
- label=type:container_runtime_t
|
- label=type:container_runtime_t
|
||||||
tty: true
|
tty: true
|
||||||
test-opensuse1500:
|
test-opensuse15:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: test/docker/opensuse1500
|
dockerfile: test/docker/opensuse15
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
security_opt:
|
security_opt:
|
||||||
- label=type:container_runtime_t
|
- label=type:container_runtime_t
|
||||||
|
|||||||
1
index.html
Normal file
1
index.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Taskwarrior Docs
|
||||||
@@ -107,7 +107,7 @@ function __fish.task.need_to_complete.attr_value
|
|||||||
or return 1
|
or return 1
|
||||||
# only start completion when there's a colon in attr_name
|
# only start completion when there's a colon in attr_name
|
||||||
set -l cmd (commandline -ct)
|
set -l cmd (commandline -ct)
|
||||||
string match -q "*:*" "$cmd[-1]"
|
string match -q -- "*:*" "$cmd[-1]"
|
||||||
end
|
end
|
||||||
|
|
||||||
function __fish.task.need_to_complete.command
|
function __fish.task.need_to_complete.command
|
||||||
@@ -251,11 +251,11 @@ function __fish.task.list.dates
|
|||||||
echo -e (string replace --all -r "^|\n" "\n$user_input_numeric" $__fish_task_static_reldates | string collect)
|
echo -e (string replace --all -r "^|\n" "\n$user_input_numeric" $__fish_task_static_reldates | string collect)
|
||||||
# special cases for 1st, 2nd and 3rd, and 4-0th
|
# special cases for 1st, 2nd and 3rd, and 4-0th
|
||||||
set -l suffix 'th' '4th, 5th, etc.'
|
set -l suffix 'th' '4th, 5th, etc.'
|
||||||
if string match -q "*1" $user_input_numeric
|
if string match -q -- "*1" $user_input_numeric
|
||||||
set suffix 'st' 'first'
|
set suffix 'st' 'first'
|
||||||
else if string match -q "*2" $user_input_numeric
|
else if string match -q -- "*2" $user_input_numeric
|
||||||
set suffix 'nd' 'second'
|
set suffix 'nd' 'second'
|
||||||
else if string match -q "*3" $user_input_numeric
|
else if string match -q -- "*3" $user_input_numeric
|
||||||
set suffix 'rd' 'third'
|
set suffix 'rd' 'third'
|
||||||
end
|
end
|
||||||
echo -e $user_input_numeric"$suffix[1]\t$suffix[2]"
|
echo -e $user_input_numeric"$suffix[1]\t$suffix[2]"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ FROM centos:8
|
|||||||
|
|
||||||
RUN dnf update -y
|
RUN dnf update -y
|
||||||
RUN yum install epel-release -y
|
RUN yum install epel-release -y
|
||||||
RUN dnf install python38 git gcc gcc-c++ cmake make gnutls-devel libuuid-devel libfaketime sudo man gdb -y
|
RUN dnf install python38 vim git gcc gcc-c++ cmake make gnutls-devel libuuid-devel libfaketime sudo man gdb -y
|
||||||
|
|
||||||
RUN useradd warrior
|
RUN useradd warrior
|
||||||
RUN echo warrior ALL=NOPASSWD:ALL > /etc/sudoers.d/warrior
|
RUN echo warrior ALL=NOPASSWD:ALL > /etc/sudoers.d/warrior
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
#include <shared.h>
|
#include <shared.h>
|
||||||
#include <format.h>
|
#include <format.h>
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
#ifdef HAVE_COMMIT
|
#ifdef HAVE_COMMIT
|
||||||
#include <commit.h>
|
#include <commit.h>
|
||||||
@@ -115,7 +116,7 @@ std::string configurationDefaults =
|
|||||||
"expressions=infix # Prefer infix over postfix expressions\n"
|
"expressions=infix # Prefer infix over postfix expressions\n"
|
||||||
"json.array=1 # Enclose JSON output in [ ]\n"
|
"json.array=1 # Enclose JSON output in [ ]\n"
|
||||||
"abbreviation.minimum=2 # Shortest allowed abbreviation\n"
|
"abbreviation.minimum=2 # Shortest allowed abbreviation\n"
|
||||||
"news.version= # Latest version higlights read by the user\n"
|
"news.version= # Latest version highlights read by the user\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# Dates\n"
|
"# Dates\n"
|
||||||
"dateformat=Y-M-D # Preferred input and display date format\n"
|
"dateformat=Y-M-D # Preferred input and display date format\n"
|
||||||
@@ -358,9 +359,9 @@ std::string configurationDefaults =
|
|||||||
"report.completed.context=1\n"
|
"report.completed.context=1\n"
|
||||||
"\n"
|
"\n"
|
||||||
"report.recurring.description=Recurring Tasks\n"
|
"report.recurring.description=Recurring Tasks\n"
|
||||||
"report.recurring.labels=ID,Active,Age,D,P,Project,Tags,Recur,Sch,Due,Until,Description,Urg\n"
|
"report.recurring.labels=ID,Active,Age,D,P,Parent,Project,Tags,Recur,Sch,Due,Until,Description,Urg\n"
|
||||||
"report.recurring.columns=id,start.age,entry.age,depends.indicator,priority,project,tags,recur,scheduled.countdown,due,until.remaining,description,urgency\n"
|
"report.recurring.columns=id,start.age,entry.age,depends.indicator,priority,parent.short,project,tags,recur,scheduled.countdown,due,until.remaining,description,urgency\n"
|
||||||
"report.recurring.filter=status:pending and (+PARENT or +CHILD)\n"
|
"report.recurring.filter=(status:pending and +CHILD) or (status:recurring and +PARENT)\n"
|
||||||
"report.recurring.sort=due+,urgency-,entry+\n"
|
"report.recurring.sort=due+,urgency-,entry+\n"
|
||||||
"report.recurring.context=1\n"
|
"report.recurring.context=1\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -474,7 +475,7 @@ int Context::initialize (int argc, const char** argv)
|
|||||||
// [1] Load the correct config file.
|
// [1] Load the correct config file.
|
||||||
// - Default to ~/.taskrc (ctor).
|
// - Default to ~/.taskrc (ctor).
|
||||||
// - If no ~/.taskrc, use $XDG_CONFIG_HOME/task/taskrc if exists, or
|
// - If no ~/.taskrc, use $XDG_CONFIG_HOME/task/taskrc if exists, or
|
||||||
// ~/.config/task/taskrc if $XDG_DATA_HOME is unset
|
// ~/.config/task/taskrc if $XDG_CONFIG_HOME is unset
|
||||||
// - Allow $TASKRC override.
|
// - Allow $TASKRC override.
|
||||||
// - Allow command line override rc:<file>
|
// - Allow command line override rc:<file>
|
||||||
// - Load resultant file.
|
// - Load resultant file.
|
||||||
@@ -667,9 +668,13 @@ int Context::initialize (int argc, const char** argv)
|
|||||||
rc = 4;
|
rc = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
catch (const std::regex_error& e)
|
||||||
|
{
|
||||||
|
std::cout << "regex_error caught: " << e.what() << '\n';
|
||||||
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
error ("Unknown error. Please report.");
|
error ("knknown error. Please report.");
|
||||||
rc = 3;
|
rc = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -966,16 +971,19 @@ std::string Context::getTaskContext (const std::string& kind, std::string name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Figure out the context string for this kind (read/write)
|
// Figure out the context string for this kind (read/write)
|
||||||
std::string contextString = config.get ("context." + name + "." + kind);
|
std::string contextString = "";
|
||||||
if (contextString.empty ())
|
|
||||||
|
if (! config.has ("context." + name + "." + kind) && kind == "read")
|
||||||
{
|
{
|
||||||
debug ("Specific " + kind + " context for '" + name + "' not defined. ");
|
debug ("Specific " + kind + " context for '" + name + "' not defined. ");
|
||||||
if (fallback)
|
if (fallback)
|
||||||
{
|
{
|
||||||
debug ("Falling back on generic.");
|
debug ("Trying to interpret old-style context definition as read context.");
|
||||||
contextString = config.get ("context." + name);
|
contextString = config.get ("context." + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
contextString = config.get ("context." + name + "." + kind);
|
||||||
|
|
||||||
debug (format ("Detected context string: {1}", contextString.empty() ? "(empty)" : contextString));
|
debug (format ("Detected context string: {1}", contextString.empty() ? "(empty)" : contextString));
|
||||||
return contextString;
|
return contextString;
|
||||||
@@ -1320,6 +1328,12 @@ void Context::debugTiming (const std::string& details, const Timer& timer)
|
|||||||
debug (out.str ());
|
debug (out.str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CurrentTask Context::withCurrentTask (const Task *task)
|
||||||
|
{
|
||||||
|
return CurrentTask(*this, task);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// This capability is to answer the question of 'what did I just do to generate
|
// This capability is to answer the question of 'what did I just do to generate
|
||||||
// this output?'.
|
// this output?'.
|
||||||
@@ -1421,6 +1435,19 @@ void Context::debug (const std::string& input)
|
|||||||
debugMessages.push_back (input);
|
debugMessages.push_back (input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CurrentTask::CurrentTask (Context &context, const Task *task)
|
||||||
|
: context {context}, previous {context.currentTask}
|
||||||
|
{
|
||||||
|
context.currentTask = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CurrentTask::~CurrentTask ()
|
||||||
|
{
|
||||||
|
context.currentTask = previous;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// vim ts=2:sw=2
|
// vim ts=2:sw=2
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
#include <Timer.h>
|
#include <Timer.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
class CurrentTask;
|
||||||
|
|
||||||
class Context
|
class Context
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -73,6 +75,9 @@ public:
|
|||||||
void decomposeSortField (const std::string&, std::string&, bool&, bool&);
|
void decomposeSortField (const std::string&, std::string&, bool&, bool&);
|
||||||
void debugTiming (const std::string&, const Timer&);
|
void debugTiming (const std::string&, const Timer&);
|
||||||
|
|
||||||
|
CurrentTask withCurrentTask (const Task *);
|
||||||
|
friend class CurrentTask;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void staticInitialization ();
|
void staticInitialization ();
|
||||||
void createDefaultConfig ();
|
void createDefaultConfig ();
|
||||||
@@ -115,6 +120,25 @@ public:
|
|||||||
long time_sort_us {0};
|
long time_sort_us {0};
|
||||||
long time_render_us {0};
|
long time_render_us {0};
|
||||||
long time_hooks_us {0};
|
long time_hooks_us {0};
|
||||||
|
|
||||||
|
// the current task for DOM references, or NULL if there is no task
|
||||||
|
const Task * currentTask {NULL};
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CurrentTask resets Context::currentTask to previous context task on destruction; this ensures
|
||||||
|
// that this context value is restored when exiting the scope where the context was applied.
|
||||||
|
class CurrentTask {
|
||||||
|
public:
|
||||||
|
~CurrentTask();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CurrentTask(Context &context, const Task *previous);
|
||||||
|
|
||||||
|
Context &context;
|
||||||
|
const Task *previous;
|
||||||
|
|
||||||
|
friend class Context;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
132
src/DOM.cpp
132
src/DOM.cpp
@@ -239,22 +239,25 @@ bool getDOM (const std::string& name, Variant& value)
|
|||||||
//
|
//
|
||||||
// This code emphasizes speed, hence 'id' and 'urgency' being evaluated first
|
// This code emphasizes speed, hence 'id' and 'urgency' being evaluated first
|
||||||
// as special cases.
|
// as special cases.
|
||||||
bool getDOM (const std::string& name, const Task& task, Variant& value)
|
//
|
||||||
|
// If task is NULL, then the contextual task will be determined from the DOM
|
||||||
|
// string, if any exists.
|
||||||
|
bool getDOM (const std::string& name, const Task* task, Variant& value)
|
||||||
{
|
{
|
||||||
// Special case, blank refs cause problems.
|
// Special case, blank refs cause problems.
|
||||||
if (name == "")
|
if (name == "")
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Quickly deal with the most common cases.
|
// Quickly deal with the most common cases.
|
||||||
if (task.data.size () && name == "id")
|
if (task && name == "id")
|
||||||
{
|
{
|
||||||
value = Variant (static_cast<int> (task.id));
|
value = Variant (static_cast<int> (task->id));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task.data.size () && name == "urgency")
|
if (task && name == "urgency")
|
||||||
{
|
{
|
||||||
value = Variant (task.urgency_c ());
|
value = Variant (task->urgency_c ());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,54 +265,55 @@ bool getDOM (const std::string& name, const Task& task, Variant& value)
|
|||||||
auto elements = split (name, '.');
|
auto elements = split (name, '.');
|
||||||
Task loaded_task;
|
Task loaded_task;
|
||||||
|
|
||||||
// Use a lambda to decide whether the reference is going to be the passed
|
// decide whether the reference is going to be the passed
|
||||||
// "task" or whether it's going to be a newly loaded task (if id/uuid was
|
// "task" or whether it's going to be a newly loaded task (if id/uuid was
|
||||||
// given).
|
// given).
|
||||||
const Task& ref = [&]() -> const Task&
|
const Task* ref = task;
|
||||||
|
Lexer lexer (elements[0]);
|
||||||
|
std::string token;
|
||||||
|
Lexer::Type type;
|
||||||
|
|
||||||
|
// If this can be ID/UUID reference (the name contains '.'),
|
||||||
|
// lex it to figure out. Otherwise don't lex, as lexing can be slow.
|
||||||
|
if ((elements.size() > 1) and lexer.token (token, type))
|
||||||
{
|
{
|
||||||
Lexer lexer (elements[0]);
|
bool reloaded = false;
|
||||||
std::string token;
|
|
||||||
Lexer::Type type;
|
|
||||||
|
|
||||||
// If this can be ID/UUID reference (the name contains '.'),
|
if (type == Lexer::Type::uuid &&
|
||||||
// lex it to figure out. Otherwise don't lex, as lexing can be slow.
|
token.length () == elements[0].length ())
|
||||||
if ((elements.size() > 1) and lexer.token (token, type))
|
|
||||||
{
|
{
|
||||||
bool reloaded = false;
|
if (!task || token != task->get ("uuid"))
|
||||||
|
|
||||||
if (type == Lexer::Type::uuid &&
|
|
||||||
token.length () == elements[0].length ())
|
|
||||||
{
|
{
|
||||||
if (token != task.get ("uuid"))
|
if (Context::getContext ().tdb2.get (token, loaded_task))
|
||||||
{
|
|
||||||
Context::getContext ().tdb2.get (token, loaded_task);
|
|
||||||
reloaded = true;
|
reloaded = true;
|
||||||
}
|
|
||||||
|
|
||||||
// Eat elements[0]/UUID.
|
|
||||||
elements.erase (elements.begin ());
|
|
||||||
}
|
|
||||||
else if (type == Lexer::Type::number &&
|
|
||||||
token.find ('.') == std::string::npos)
|
|
||||||
{
|
|
||||||
auto id = strtol (token.c_str (), nullptr, 10);
|
|
||||||
if (id && id != task.id)
|
|
||||||
{
|
|
||||||
Context::getContext ().tdb2.get (id, loaded_task);
|
|
||||||
reloaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eat elements[0]/ID.
|
|
||||||
elements.erase (elements.begin ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reloaded)
|
// Eat elements[0]/UUID.
|
||||||
return loaded_task;
|
elements.erase (elements.begin ());
|
||||||
|
}
|
||||||
|
else if (type == Lexer::Type::number &&
|
||||||
|
token.find ('.') == std::string::npos)
|
||||||
|
{
|
||||||
|
auto id = strtol (token.c_str (), nullptr, 10);
|
||||||
|
if (id && (!task || id != task->id))
|
||||||
|
{
|
||||||
|
if (Context::getContext ().tdb2.get (id, loaded_task))
|
||||||
|
reloaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eat elements[0]/ID.
|
||||||
|
elements.erase (elements.begin ());
|
||||||
}
|
}
|
||||||
|
|
||||||
return task;
|
if (reloaded)
|
||||||
|
ref = &loaded_task;
|
||||||
|
}
|
||||||
|
|
||||||
} ();
|
|
||||||
|
// The remainder of this method requires a contextual task, so if we do not
|
||||||
|
// have one, delegate to the two-argument getDOM
|
||||||
|
if (!ref)
|
||||||
|
return getDOM (name, value);
|
||||||
|
|
||||||
auto size = elements.size ();
|
auto size = elements.size ();
|
||||||
|
|
||||||
@@ -318,31 +322,31 @@ bool getDOM (const std::string& name, const Task& task, Variant& value)
|
|||||||
{
|
{
|
||||||
// Now that 'ref' is the contextual task, and any ID/UUID is chopped off the
|
// Now that 'ref' is the contextual task, and any ID/UUID is chopped off the
|
||||||
// elements vector, DOM resolution is now simple.
|
// elements vector, DOM resolution is now simple.
|
||||||
if (ref.data.size () && size == 1 && canonical == "id")
|
if (size == 1 && canonical == "id")
|
||||||
{
|
{
|
||||||
value = Variant (static_cast<int> (ref.id));
|
value = Variant (static_cast<int> (ref->id));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref.data.size () && size == 1 && canonical == "urgency")
|
if (size == 1 && canonical == "urgency")
|
||||||
{
|
{
|
||||||
value = Variant (ref.urgency_c ());
|
value = Variant (ref->urgency_c ());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special handling of status required for virtual waiting status
|
// Special handling of status required for virtual waiting status
|
||||||
// implementation. Remove in 3.0.0.
|
// implementation. Remove in 3.0.0.
|
||||||
if (ref.data.size () && size == 1 && canonical == "status")
|
if (size == 1 && canonical == "status")
|
||||||
{
|
{
|
||||||
value = Variant (ref.statusToText (ref.getStatus ()));
|
value = Variant (ref->statusToText (ref->getStatus ()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Column* column = Context::getContext ().columns[canonical];
|
Column* column = Context::getContext ().columns[canonical];
|
||||||
|
|
||||||
if (ref.data.size () && size == 1 && column)
|
if (size == 1 && column)
|
||||||
{
|
{
|
||||||
if (column->is_uda () && ! ref.has (canonical))
|
if (column->is_uda () && ! ref->has (canonical))
|
||||||
{
|
{
|
||||||
value = Variant ("");
|
value = Variant ("");
|
||||||
return true;
|
return true;
|
||||||
@@ -350,7 +354,7 @@ bool getDOM (const std::string& name, const Task& task, Variant& value)
|
|||||||
|
|
||||||
if (column->type () == "date")
|
if (column->type () == "date")
|
||||||
{
|
{
|
||||||
auto numeric = ref.get_date (canonical);
|
auto numeric = ref->get_date (canonical);
|
||||||
if (numeric == 0)
|
if (numeric == 0)
|
||||||
value = Variant ("");
|
value = Variant ("");
|
||||||
else
|
else
|
||||||
@@ -358,32 +362,32 @@ bool getDOM (const std::string& name, const Task& task, Variant& value)
|
|||||||
}
|
}
|
||||||
else if (column->type () == "duration" || canonical == "recur")
|
else if (column->type () == "duration" || canonical == "recur")
|
||||||
{
|
{
|
||||||
auto period = ref.get (canonical);
|
auto period = ref->get (canonical);
|
||||||
|
|
||||||
Duration iso;
|
Duration iso;
|
||||||
std::string::size_type cursor = 0;
|
std::string::size_type cursor = 0;
|
||||||
if (iso.parse (period, cursor))
|
if (iso.parse (period, cursor))
|
||||||
value = Variant (iso.toTime_t (), Variant::type_duration);
|
value = Variant (iso.toTime_t (), Variant::type_duration);
|
||||||
else
|
else
|
||||||
value = Variant (Duration (ref.get (canonical)).toTime_t (), Variant::type_duration);
|
value = Variant (Duration (ref->get (canonical)).toTime_t (), Variant::type_duration);
|
||||||
}
|
}
|
||||||
else if (column->type () == "numeric")
|
else if (column->type () == "numeric")
|
||||||
value = Variant (ref.get_float (canonical));
|
value = Variant (ref->get_float (canonical));
|
||||||
else
|
else
|
||||||
value = Variant (ref.get (canonical));
|
value = Variant (ref->get (canonical));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref.data.size () && size == 2 && canonical == "tags")
|
if (size == 2 && canonical == "tags")
|
||||||
{
|
{
|
||||||
value = Variant (ref.hasTag (elements[1]) ? elements[1] : "");
|
value = Variant (ref->hasTag (elements[1]) ? elements[1] : "");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref.data.size () && size == 2 && column && column->type () == "date")
|
if (size == 2 && column && column->type () == "date")
|
||||||
{
|
{
|
||||||
Datetime date (ref.get_date (canonical));
|
Datetime date (ref->get_date (canonical));
|
||||||
if (elements[1] == "year") { value = Variant (static_cast<int> (date.year ())); return true; }
|
if (elements[1] == "year") { value = Variant (static_cast<int> (date.year ())); return true; }
|
||||||
else if (elements[1] == "month") { value = Variant (static_cast<int> (date.month ())); return true; }
|
else if (elements[1] == "month") { value = Variant (static_cast<int> (date.month ())); return true; }
|
||||||
else if (elements[1] == "day") { value = Variant (static_cast<int> (date.day ())); return true; }
|
else if (elements[1] == "day") { value = Variant (static_cast<int> (date.day ())); return true; }
|
||||||
@@ -396,15 +400,15 @@ bool getDOM (const std::string& name, const Task& task, Variant& value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref.data.size () && size == 2 && elements[0] == "annotations" && elements[1] == "count")
|
if (size == 2 && elements[0] == "annotations" && elements[1] == "count")
|
||||||
{
|
{
|
||||||
value = Variant (static_cast<int> (ref.getAnnotationCount ()));
|
value = Variant (static_cast<int> (ref->getAnnotationCount ()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref.data.size () && size == 3 && elements[0] == "annotations")
|
if (size == 3 && elements[0] == "annotations")
|
||||||
{
|
{
|
||||||
auto annos = ref.getAnnotations ();
|
auto annos = ref->getAnnotations ();
|
||||||
|
|
||||||
int a = strtol (elements[1].c_str (), nullptr, 10);
|
int a = strtol (elements[1].c_str (), nullptr, 10);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@@ -430,9 +434,9 @@ bool getDOM (const std::string& name, const Task& task, Variant& value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref.data.size () && size == 4 && elements[0] == "annotations" && elements[2] == "entry")
|
if (size == 4 && elements[0] == "annotations" && elements[2] == "entry")
|
||||||
{
|
{
|
||||||
auto annos = ref.getAnnotations ();
|
auto annos = ref->getAnnotations ();
|
||||||
|
|
||||||
int a = strtol (elements[1].c_str (), nullptr, 10);
|
int a = strtol (elements[1].c_str (), nullptr, 10);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
// 2017-04-22 Deprecated, use DOM::get.
|
// 2017-04-22 Deprecated, use DOM::get.
|
||||||
bool getDOM (const std::string&, Variant&);
|
bool getDOM (const std::string&, Variant&);
|
||||||
bool getDOM (const std::string&, const Task&, Variant&);
|
bool getDOM (const std::string&, const Task*, Variant&);
|
||||||
|
|
||||||
class DOM
|
class DOM
|
||||||
{
|
{
|
||||||
|
|||||||
30
src/Eval.cpp
30
src/Eval.cpp
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <cmake.h>
|
#include <cmake.h>
|
||||||
#include <Eval.h>
|
#include <Eval.h>
|
||||||
|
#include <DOM.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <Context.h>
|
#include <Context.h>
|
||||||
@@ -34,8 +35,6 @@
|
|||||||
#include <shared.h>
|
#include <shared.h>
|
||||||
#include <format.h>
|
#include <format.h>
|
||||||
|
|
||||||
extern Task& contextTask;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Supported operators, borrowed from C++, particularly the precedence.
|
// Supported operators, borrowed from C++, particularly the precedence.
|
||||||
// Note: table is sorted by length of operator string, so searches match
|
// Note: table is sorted by length of operator string, so searches match
|
||||||
@@ -101,6 +100,19 @@ static bool namedConstants (const std::string& name, Variant& value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Support for evaluating DOM references (add with `e.AddSource(domSource)`)
|
||||||
|
bool domSource (const std::string& identifier, Variant& value)
|
||||||
|
{
|
||||||
|
if (getDOM (identifier, Context::getContext ().currentTask, value))
|
||||||
|
{
|
||||||
|
value.source (identifier);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
Eval::Eval ()
|
Eval::Eval ()
|
||||||
{
|
{
|
||||||
@@ -278,6 +290,8 @@ void Eval::evaluatePostfixStack (
|
|||||||
Variant left = values.back ();
|
Variant left = values.back ();
|
||||||
values.pop_back ();
|
values.pop_back ();
|
||||||
|
|
||||||
|
auto contextTask = Context::getContext ().currentTask;
|
||||||
|
|
||||||
// Ordering these by anticipation frequency of use is a good idea.
|
// Ordering these by anticipation frequency of use is a good idea.
|
||||||
Variant result;
|
Variant result;
|
||||||
if (token.first == "and") result = left && right;
|
if (token.first == "and") result = left && right;
|
||||||
@@ -299,10 +313,14 @@ void Eval::evaluatePostfixStack (
|
|||||||
else if (token.first == "^") result = left ^ right;
|
else if (token.first == "^") result = left ^ right;
|
||||||
else if (token.first == "%") result = left % right;
|
else if (token.first == "%") result = left % right;
|
||||||
else if (token.first == "xor") result = left.operator_xor (right);
|
else if (token.first == "xor") result = left.operator_xor (right);
|
||||||
else if (token.first == "~") result = left.operator_match (right, contextTask);
|
else if (contextTask) {
|
||||||
else if (token.first == "!~") result = left.operator_nomatch (right, contextTask);
|
if (token.first == "~") result = left.operator_match (right, *contextTask);
|
||||||
else if (token.first == "_hastag_") result = left.operator_hastag (right, contextTask);
|
else if (token.first == "!~") result = left.operator_nomatch (right, *contextTask);
|
||||||
else if (token.first == "_notag_") result = left.operator_notag (right, contextTask);
|
else if (token.first == "_hastag_") result = left.operator_hastag (right, *contextTask);
|
||||||
|
else if (token.first == "_notag_") result = left.operator_notag (right, *contextTask);
|
||||||
|
else
|
||||||
|
throw format ("Unsupported operator '{1}'.", token.first);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw format ("Unsupported operator '{1}'.", token.first);
|
throw format ("Unsupported operator '{1}'.", token.first);
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
#include <Lexer.h>
|
#include <Lexer.h>
|
||||||
#include <Variant.h>
|
#include <Variant.h>
|
||||||
|
|
||||||
|
bool domSource (const std::string&, Variant&);
|
||||||
|
|
||||||
class Eval
|
class Eval
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -35,23 +35,6 @@
|
|||||||
#include <format.h>
|
#include <format.h>
|
||||||
#include <shared.h>
|
#include <shared.h>
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Const iterator that can be derefenced into a Task by domSource.
|
|
||||||
static Task dummy;
|
|
||||||
Task& contextTask = dummy;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool domSource (const std::string& identifier, Variant& value)
|
|
||||||
{
|
|
||||||
if (getDOM (identifier, contextTask, value))
|
|
||||||
{
|
|
||||||
value.source (identifier);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Take an input set of tasks and filter into a subset.
|
// Take an input set of tasks and filter into a subset.
|
||||||
void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output)
|
void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output)
|
||||||
@@ -79,7 +62,7 @@ void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output
|
|||||||
for (auto& task : input)
|
for (auto& task : input)
|
||||||
{
|
{
|
||||||
// Set up context for any DOM references.
|
// Set up context for any DOM references.
|
||||||
contextTask = task;
|
auto currentTask = Context::getContext ().withCurrentTask(&task);
|
||||||
|
|
||||||
Variant var;
|
Variant var;
|
||||||
eval.evaluateCompiledExpression (var);
|
eval.evaluateCompiledExpression (var);
|
||||||
@@ -131,7 +114,7 @@ void Filter::subset (std::vector <Task>& output)
|
|||||||
for (auto& task : pending)
|
for (auto& task : pending)
|
||||||
{
|
{
|
||||||
// Set up context for any DOM references.
|
// Set up context for any DOM references.
|
||||||
contextTask = task;
|
auto currentTask = Context::getContext ().withCurrentTask(&task);
|
||||||
|
|
||||||
Variant var;
|
Variant var;
|
||||||
eval.evaluateCompiledExpression (var);
|
eval.evaluateCompiledExpression (var);
|
||||||
@@ -150,7 +133,7 @@ void Filter::subset (std::vector <Task>& output)
|
|||||||
for (auto& task : completed)
|
for (auto& task : completed)
|
||||||
{
|
{
|
||||||
// Set up context for any DOM references.
|
// Set up context for any DOM references.
|
||||||
contextTask = task;
|
auto currentTask = Context::getContext ().withCurrentTask(&task);
|
||||||
|
|
||||||
Variant var;
|
Variant var;
|
||||||
eval.evaluateCompiledExpression (var);
|
eval.evaluateCompiledExpression (var);
|
||||||
|
|||||||
@@ -32,8 +32,6 @@
|
|||||||
#include <Task.h>
|
#include <Task.h>
|
||||||
#include <Variant.h>
|
#include <Variant.h>
|
||||||
|
|
||||||
bool domSource (const std::string&, Variant&);
|
|
||||||
|
|
||||||
class Filter
|
class Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
195
src/TDB2.cpp
195
src/TDB2.cpp
@@ -1025,203 +1025,24 @@ void TDB2::show_diff (
|
|||||||
Color color_red (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.before") : "");
|
Color color_red (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.before") : "");
|
||||||
Color color_green (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.after") : "");
|
Color color_green (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.after") : "");
|
||||||
|
|
||||||
|
auto before = prior == "" ? Task() : Task(prior);
|
||||||
|
auto after = Task(current);
|
||||||
|
|
||||||
if (Context::getContext ().config.get ("undo.style") == "side")
|
if (Context::getContext ().config.get ("undo.style") == "side")
|
||||||
{
|
{
|
||||||
|
Table view = before.diffForUndoSide(after);
|
||||||
|
|
||||||
std::cout << '\n'
|
std::cout << '\n'
|
||||||
<< format ("The last modification was made {1}", lastChange.toString ())
|
<< format ("The last modification was made {1}", lastChange.toString ())
|
||||||
<< '\n';
|
<< '\n'
|
||||||
|
<< '\n'
|
||||||
// Attributes are all there is, so figure the different attribute names
|
|
||||||
// between before and after.
|
|
||||||
Table view;
|
|
||||||
view.width (Context::getContext ().getWidth ());
|
|
||||||
view.intraPadding (2);
|
|
||||||
view.add ("");
|
|
||||||
view.add ("Prior Values");
|
|
||||||
view.add ("Current Values");
|
|
||||||
setHeaderUnderline (view);
|
|
||||||
|
|
||||||
Task after (current);
|
|
||||||
|
|
||||||
if (prior != "")
|
|
||||||
{
|
|
||||||
Task before (prior);
|
|
||||||
|
|
||||||
std::vector <std::string> beforeAtts;
|
|
||||||
for (auto& att : before.data)
|
|
||||||
beforeAtts.push_back (att.first);
|
|
||||||
|
|
||||||
std::vector <std::string> afterAtts;
|
|
||||||
for (auto& att : after.data)
|
|
||||||
afterAtts.push_back (att.first);
|
|
||||||
|
|
||||||
std::vector <std::string> beforeOnly;
|
|
||||||
std::vector <std::string> afterOnly;
|
|
||||||
listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly);
|
|
||||||
|
|
||||||
int row;
|
|
||||||
for (auto& name : beforeOnly)
|
|
||||||
{
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, name);
|
|
||||||
view.set (row, 1, renderAttribute (name, before.get (name)), color_red);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& att : before.data)
|
|
||||||
{
|
|
||||||
std::string priorValue = before.get (att.first);
|
|
||||||
std::string currentValue = after.get (att.first);
|
|
||||||
|
|
||||||
if (currentValue != "")
|
|
||||||
{
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, att.first);
|
|
||||||
view.set (row, 1, renderAttribute (att.first, priorValue),
|
|
||||||
(priorValue != currentValue ? color_red : Color ()));
|
|
||||||
view.set (row, 2, renderAttribute (att.first, currentValue),
|
|
||||||
(priorValue != currentValue ? color_green : Color ()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& name : afterOnly)
|
|
||||||
{
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, name);
|
|
||||||
view.set (row, 2, renderAttribute (name, after.get (name)), color_green);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int row;
|
|
||||||
for (auto& att : after.data)
|
|
||||||
{
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, att.first);
|
|
||||||
view.set (row, 2, renderAttribute (att.first, after.get (att.first)), color_green);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << '\n'
|
|
||||||
<< view.render ()
|
<< view.render ()
|
||||||
<< '\n';
|
<< '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// This style looks like this:
|
|
||||||
// --- before 2009-07-04 00:00:25.000000000 +0200
|
|
||||||
// +++ after 2009-07-04 00:00:45.000000000 +0200
|
|
||||||
//
|
|
||||||
// - name: old // att deleted
|
|
||||||
// + name:
|
|
||||||
//
|
|
||||||
// - name: old // att changed
|
|
||||||
// + name: new
|
|
||||||
//
|
|
||||||
// - name:
|
|
||||||
// + name: new // att added
|
|
||||||
//
|
|
||||||
else if (Context::getContext ().config.get ("undo.style") == "diff")
|
else if (Context::getContext ().config.get ("undo.style") == "diff")
|
||||||
{
|
{
|
||||||
// Create reference tasks.
|
Table view = before.diffForUndoPatch(after, lastChange);
|
||||||
Task before;
|
|
||||||
if (prior != "")
|
|
||||||
before.parse (prior);
|
|
||||||
|
|
||||||
Task after (current);
|
|
||||||
|
|
||||||
// Generate table header.
|
|
||||||
Table view;
|
|
||||||
view.width (Context::getContext ().getWidth ());
|
|
||||||
view.intraPadding (2);
|
|
||||||
view.add ("");
|
|
||||||
view.add ("");
|
|
||||||
|
|
||||||
int row = view.addRow ();
|
|
||||||
view.set (row, 0, "--- previous state", color_red);
|
|
||||||
view.set (row, 1, "Undo will restore this state", color_red);
|
|
||||||
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, "+++ current state ", color_green);
|
|
||||||
view.set (row, 1, format ("Change made {1}",
|
|
||||||
lastChange.toString (Context::getContext ().config.get ("dateformat"))),
|
|
||||||
color_green);
|
|
||||||
|
|
||||||
view.addRow ();
|
|
||||||
|
|
||||||
// Add rows to table showing diffs.
|
|
||||||
std::vector <std::string> all = Context::getContext ().getColumns ();
|
|
||||||
|
|
||||||
// Now factor in the annotation attributes.
|
|
||||||
for (auto& it : before.data)
|
|
||||||
if (it.first.substr (0, 11) == "annotation_")
|
|
||||||
all.push_back (it.first);
|
|
||||||
|
|
||||||
for (auto& it : after.data)
|
|
||||||
if (it.first.substr (0, 11) == "annotation_")
|
|
||||||
all.push_back (it.first);
|
|
||||||
|
|
||||||
// Now render all the attributes.
|
|
||||||
std::sort (all.begin (), all.end ());
|
|
||||||
|
|
||||||
std::string before_att;
|
|
||||||
std::string after_att;
|
|
||||||
std::string last_att;
|
|
||||||
for (auto& a : all)
|
|
||||||
{
|
|
||||||
if (a != last_att) // Skip duplicates.
|
|
||||||
{
|
|
||||||
last_att = a;
|
|
||||||
|
|
||||||
before_att = before.get (a);
|
|
||||||
after_att = after.get (a);
|
|
||||||
|
|
||||||
// Don't report different uuid.
|
|
||||||
// Show nothing if values are the unchanged.
|
|
||||||
if (a == "uuid" ||
|
|
||||||
before_att == after_att)
|
|
||||||
{
|
|
||||||
// Show nothing - no point displaying that which did not change.
|
|
||||||
|
|
||||||
// row = view.addRow ();
|
|
||||||
// view.set (row, 0, *a + ":");
|
|
||||||
// view.set (row, 1, before_att);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attribute deleted.
|
|
||||||
else if (before_att != "" && after_att == "")
|
|
||||||
{
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, '-' + a + ':', color_red);
|
|
||||||
view.set (row, 1, before_att, color_red);
|
|
||||||
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, '+' + a + ':', color_green);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attribute added.
|
|
||||||
else if (before_att == "" && after_att != "")
|
|
||||||
{
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, '-' + a + ':', color_red);
|
|
||||||
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, '+' + a + ':', color_green);
|
|
||||||
view.set (row, 1, after_att, color_green);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attribute changed.
|
|
||||||
else
|
|
||||||
{
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, '-' + a + ':', color_red);
|
|
||||||
view.set (row, 1, before_att, color_red);
|
|
||||||
|
|
||||||
row = view.addRow ();
|
|
||||||
view.set (row, 0, '+' + a + ':', color_green);
|
|
||||||
view.set (row, 1, after_att, color_green);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << '\n'
|
std::cout << '\n'
|
||||||
<< view.render ()
|
<< view.render ()
|
||||||
<< '\n';
|
<< '\n';
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include <TLSClient.h>
|
#include <TLSClient.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
#include <shared.h>
|
#include <shared.h>
|
||||||
#include <format.h>
|
#include <format.h>
|
||||||
|
|
||||||
|
#define HEADER_SIZE 4
|
||||||
#define MAX_BUF 16384
|
#define MAX_BUF 16384
|
||||||
|
|
||||||
#if GNUTLS_VERSION_NUMBER < 0x030406
|
#if GNUTLS_VERSION_NUMBER < 0x030406
|
||||||
@@ -469,24 +471,15 @@ void TLSClient::send (const std::string& data)
|
|||||||
packet[3] = l;
|
packet[3] = l;
|
||||||
|
|
||||||
unsigned int total = 0;
|
unsigned int total = 0;
|
||||||
unsigned int remaining = packet.length ();
|
|
||||||
|
|
||||||
while (total < packet.length ())
|
int status;
|
||||||
|
do
|
||||||
{
|
{
|
||||||
int status;
|
status = gnutls_record_send (_session, packet.c_str () + total, packet.length () - total); // All
|
||||||
do
|
|
||||||
{
|
|
||||||
status = gnutls_record_send (_session, packet.c_str () + total, remaining); // All
|
|
||||||
}
|
|
||||||
while (errno == GNUTLS_E_INTERRUPTED ||
|
|
||||||
errno == GNUTLS_E_AGAIN);
|
|
||||||
|
|
||||||
if (status == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
total += (unsigned int) status;
|
|
||||||
remaining -= (unsigned int) status;
|
|
||||||
}
|
}
|
||||||
|
while ((status > 0 && (total += status) < packet.length ()) ||
|
||||||
|
status == GNUTLS_E_INTERRUPTED ||
|
||||||
|
status == GNUTLS_E_AGAIN);
|
||||||
|
|
||||||
if (_debug)
|
if (_debug)
|
||||||
std::cout << "c: INFO Sending 'XXXX"
|
std::cout << "c: INFO Sending 'XXXX"
|
||||||
@@ -500,18 +493,22 @@ void TLSClient::recv (std::string& data)
|
|||||||
{
|
{
|
||||||
data = ""; // No appending of data.
|
data = ""; // No appending of data.
|
||||||
int received = 0;
|
int received = 0;
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
// Get the encoded length.
|
// Get the encoded length.
|
||||||
unsigned char header[4] {};
|
unsigned char header[HEADER_SIZE] {};
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
received = gnutls_record_recv (_session, header, 4); // All
|
received = gnutls_record_recv (_session, header + total, HEADER_SIZE - total); // All
|
||||||
}
|
}
|
||||||
while (received > 0 &&
|
while ((received > 0 && (total += received) < HEADER_SIZE) ||
|
||||||
(errno == GNUTLS_E_INTERRUPTED ||
|
received == GNUTLS_E_INTERRUPTED ||
|
||||||
errno == GNUTLS_E_AGAIN));
|
received == GNUTLS_E_AGAIN);
|
||||||
|
|
||||||
int total = received;
|
if (total < HEADER_SIZE) {
|
||||||
|
throw std::string ("Failed to receive header: ") +
|
||||||
|
(received < 0 ? gnutls_strerror(received) : "connection lost?");
|
||||||
|
}
|
||||||
|
|
||||||
// Decode the length.
|
// Decode the length.
|
||||||
unsigned long expected = (header[0]<<24) |
|
unsigned long expected = (header[0]<<24) |
|
||||||
@@ -521,7 +518,11 @@ void TLSClient::recv (std::string& data)
|
|||||||
if (_debug)
|
if (_debug)
|
||||||
std::cout << "c: INFO expecting " << expected << " bytes.\n";
|
std::cout << "c: INFO expecting " << expected << " bytes.\n";
|
||||||
|
|
||||||
// TODO This would be a good place to assert 'expected < _limit'.
|
if (_limit && expected >= (unsigned long) _limit) {
|
||||||
|
std::ostringstream err_str;
|
||||||
|
err_str << "Expected message size " << expected << " is larger than allowed limit " << _limit;
|
||||||
|
throw err_str.str ();
|
||||||
|
}
|
||||||
|
|
||||||
// Arbitrary buffer size.
|
// Arbitrary buffer size.
|
||||||
char buffer[MAX_BUF];
|
char buffer[MAX_BUF];
|
||||||
@@ -531,13 +532,18 @@ void TLSClient::recv (std::string& data)
|
|||||||
// fits in the buffer.
|
// fits in the buffer.
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
int chunk_size = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
received = gnutls_record_recv (_session, buffer, MAX_BUF - 1); // All
|
received = gnutls_record_recv (_session, buffer + chunk_size, MAX_BUF - chunk_size); // All
|
||||||
|
if (received > 0) {
|
||||||
|
total += received;
|
||||||
|
chunk_size += received;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (received > 0 &&
|
while ((received > 0 && (unsigned long) total < expected && chunk_size < MAX_BUF) ||
|
||||||
(errno == GNUTLS_E_INTERRUPTED ||
|
received == GNUTLS_E_INTERRUPTED ||
|
||||||
errno == GNUTLS_E_AGAIN));
|
received == GNUTLS_E_AGAIN);
|
||||||
|
|
||||||
// Other end closed the connection.
|
// Other end closed the connection.
|
||||||
if (received == 0)
|
if (received == 0)
|
||||||
@@ -548,17 +554,10 @@ void TLSClient::recv (std::string& data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Something happened.
|
// Something happened.
|
||||||
if (received < 0 && gnutls_error_is_fatal (received) == 0) // All
|
if (received < 0)
|
||||||
{
|
|
||||||
if (_debug)
|
|
||||||
std::cout << "c: WARNING " << gnutls_strerror (received) << '\n'; // All
|
|
||||||
}
|
|
||||||
else if (received < 0)
|
|
||||||
throw std::string (gnutls_strerror (received)); // All
|
throw std::string (gnutls_strerror (received)); // All
|
||||||
|
|
||||||
buffer [received] = '\0';
|
data.append (buffer, chunk_size);
|
||||||
data += buffer;
|
|
||||||
total += received;
|
|
||||||
|
|
||||||
// Stop at defined limit.
|
// Stop at defined limit.
|
||||||
if (_limit && total > _limit)
|
if (_limit && total > _limit)
|
||||||
|
|||||||
285
src/Task.cpp
285
src/Task.cpp
@@ -60,8 +60,6 @@
|
|||||||
|
|
||||||
#define APPROACHING_INFINITY 1000 // Close enough. This isn't rocket surgery.
|
#define APPROACHING_INFINITY 1000 // Close enough. This isn't rocket surgery.
|
||||||
|
|
||||||
extern Task& contextTask;
|
|
||||||
|
|
||||||
static const float epsilon = 0.000001;
|
static const float epsilon = 0.000001;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -114,6 +112,12 @@ bool Task::operator== (const Task& other)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool Task::operator!= (const Task& other)
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
Task::Task (const std::string& input)
|
Task::Task (const std::string& input)
|
||||||
{
|
{
|
||||||
@@ -363,6 +367,14 @@ Task::dateState Task::getDateState (const std::string& name) const
|
|||||||
return dateNotDue;
|
return dateNotDue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// An empty task is typically a "dummy", such as in DOM evaluation, which may or
|
||||||
|
// may not occur in the context of a task.
|
||||||
|
bool Task::is_empty () const
|
||||||
|
{
|
||||||
|
return data.size () == 0;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Ready means pending, not blocked and either not scheduled or scheduled before
|
// Ready means pending, not blocked and either not scheduled or scheduled before
|
||||||
// now.
|
// now.
|
||||||
@@ -546,9 +558,11 @@ bool Task::is_udaPresent () const
|
|||||||
bool Task::is_orphanPresent () const
|
bool Task::is_orphanPresent () const
|
||||||
{
|
{
|
||||||
for (auto& att : data)
|
for (auto& att : data)
|
||||||
if (att.first.compare (0, 11, "annotation_", 11) != 0)
|
if (! isAnnotationAttr (att.first) &&
|
||||||
if (Context::getContext ().columns.find (att.first) == Context::getContext ().columns.end ())
|
! isTagAttr (att.first) &&
|
||||||
return true;
|
! isDepAttr (att.first) &&
|
||||||
|
Context::getContext ().columns.find (att.first) == Context::getContext ().columns.end ())
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -576,12 +590,14 @@ bool Task::is_overdue () const
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Task is considered waiting if it's pending and the wait attribute is set as
|
||||||
|
// future datetime value.
|
||||||
|
// While this is not consistent with other attribute-based virtual tags, such
|
||||||
|
// as +BLOCKED, it is more backwards compatible with how +WAITING virtual tag
|
||||||
|
// behaved in the past, when waiting had a dedicated status value.
|
||||||
bool Task::is_waiting () const
|
bool Task::is_waiting () const
|
||||||
{
|
{
|
||||||
// note that is_waiting can return true for tasks in an actual status other
|
if (has ("wait") && get ("status") == "pending")
|
||||||
// than pending; in this case +WAITING will be set but the status will not be
|
|
||||||
// "waiting"
|
|
||||||
if (has ("wait"))
|
|
||||||
{
|
{
|
||||||
Datetime now;
|
Datetime now;
|
||||||
Datetime wait (get_date ("wait"));
|
Datetime wait (get_date ("wait"));
|
||||||
@@ -761,7 +777,25 @@ void Task::parseJSON (const json::object* root_obj)
|
|||||||
else if (i.first == "depends" && i.second->type() == json::j_string)
|
else if (i.first == "depends" && i.second->type() == json::j_string)
|
||||||
{
|
{
|
||||||
auto deps = (json::string*)i.second;
|
auto deps = (json::string*)i.second;
|
||||||
auto uuids = split (deps->_data, ',');
|
|
||||||
|
// Fix for issue#2689: taskserver sometimes encodes the depends
|
||||||
|
// property as a string of the format `[\"uuid\",\"uuid\"]`
|
||||||
|
// The string includes the backslash-escaped `"` characters, making
|
||||||
|
// it invalid JSON. Since we know the characters we're looking for,
|
||||||
|
// we'll just filter out everything else.
|
||||||
|
std::string deps_str = deps->_data;
|
||||||
|
if (deps_str.front () == '[' && deps_str.back () == ']') {
|
||||||
|
std::string filtered;
|
||||||
|
for (auto &c: deps_str) {
|
||||||
|
if ((c >= '0' && c <= '9') ||
|
||||||
|
(c >= 'a' && c <= 'f') ||
|
||||||
|
c == ',' || c == '-') {
|
||||||
|
filtered.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deps_str = filtered;
|
||||||
|
}
|
||||||
|
auto uuids = split (deps_str, ',');
|
||||||
|
|
||||||
for (const auto& uuid : uuids)
|
for (const auto& uuid : uuids)
|
||||||
addDependency (uuid);
|
addDependency (uuid);
|
||||||
@@ -1478,7 +1512,7 @@ void Task::fixTagsAttribute ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool Task::isTagAttr(const std::string& attr) const
|
bool Task::isTagAttr(const std::string& attr)
|
||||||
{
|
{
|
||||||
return attr.compare(0, 5, "tags_") == 0;
|
return attr.compare(0, 5, "tags_") == 0;
|
||||||
}
|
}
|
||||||
@@ -1512,7 +1546,7 @@ void Task::fixDependsAttribute ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool Task::isDepAttr(const std::string& attr) const
|
bool Task::isDepAttr(const std::string& attr)
|
||||||
{
|
{
|
||||||
return attr.compare(0, 4, "dep_") == 0;
|
return attr.compare(0, 4, "dep_") == 0;
|
||||||
}
|
}
|
||||||
@@ -1533,7 +1567,7 @@ const std::string Task::attr2Dep (const std::string& attr) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool Task::isAnnotationAttr(const std::string& attr) const
|
bool Task::isAnnotationAttr(const std::string& attr)
|
||||||
{
|
{
|
||||||
return attr.compare(0, 11, "annotation_") == 0;
|
return attr.compare(0, 11, "annotation_") == 0;
|
||||||
}
|
}
|
||||||
@@ -1541,7 +1575,7 @@ bool Task::isAnnotationAttr(const std::string& attr) const
|
|||||||
#ifdef PRODUCT_TASKWARRIOR
|
#ifdef PRODUCT_TASKWARRIOR
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// A UDA Orphan is an attribute that is not represented in context.columns.
|
// A UDA Orphan is an attribute that is not represented in context.columns.
|
||||||
std::vector <std::string> Task::getUDAOrphanUUIDs () const
|
std::vector <std::string> Task::getUDAOrphans () const
|
||||||
{
|
{
|
||||||
std::vector <std::string> orphans;
|
std::vector <std::string> orphans;
|
||||||
for (auto& it : data)
|
for (auto& it : data)
|
||||||
@@ -2253,6 +2287,10 @@ void Task::modify (modType type, bool text_required /* = false */)
|
|||||||
{
|
{
|
||||||
std::string label = " [1;37;43mMODIFICATION[0m ";
|
std::string label = " [1;37;43mMODIFICATION[0m ";
|
||||||
|
|
||||||
|
// while reading the parse tree, consider DOM references in the context of
|
||||||
|
// this task
|
||||||
|
auto currentTask = Context::getContext ().withCurrentTask(this);
|
||||||
|
|
||||||
// Need this for later comparison.
|
// Need this for later comparison.
|
||||||
auto originalStatus = getStatus ();
|
auto originalStatus = getStatus ();
|
||||||
|
|
||||||
@@ -2272,6 +2310,19 @@ void Task::modify (modType type, bool text_required /* = false */)
|
|||||||
value == "''" ||
|
value == "''" ||
|
||||||
value == "\"\"")
|
value == "\"\"")
|
||||||
{
|
{
|
||||||
|
// Special case: Handle bulk removal of 'tags' and 'depends" virtual
|
||||||
|
// attributes
|
||||||
|
if (name == "depends")
|
||||||
|
{
|
||||||
|
for (auto dep: getDependencyUUIDs ())
|
||||||
|
removeDependency(dep);
|
||||||
|
}
|
||||||
|
else if (name == "tags")
|
||||||
|
{
|
||||||
|
for (auto tag: getTags ())
|
||||||
|
removeTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
// ::composeF4 will skip if the value is blank, but the presence of
|
// ::composeF4 will skip if the value is blank, but the presence of
|
||||||
// the attribute will prevent ::validate from applying defaults.
|
// the attribute will prevent ::validate from applying defaults.
|
||||||
if ((has (name) && get (name) != "") ||
|
if ((has (name) && get (name) != "") ||
|
||||||
@@ -2400,7 +2451,8 @@ void Task::modify (modType type, bool text_required /* = false */)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Compare this task to another and summarize the differences for display
|
// Compare this task to another and summarize the differences for display, in
|
||||||
|
// the future tense ("Foo will be set to ..").
|
||||||
std::string Task::diff (const Task& after) const
|
std::string Task::diff (const Task& after) const
|
||||||
{
|
{
|
||||||
// Attributes are all there is, so figure the different attribute names
|
// Attributes are all there is, so figure the different attribute names
|
||||||
@@ -2645,3 +2697,206 @@ std::string Task::diffForInfo (
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Similar to diff, but formatted as a side-by-side table for an Undo preview
|
||||||
|
Table Task::diffForUndoSide (
|
||||||
|
const Task& after) const
|
||||||
|
{
|
||||||
|
// Set the colors.
|
||||||
|
Color color_red (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.before") : "");
|
||||||
|
Color color_green (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.after") : "");
|
||||||
|
|
||||||
|
// Attributes are all there is, so figure the different attribute names
|
||||||
|
// between before and after.
|
||||||
|
Table view;
|
||||||
|
view.width (Context::getContext ().getWidth ());
|
||||||
|
view.intraPadding (2);
|
||||||
|
view.add ("");
|
||||||
|
view.add ("Prior Values");
|
||||||
|
view.add ("Current Values");
|
||||||
|
setHeaderUnderline (view);
|
||||||
|
|
||||||
|
if (!is_empty ())
|
||||||
|
{
|
||||||
|
const Task &before = *this;
|
||||||
|
|
||||||
|
std::vector <std::string> beforeAtts;
|
||||||
|
for (auto& att : before.data)
|
||||||
|
beforeAtts.push_back (att.first);
|
||||||
|
|
||||||
|
std::vector <std::string> afterAtts;
|
||||||
|
for (auto& att : after.data)
|
||||||
|
afterAtts.push_back (att.first);
|
||||||
|
|
||||||
|
std::vector <std::string> beforeOnly;
|
||||||
|
std::vector <std::string> afterOnly;
|
||||||
|
listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly);
|
||||||
|
|
||||||
|
int row;
|
||||||
|
for (auto& name : beforeOnly)
|
||||||
|
{
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, name);
|
||||||
|
view.set (row, 1, renderAttribute (name, before.get (name)), color_red);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& att : before.data)
|
||||||
|
{
|
||||||
|
std::string priorValue = before.get (att.first);
|
||||||
|
std::string currentValue = after.get (att.first);
|
||||||
|
|
||||||
|
if (currentValue != "")
|
||||||
|
{
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, att.first);
|
||||||
|
view.set (row, 1, renderAttribute (att.first, priorValue),
|
||||||
|
(priorValue != currentValue ? color_red : Color ()));
|
||||||
|
view.set (row, 2, renderAttribute (att.first, currentValue),
|
||||||
|
(priorValue != currentValue ? color_green : Color ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& name : afterOnly)
|
||||||
|
{
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, name);
|
||||||
|
view.set (row, 2, renderAttribute (name, after.get (name)), color_green);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int row;
|
||||||
|
for (auto& att : after.data)
|
||||||
|
{
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, att.first);
|
||||||
|
view.set (row, 2, renderAttribute (att.first, after.get (att.first)), color_green);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Similar to diff, but formatted as a diff for an Undo preview
|
||||||
|
Table Task::diffForUndoPatch (
|
||||||
|
const Task& after,
|
||||||
|
const Datetime& lastChange) const
|
||||||
|
{
|
||||||
|
// This style looks like this:
|
||||||
|
// --- before 2009-07-04 00:00:25.000000000 +0200
|
||||||
|
// +++ after 2009-07-04 00:00:45.000000000 +0200
|
||||||
|
//
|
||||||
|
// - name: old // att deleted
|
||||||
|
// + name:
|
||||||
|
//
|
||||||
|
// - name: old // att changed
|
||||||
|
// + name: new
|
||||||
|
//
|
||||||
|
// - name:
|
||||||
|
// + name: new // att added
|
||||||
|
//
|
||||||
|
|
||||||
|
// Set the colors.
|
||||||
|
Color color_red (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.before") : "");
|
||||||
|
Color color_green (Context::getContext ().color () ? Context::getContext ().config.get ("color.undo.after") : "");
|
||||||
|
|
||||||
|
const Task &before = *this;
|
||||||
|
|
||||||
|
// Generate table header.
|
||||||
|
Table view;
|
||||||
|
view.width (Context::getContext ().getWidth ());
|
||||||
|
view.intraPadding (2);
|
||||||
|
view.add ("");
|
||||||
|
view.add ("");
|
||||||
|
|
||||||
|
int row = view.addRow ();
|
||||||
|
view.set (row, 0, "--- previous state", color_red);
|
||||||
|
view.set (row, 1, "Undo will restore this state", color_red);
|
||||||
|
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, "+++ current state ", color_green);
|
||||||
|
view.set (row, 1, format ("Change made {1}",
|
||||||
|
lastChange.toString (Context::getContext ().config.get ("dateformat"))),
|
||||||
|
color_green);
|
||||||
|
|
||||||
|
view.addRow ();
|
||||||
|
|
||||||
|
// Add rows to table showing diffs.
|
||||||
|
std::vector <std::string> all = Context::getContext ().getColumns ();
|
||||||
|
|
||||||
|
// Now factor in the annotation attributes.
|
||||||
|
for (auto& it : before.data)
|
||||||
|
if (it.first.substr (0, 11) == "annotation_")
|
||||||
|
all.push_back (it.first);
|
||||||
|
|
||||||
|
for (auto& it : after.data)
|
||||||
|
if (it.first.substr (0, 11) == "annotation_")
|
||||||
|
all.push_back (it.first);
|
||||||
|
|
||||||
|
// Now render all the attributes.
|
||||||
|
std::sort (all.begin (), all.end ());
|
||||||
|
|
||||||
|
std::string before_att;
|
||||||
|
std::string after_att;
|
||||||
|
std::string last_att;
|
||||||
|
for (auto& a : all)
|
||||||
|
{
|
||||||
|
if (a != last_att) // Skip duplicates.
|
||||||
|
{
|
||||||
|
last_att = a;
|
||||||
|
|
||||||
|
before_att = before.get (a);
|
||||||
|
after_att = after.get (a);
|
||||||
|
|
||||||
|
// Don't report different uuid.
|
||||||
|
// Show nothing if values are the unchanged.
|
||||||
|
if (a == "uuid" ||
|
||||||
|
before_att == after_att)
|
||||||
|
{
|
||||||
|
// Show nothing - no point displaying that which did not change.
|
||||||
|
|
||||||
|
// row = view.addRow ();
|
||||||
|
// view.set (row, 0, *a + ":");
|
||||||
|
// view.set (row, 1, before_att);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attribute deleted.
|
||||||
|
else if (before_att != "" && after_att == "")
|
||||||
|
{
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, '-' + a + ':', color_red);
|
||||||
|
view.set (row, 1, before_att, color_red);
|
||||||
|
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, '+' + a + ':', color_green);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attribute added.
|
||||||
|
else if (before_att == "" && after_att != "")
|
||||||
|
{
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, '-' + a + ':', color_red);
|
||||||
|
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, '+' + a + ':', color_green);
|
||||||
|
view.set (row, 1, after_att, color_green);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attribute changed.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, '-' + a + ':', color_red);
|
||||||
|
view.set (row, 1, before_att, color_red);
|
||||||
|
|
||||||
|
row = view.addRow ();
|
||||||
|
view.set (row, 0, '+' + a + ':', color_green);
|
||||||
|
view.set (row, 1, after_att, color_green);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
20
src/Task.h
20
src/Task.h
@@ -33,6 +33,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <JSON.h>
|
#include <JSON.h>
|
||||||
|
#include <Table.h>
|
||||||
|
#include <Datetime.h>
|
||||||
|
|
||||||
class Task
|
class Task
|
||||||
{
|
{
|
||||||
@@ -60,6 +62,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
Task () = default;
|
Task () = default;
|
||||||
bool operator== (const Task&);
|
bool operator== (const Task&);
|
||||||
|
bool operator!= (const Task&);
|
||||||
Task (const std::string&);
|
Task (const std::string&);
|
||||||
Task (const json::object*);
|
Task (const json::object*);
|
||||||
|
|
||||||
@@ -74,7 +77,6 @@ public:
|
|||||||
enum dateState {dateNotDue, dateAfterToday, dateLaterToday, dateEarlierToday, dateBeforeToday};
|
enum dateState {dateNotDue, dateAfterToday, dateLaterToday, dateEarlierToday, dateBeforeToday};
|
||||||
|
|
||||||
// Public data.
|
// Public data.
|
||||||
std::map <std::string, std::string> data {};
|
|
||||||
int id {0};
|
int id {0};
|
||||||
float urgency_value {0.0};
|
float urgency_value {0.0};
|
||||||
bool recalc_urgency {true};
|
bool recalc_urgency {true};
|
||||||
@@ -100,6 +102,8 @@ public:
|
|||||||
void set (const std::string&, long long);
|
void set (const std::string&, long long);
|
||||||
void remove (const std::string&);
|
void remove (const std::string&);
|
||||||
|
|
||||||
|
bool is_empty () const;
|
||||||
|
|
||||||
#ifdef PRODUCT_TASKWARRIOR
|
#ifdef PRODUCT_TASKWARRIOR
|
||||||
bool is_ready () const;
|
bool is_ready () const;
|
||||||
bool is_due () const;
|
bool is_due () const;
|
||||||
@@ -113,6 +117,10 @@ public:
|
|||||||
bool is_overdue () const;
|
bool is_overdue () const;
|
||||||
bool is_udaPresent () const;
|
bool is_udaPresent () const;
|
||||||
bool is_orphanPresent () const;
|
bool is_orphanPresent () const;
|
||||||
|
|
||||||
|
static bool isTagAttr (const std::string&);
|
||||||
|
static bool isDepAttr (const std::string&);
|
||||||
|
static bool isAnnotationAttr (const std::string&);
|
||||||
#endif
|
#endif
|
||||||
bool is_waiting () const;
|
bool is_waiting () const;
|
||||||
|
|
||||||
@@ -150,7 +158,7 @@ public:
|
|||||||
std::vector <Task> getBlockedTasks () const;
|
std::vector <Task> getBlockedTasks () const;
|
||||||
std::vector <Task> getDependencyTasks () const;
|
std::vector <Task> getDependencyTasks () const;
|
||||||
|
|
||||||
std::vector <std::string> getUDAOrphanUUIDs () const;
|
std::vector <std::string> getUDAOrphans () const;
|
||||||
|
|
||||||
void substitute (const std::string&, const std::string&, const std::string&);
|
void substitute (const std::string&, const std::string&, const std::string&);
|
||||||
#endif
|
#endif
|
||||||
@@ -167,6 +175,8 @@ public:
|
|||||||
|
|
||||||
std::string diff (const Task& after) const;
|
std::string diff (const Task& after) const;
|
||||||
std::string diffForInfo (const Task& after, const std::string& dateformat, long& last_timestamp, const long current_timestamp) const;
|
std::string diffForInfo (const Task& after, const std::string& dateformat, long& last_timestamp, const long current_timestamp) const;
|
||||||
|
Table diffForUndoSide (const Task& after) const;
|
||||||
|
Table diffForUndoPatch (const Task& after, const Datetime& lastChange) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int determineVersion (const std::string&);
|
int determineVersion (const std::string&);
|
||||||
@@ -176,16 +186,16 @@ private:
|
|||||||
void validate_before (const std::string&, const std::string&);
|
void validate_before (const std::string&, const std::string&);
|
||||||
const std::string encode (const std::string&) const;
|
const std::string encode (const std::string&) const;
|
||||||
const std::string decode (const std::string&) const;
|
const std::string decode (const std::string&) const;
|
||||||
bool isTagAttr (const std::string&) const;
|
|
||||||
const std::string tag2Attr (const std::string&) const;
|
const std::string tag2Attr (const std::string&) const;
|
||||||
const std::string attr2Tag (const std::string&) const;
|
const std::string attr2Tag (const std::string&) const;
|
||||||
bool isDepAttr (const std::string&) const;
|
|
||||||
const std::string dep2Attr (const std::string&) const;
|
const std::string dep2Attr (const std::string&) const;
|
||||||
const std::string attr2Dep (const std::string&) const;
|
const std::string attr2Dep (const std::string&) const;
|
||||||
bool isAnnotationAttr (const std::string&) const;
|
|
||||||
void fixDependsAttribute ();
|
void fixDependsAttribute ();
|
||||||
void fixTagsAttribute ();
|
void fixTagsAttribute ();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::map <std::string, std::string> data {};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
float urgency_project () const;
|
float urgency_project () const;
|
||||||
float urgency_active () const;
|
float urgency_active () const;
|
||||||
|
|||||||
@@ -32,7 +32,9 @@
|
|||||||
#include <format.h>
|
#include <format.h>
|
||||||
#include <utf8.h>
|
#include <utf8.h>
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
|
#include <util.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
#define STRING_COLUMN_LABEL_DEP "Depends"
|
#define STRING_COLUMN_LABEL_DEP "Depends"
|
||||||
|
|
||||||
@@ -152,20 +154,59 @@ void ColumnDepends::modify (Task& task, const std::string& value)
|
|||||||
// Apply or remove dendencies in turn.
|
// Apply or remove dendencies in turn.
|
||||||
for (auto& dep : split (value, ','))
|
for (auto& dep : split (value, ','))
|
||||||
{
|
{
|
||||||
|
bool removal = false;
|
||||||
if (dep[0] == '-')
|
if (dep[0] == '-')
|
||||||
{
|
{
|
||||||
if (dep.length () == 37)
|
removal = true;
|
||||||
task.removeDependency (dep.substr (1));
|
dep = dep.substr(1);
|
||||||
else
|
|
||||||
task.removeDependency (strtol (dep.substr (1).c_str (), nullptr, 10));
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
auto hyphen = dep.find ('-');
|
||||||
|
long lower, upper; // For ID ranges
|
||||||
|
std::regex valid_uuid ("[a-f0-9]{8}([a-f0-9-]{4,28})?"); // TODO: Make more precise
|
||||||
|
|
||||||
|
// UUID
|
||||||
|
if (dep.length () >= 8 && std::regex_match (dep, valid_uuid))
|
||||||
{
|
{
|
||||||
if (dep.length () == 36)
|
// Full UUID, can be added directly
|
||||||
task.addDependency (dep);
|
if (dep.length () == 36)
|
||||||
else
|
if (removal)
|
||||||
task.addDependency (strtol (dep.c_str (), nullptr, 10));
|
task.removeDependency (dep);
|
||||||
|
else
|
||||||
|
task.addDependency (dep);
|
||||||
|
|
||||||
|
// Short UUID, need to look up full form
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Task loaded_task;
|
||||||
|
if (Context::getContext ().tdb2.get (dep, loaded_task))
|
||||||
|
if (removal)
|
||||||
|
task.removeDependency (loaded_task.get ("uuid"));
|
||||||
|
else
|
||||||
|
task.addDependency (loaded_task.get ("uuid"));
|
||||||
|
else
|
||||||
|
throw format ("Dependency could not be set - task with UUID '{1}' does not exist.", dep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// ID range
|
||||||
|
else if (dep.find ('-') != std::string::npos &&
|
||||||
|
extractLongInteger (dep.substr (0, hyphen), lower) &&
|
||||||
|
extractLongInteger (dep.substr (hyphen + 1), upper))
|
||||||
|
{
|
||||||
|
for (long i = lower; i <= upper; i++)
|
||||||
|
if (removal)
|
||||||
|
task.removeDependency (i);
|
||||||
|
else
|
||||||
|
task.addDependency (i);
|
||||||
|
}
|
||||||
|
// Simple ID
|
||||||
|
else if (extractLongInteger (dep, lower))
|
||||||
|
if (removal)
|
||||||
|
task.removeDependency (lower);
|
||||||
|
else
|
||||||
|
task.addDependency (lower);
|
||||||
|
else
|
||||||
|
throw format ("Invalid dependency value: '{1}'", dep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
#include <utf8.h>
|
#include <utf8.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
|
||||||
extern Task& contextTask;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
ColumnProject::ColumnProject ()
|
ColumnProject::ColumnProject ()
|
||||||
{
|
{
|
||||||
@@ -121,7 +119,6 @@ void ColumnProject::modify (Task& task, const std::string& value)
|
|||||||
{
|
{
|
||||||
Eval e;
|
Eval e;
|
||||||
e.addSource (domSource);
|
e.addSource (domSource);
|
||||||
contextTask = task;
|
|
||||||
|
|
||||||
Variant v;
|
Variant v;
|
||||||
e.evaluateInfixExpression (value, v);
|
e.evaluateInfixExpression (value, v);
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
#include <format.h>
|
#include <format.h>
|
||||||
#include <utf8.h>
|
#include <utf8.h>
|
||||||
|
|
||||||
extern Task& contextTask;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
ColumnRecur::ColumnRecur ()
|
ColumnRecur::ColumnRecur ()
|
||||||
{
|
{
|
||||||
@@ -108,7 +106,6 @@ void ColumnRecur::modify (Task& task, const std::string& value)
|
|||||||
{
|
{
|
||||||
Eval e;
|
Eval e;
|
||||||
e.addSource (domSource);
|
e.addSource (domSource);
|
||||||
contextTask = task;
|
|
||||||
e.evaluateInfixExpression (value, evaluatedValue);
|
e.evaluateInfixExpression (value, evaluatedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
#include <utf8.h>
|
#include <utf8.h>
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
|
|
||||||
extern Task& contextTask;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
ColumnTags::ColumnTags ()
|
ColumnTags::ColumnTags ()
|
||||||
{
|
{
|
||||||
@@ -162,7 +160,6 @@ void ColumnTags::modify (Task& task, const std::string& value)
|
|||||||
{
|
{
|
||||||
Eval e;
|
Eval e;
|
||||||
e.addSource (domSource);
|
e.addSource (domSource);
|
||||||
contextTask = task;
|
|
||||||
|
|
||||||
Variant v;
|
Variant v;
|
||||||
e.evaluateInfixExpression (value, v);
|
e.evaluateInfixExpression (value, v);
|
||||||
|
|||||||
@@ -34,8 +34,6 @@
|
|||||||
#include <Filter.h>
|
#include <Filter.h>
|
||||||
#include <format.h>
|
#include <format.h>
|
||||||
|
|
||||||
extern Task& contextTask;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
ColumnTypeDate::ColumnTypeDate ()
|
ColumnTypeDate::ColumnTypeDate ()
|
||||||
{
|
{
|
||||||
@@ -213,7 +211,6 @@ void ColumnTypeDate::modify (Task& task, const std::string& value)
|
|||||||
{
|
{
|
||||||
Eval e;
|
Eval e;
|
||||||
e.addSource (domSource);
|
e.addSource (domSource);
|
||||||
contextTask = task;
|
|
||||||
e.evaluateInfixExpression (value, evaluatedValue);
|
e.evaluateInfixExpression (value, evaluatedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,6 @@
|
|||||||
#include <Filter.h>
|
#include <Filter.h>
|
||||||
#include <format.h>
|
#include <format.h>
|
||||||
|
|
||||||
extern Task& contextTask;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
ColumnTypeDuration::ColumnTypeDuration ()
|
ColumnTypeDuration::ColumnTypeDuration ()
|
||||||
{
|
{
|
||||||
@@ -55,7 +53,6 @@ void ColumnTypeDuration::modify (Task& task, const std::string& value)
|
|||||||
{
|
{
|
||||||
Eval e;
|
Eval e;
|
||||||
e.addSource (domSource);
|
e.addSource (domSource);
|
||||||
contextTask = task;
|
|
||||||
e.evaluateInfixExpression (value, evaluatedValue);
|
e.evaluateInfixExpression (value, evaluatedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,6 @@
|
|||||||
#include <Filter.h>
|
#include <Filter.h>
|
||||||
#include <format.h>
|
#include <format.h>
|
||||||
|
|
||||||
extern Task& contextTask;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
ColumnTypeNumeric::ColumnTypeNumeric ()
|
ColumnTypeNumeric::ColumnTypeNumeric ()
|
||||||
{
|
{
|
||||||
@@ -55,7 +53,6 @@ void ColumnTypeNumeric::modify (Task& task, const std::string& value)
|
|||||||
{
|
{
|
||||||
Eval e;
|
Eval e;
|
||||||
e.addSource (domSource);
|
e.addSource (domSource);
|
||||||
contextTask = task;
|
|
||||||
e.evaluateInfixExpression (value, evaluatedValue);
|
e.evaluateInfixExpression (value, evaluatedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,6 @@
|
|||||||
|
|
||||||
#define STRING_INVALID_MOD "The '{1}' attribute does not allow a value of '{2}'."
|
#define STRING_INVALID_MOD "The '{1}' attribute does not allow a value of '{2}'."
|
||||||
|
|
||||||
extern Task& contextTask;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
ColumnTypeString::ColumnTypeString ()
|
ColumnTypeString::ColumnTypeString ()
|
||||||
{
|
{
|
||||||
@@ -67,7 +65,6 @@ void ColumnTypeString::modify (Task& task, const std::string& value)
|
|||||||
{
|
{
|
||||||
Eval e;
|
Eval e;
|
||||||
e.addSource (domSource);
|
e.addSource (domSource);
|
||||||
contextTask = task;
|
|
||||||
|
|
||||||
Variant v;
|
Variant v;
|
||||||
e.evaluateInfixExpression (value, v);
|
e.evaluateInfixExpression (value, v);
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ int CmdAdd::execute (std::string& output)
|
|||||||
{
|
{
|
||||||
// Apply the command line modifications to the new task.
|
// Apply the command line modifications to the new task.
|
||||||
Task task;
|
Task task;
|
||||||
|
|
||||||
|
// the task is empty, but DOM references can refer to earlier parts of the
|
||||||
|
// command line, e.g., `task add due:20110101 wait:due`.
|
||||||
task.modify (Task::modReplace, true);
|
task.modify (Task::modReplace, true);
|
||||||
Context::getContext ().tdb2.add (task);
|
Context::getContext ().tdb2.add (task);
|
||||||
|
|
||||||
|
|||||||
@@ -110,33 +110,43 @@ std::string CmdContext::joinWords (const std::vector <std::string>& words, unsig
|
|||||||
// Validate the context as valid for writing and fail the write context definition
|
// Validate the context as valid for writing and fail the write context definition
|
||||||
// A valid write context:
|
// A valid write context:
|
||||||
// - does not contain any operators except AND
|
// - does not contain any operators except AND
|
||||||
// - does not use modifiers
|
// - does not contain tag exclusion
|
||||||
|
// - does not use modifiers, except for 'equals' and 'is'
|
||||||
//
|
//
|
||||||
// Returns True if the context is a valid write context. If the context is
|
// Returns True if the context is a valid write context. If the context is
|
||||||
// invalid due to a wrong modifier use, the modifier string will contain the
|
// invalid due to a wrong modifier use, the modifier string will contain the
|
||||||
// first invalid modifier.
|
// first invalid modifier.
|
||||||
bool CmdContext::validateWriteContext (const std::vector <A2>& lexedArgs, std::string& modifier_token)
|
//
|
||||||
|
bool CmdContext::validateWriteContext (const std::vector <A2>& lexedArgs, std::string& reason)
|
||||||
{
|
{
|
||||||
bool contains_or = false;
|
|
||||||
bool contains_modifier = false;
|
|
||||||
|
|
||||||
for (auto &arg: lexedArgs) {
|
for (auto &arg: lexedArgs) {
|
||||||
if (arg._lextype == Lexer::Type::op)
|
if (arg._lextype == Lexer::Type::op)
|
||||||
if (arg.attribute ("raw") == "or")
|
if (arg.attribute ("raw") == "or")
|
||||||
contains_or = true;
|
{
|
||||||
|
reason = "contains the 'OR' operator";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg._lextype == Lexer::Type::pair) {
|
if (arg._lextype == Lexer::Type::pair) {
|
||||||
auto modifier = arg.attribute ("modifier");
|
auto modifier = arg.attribute ("modifier");
|
||||||
if (modifier != "" && modifier != "is" && modifier != "equals")
|
if (modifier != "" && modifier != "is" && modifier != "equals")
|
||||||
{
|
{
|
||||||
contains_modifier = true;
|
reason = format ("contains an attribute modifier '{1}'", arg.attribute ("raw"));
|
||||||
modifier_token = arg.attribute ("raw");
|
return false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg._lextype == Lexer::Type::tag) {
|
||||||
|
if (arg.attribute ("sign") == "-")
|
||||||
|
{
|
||||||
|
reason = format ("contains tag exclusion '{1}'", arg.attribute ("raw"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return not contains_or and not contains_modifier;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -211,14 +221,13 @@ void CmdContext::defineContext (const std::vector <std::string>& words, std::str
|
|||||||
! confirm (format ("The filter '{1}' matches 0 pending tasks. Do you wish to continue?", value)))
|
! confirm (format ("The filter '{1}' matches 0 pending tasks. Do you wish to continue?", value)))
|
||||||
throw std::string ("Context definition aborted.");
|
throw std::string ("Context definition aborted.");
|
||||||
|
|
||||||
std::string modifier_token = "";
|
std::string reason = "";
|
||||||
bool valid_write_context = CmdContext::validateWriteContext (lexedArgs, modifier_token);
|
bool valid_write_context = CmdContext::validateWriteContext (lexedArgs, reason);
|
||||||
|
|
||||||
if (! valid_write_context)
|
if (! valid_write_context)
|
||||||
{
|
{
|
||||||
std::stringstream warning;
|
std::stringstream warning;
|
||||||
warning << format ("The filter '{1}' is not a valid modification string, because it contains ", value)
|
warning << format ("The filter '{1}' is not a valid modification string, because it contains {2}.", value, reason)
|
||||||
<< ( modifier_token.empty () ? "the OR operator." : format ("an attribute modifier ({1}).", modifier_token) )
|
|
||||||
<< "\nAs such, value for the write context cannot be set (context will not apply on task add / task log).\n\n"
|
<< "\nAs such, value for the write context cannot be set (context will not apply on task add / task log).\n\n"
|
||||||
<< format ("Please use 'task config context.{1}.write <default mods>' to set default attribute values for new tasks in this context manually.\n\n", words[1]);
|
<< format ("Please use 'task config context.{1}.write <default mods>' to set default attribute values for new tasks in this context manually.\n\n", words[1]);
|
||||||
out << colorizeFootnote (warning.str ());
|
out << colorizeFootnote (warning.str ());
|
||||||
|
|||||||
@@ -249,20 +249,20 @@ int CmdCustom::execute (std::string& output)
|
|||||||
rc = 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inform user about the new release higlights if not presented yet
|
// Inform user about the new release highlights if not presented yet
|
||||||
if (Context::getContext ().config.get ("news.version") != "2.6.0")
|
if (Context::getContext ().config.get ("news.version") != "2.6.0")
|
||||||
{
|
{
|
||||||
std::random_device device;
|
std::random_device device;
|
||||||
std::mt19937 random_generator(device());
|
std::mt19937 random_generator(device());
|
||||||
std::uniform_int_distribution<std::mt19937::result_type> ten_percent(1, 10);
|
std::uniform_int_distribution<std::mt19937::result_type> twentyfive_percent(1, 4);
|
||||||
|
|
||||||
std::string NEWS_NOTICE = (
|
std::string NEWS_NOTICE = (
|
||||||
"Recently upgraded to 2.6.0. "
|
"Recently upgraded to 2.6.0. "
|
||||||
"Please run 'task news' to read higlights about the new release."
|
"Please run 'task news' to read highlights about the new release."
|
||||||
);
|
);
|
||||||
|
|
||||||
// 1 in 10 chance to display the message.
|
// 1 in 10 chance to display the message.
|
||||||
if (ten_percent(random_generator) == 10)
|
if (twentyfive_percent(random_generator) == 4)
|
||||||
{
|
{
|
||||||
if (Context::getContext ().verbose ("footnote"))
|
if (Context::getContext ().verbose ("footnote"))
|
||||||
Context::getContext ().footnote (NEWS_NOTICE);
|
Context::getContext ().footnote (NEWS_NOTICE);
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ int CmdDenotate::execute (std::string&)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (before.data != task.data)
|
if (before.getAnnotations () != task.getAnnotations ())
|
||||||
{
|
{
|
||||||
auto question = format ("Denotate task {1} '{2}'?",
|
auto question = format ("Denotate task {1} '{2}'?",
|
||||||
task.identifier (true),
|
task.identifier (true),
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ std::string CmdEdit::formatTask (Task task, const std::string& dateformat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UDA orphans
|
// UDA orphans
|
||||||
auto orphans = task.getUDAOrphanUUIDs ();
|
auto orphans = task.getUDAOrphans ();
|
||||||
if (orphans.size ())
|
if (orphans.size ())
|
||||||
{
|
{
|
||||||
before << "# User Defined Attribute Orphans\n";
|
before << "# User Defined Attribute Orphans\n";
|
||||||
|
|||||||
@@ -64,9 +64,8 @@ int CmdGet::execute (std::string& output)
|
|||||||
{
|
{
|
||||||
case Lexer::Type::dom:
|
case Lexer::Type::dom:
|
||||||
{
|
{
|
||||||
Task t;
|
|
||||||
Variant result;
|
Variant result;
|
||||||
if (getDOM (arg.attribute ("raw"), t, result))
|
if (getDOM (arg.attribute ("raw"), NULL, result))
|
||||||
results.emplace_back (result);
|
results.emplace_back (result);
|
||||||
else
|
else
|
||||||
results.emplace_back ("");
|
results.emplace_back ("");
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ void CmdImport::importSingleTask (json::object* obj)
|
|||||||
if (hasGeneratedEnd)
|
if (hasGeneratedEnd)
|
||||||
task.set ("end", before.get ("end"));
|
task.set ("end", before.get ("end"));
|
||||||
|
|
||||||
if (before.data != task.data)
|
if (before != task)
|
||||||
{
|
{
|
||||||
CmdModify modHelper;
|
CmdModify modHelper;
|
||||||
modHelper.checkConsistency (before, task);
|
modHelper.checkConsistency (before, task);
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ int CmdModify::execute (std::string&)
|
|||||||
Task before (task);
|
Task before (task);
|
||||||
task.modify (Task::modReplace);
|
task.modify (Task::modReplace);
|
||||||
|
|
||||||
if (before.data != task.data)
|
if (before != task)
|
||||||
{
|
{
|
||||||
// Abort if change introduces inconsistencies.
|
// Abort if change introduces inconsistencies.
|
||||||
checkConsistency(before, task);
|
checkConsistency(before, task);
|
||||||
|
|||||||
@@ -477,7 +477,7 @@ void CmdNews::version2_6_0 (std::vector<NewsItem>& items) {
|
|||||||
" hooks.location=$XDG_CONFIG_HOME/task/hooks/\n\n"
|
" hooks.location=$XDG_CONFIG_HOME/task/hooks/\n\n"
|
||||||
" Solutions in the past required symlinks or more cumbersome configuration overrides.",
|
" Solutions in the past required symlinks or more cumbersome configuration overrides.",
|
||||||
" If you configure your data.location and hooks.location as above, ensure\n"
|
" If you configure your data.location and hooks.location as above, ensure\n"
|
||||||
" that the XFG_DATA_HOME and XDG_CONFIG_HOME environment variables are set,\n"
|
" that the XDG_DATA_HOME and XDG_CONFIG_HOME environment variables are set,\n"
|
||||||
" otherwise they're going to expand to empty string. Alternatively you can\n"
|
" otherwise they're going to expand to empty string. Alternatively you can\n"
|
||||||
" hardcode the desired paths on your system."
|
" hardcode the desired paths on your system."
|
||||||
);
|
);
|
||||||
@@ -575,14 +575,15 @@ int CmdNews::execute (std::string& output)
|
|||||||
std::stringstream outro;
|
std::stringstream outro;
|
||||||
outro << underline.colorize (bold.colorize ("Taskwarrior crowdfunding\n"));
|
outro << underline.colorize (bold.colorize ("Taskwarrior crowdfunding\n"));
|
||||||
outro << format (
|
outro << format (
|
||||||
"Taskwarrior has been in development for {1} years and its continued survival\n"
|
"Taskwarrior has been in development for {1} years but its survival\n"
|
||||||
"depends on your support!\n\n"
|
"depends on your support!\n\n"
|
||||||
"Please consider joining our {2} fundraiser and visit crowdfunding page at:\n\n",
|
"Please consider joining our {2} fundraiser to help us fund maintenance\n"
|
||||||
|
"and development of new features:\n\n",
|
||||||
std::lround (static_cast<float>(development_time.days ()) / 365.25),
|
std::lround (static_cast<float>(development_time.days ()) / 365.25),
|
||||||
now.year ()
|
now.year ()
|
||||||
);
|
);
|
||||||
outro << bold.colorize(" https://github.com/sponsors/GothenburgBitFactory/\n\n");
|
outro << bold.colorize(" https://github.com/sponsors/GothenburgBitFactory/\n\n");
|
||||||
outro << "Interesting perks are available for our sponsors.\nSponsorship directly translates to more development time spent on the project.\n";
|
outro << "Perks are available for our sponsors.\n";
|
||||||
|
|
||||||
std::cout << outro.str ();
|
std::cout << outro.str ();
|
||||||
|
|
||||||
@@ -615,7 +616,11 @@ int CmdNews::execute (std::string& output)
|
|||||||
autoComplete (answer, options, matches, 1); // Hard-coded 1.
|
autoComplete (answer, options, matches, 1); // Hard-coded 1.
|
||||||
|
|
||||||
if (matches.size () == 1 && matches[0] == "yes")
|
if (matches.size () == 1 && matches[0] == "yes")
|
||||||
|
#if defined (DARWIN)
|
||||||
|
system ("open 'https://github.com/sponsors/GothenburgBitFactory/'");
|
||||||
|
#else
|
||||||
system ("xdg-open 'https://github.com/sponsors/GothenburgBitFactory/'");
|
system ("xdg-open 'https://github.com/sponsors/GothenburgBitFactory/'");
|
||||||
|
#endif
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
@@ -624,7 +629,7 @@ int CmdNews::execute (std::string& output)
|
|||||||
|
|
||||||
if (! full_summary && major_items)
|
if (! full_summary && major_items)
|
||||||
Context::getContext ().footnote (format (
|
Context::getContext ().footnote (format (
|
||||||
"Only major higlights were displayed ({1} out of {2} total).\n"
|
"Only major highlights were displayed ({1} out of {2} total).\n"
|
||||||
"If you're interested in more release highlights, run 'task news {3} minor'.",
|
"If you're interested in more release highlights, run 'task news {3} minor'.",
|
||||||
items.size (),
|
items.size (),
|
||||||
total_highlights,
|
total_highlights,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <format.h>
|
#include <format.h>
|
||||||
#include <shared.h>
|
#include <shared.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
#include <Task.h>
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
CmdUDAs::CmdUDAs ()
|
CmdUDAs::CmdUDAs ()
|
||||||
@@ -133,10 +134,8 @@ int CmdUDAs::execute (std::string& output)
|
|||||||
std::map <std::string, int> orphans;
|
std::map <std::string, int> orphans;
|
||||||
for (auto& i : filtered)
|
for (auto& i : filtered)
|
||||||
{
|
{
|
||||||
for (auto& att : i.data)
|
for (auto& att : i.getUDAOrphans ())
|
||||||
if (att.first.substr (0, 11) != "annotation_" &&
|
orphans[att]++;
|
||||||
Context::getContext ().columns.find (att.first) == Context::getContext ().columns.end ())
|
|
||||||
orphans[att.first]++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (orphans.size ())
|
if (orphans.size ())
|
||||||
|
|||||||
Submodule src/libshared updated: 945d0fb9a1...072e0e0cb9
@@ -29,6 +29,7 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <Context.h>
|
#include <Context.h>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int main (int argc, const char** argv)
|
int main (int argc, const char** argv)
|
||||||
@@ -64,6 +65,11 @@ int main (int argc, const char** argv)
|
|||||||
status = -3;
|
status = -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
catch (const std::regex_error& e)
|
||||||
|
{
|
||||||
|
std::cout << "regex_error caught: " << e.what() << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
std::cerr << "Unknown error. Please report.\n";
|
std::cerr << "Unknown error. Please report.\n";
|
||||||
|
|||||||
@@ -189,10 +189,9 @@ static void colorizeKeyword (Task& task, const std::string& rule, const Color& b
|
|||||||
// first match.
|
// first match.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (const auto& att : task.data)
|
for (const auto& att : task.getAnnotations ())
|
||||||
{
|
{
|
||||||
if (! att.first.compare (0, 11, "annotation_", 11) &&
|
if (find (att.second, rule.substr (14), sensitive) != std::string::npos)
|
||||||
find (att.second, rule.substr (14), sensitive) != std::string::npos)
|
|
||||||
{
|
{
|
||||||
applyColor (base, c, merge);
|
applyColor (base, c, merge);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <cmake.h>
|
#include <cmake.h>
|
||||||
|
#include <format.h>
|
||||||
#include <shared.h>
|
#include <shared.h>
|
||||||
// If <iostream> is included, put it after <stdio.h>, because it includes
|
// If <iostream> is included, put it after <stdio.h>, because it includes
|
||||||
// <stdio.h>, and therefore would ignore the _WITH_GETLINE.
|
// <stdio.h>, and therefore would ignore the _WITH_GETLINE.
|
||||||
@@ -309,3 +310,10 @@ void setHeaderUnderline (Table& table)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Perform strtol on a string and check if the extracted value matches.
|
||||||
|
//
|
||||||
|
bool extractLongInteger (const std::string& input, long& output)
|
||||||
|
{
|
||||||
|
output = strtol (input.c_str (), nullptr, 10);
|
||||||
|
return (format ("{1}", output) == input);
|
||||||
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ const std::vector <std::string> extractParents (
|
|||||||
bool nontrivial (const std::string&);
|
bool nontrivial (const std::string&);
|
||||||
const char* optionalBlankLine ();
|
const char* optionalBlankLine ();
|
||||||
void setHeaderUnderline (Table&);
|
void setHeaderUnderline (Table&);
|
||||||
|
bool extractLongInteger (const std::string&, long&);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
1
test/.gitignore
vendored
1
test/.gitignore
vendored
@@ -34,5 +34,6 @@ variant_partial.t
|
|||||||
variant_subtract.t
|
variant_subtract.t
|
||||||
variant_xor.t
|
variant_xor.t
|
||||||
view.t
|
view.t
|
||||||
|
tw-2689.t
|
||||||
|
|
||||||
json_test
|
json_test
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ include_directories (${CMAKE_SOURCE_DIR}
|
|||||||
${CMAKE_SOURCE_DIR}/test
|
${CMAKE_SOURCE_DIR}/test
|
||||||
${TASK_INCLUDE_DIRS})
|
${TASK_INCLUDE_DIRS})
|
||||||
|
|
||||||
set (test_SRCS col.t dom.t eval.t lexer.t t.t tdb2.t util.t variant_add.t variant_and.t variant_cast.t variant_divide.t variant_equal.t variant_exp.t variant_gt.t variant_gte.t variant_inequal.t variant_lt.t variant_lte.t variant_match.t variant_math.t variant_modulo.t variant_multiply.t variant_nomatch.t variant_not.t variant_or.t variant_partial.t variant_subtract.t variant_xor.t view.t)
|
set (test_SRCS col.t dom.t eval.t lexer.t t.t tw-2689.t tdb2.t util.t variant_add.t variant_and.t variant_cast.t variant_divide.t variant_equal.t variant_exp.t variant_gt.t variant_gte.t variant_inequal.t variant_lt.t variant_lte.t variant_match.t variant_math.t variant_modulo.t variant_multiply.t variant_nomatch.t variant_not.t variant_or.t variant_partial.t variant_subtract.t variant_xor.t view.t)
|
||||||
|
|
||||||
add_custom_target (test ./run_all --verbose
|
add_custom_target (test ./run_all --verbose
|
||||||
DEPENDS ${test_SRCS} task_executable
|
DEPENDS ${test_SRCS} task_executable
|
||||||
|
|||||||
@@ -121,15 +121,15 @@ class ContextManagementTest(TestCase):
|
|||||||
self.assertEqual(self.t.taskrc_content.count(context_line), 1)
|
self.assertEqual(self.t.taskrc_content.count(context_line), 1)
|
||||||
|
|
||||||
# Assert the config does not contain write context definition
|
# Assert the config does not contain write context definition
|
||||||
context_line = 'context.work.write=due.before:today\n'
|
context_line = 'context.urgent.write=due.before:today\n'
|
||||||
self.assertNotIn(context_line, self.t.taskrc_content)
|
self.assertNotIn(context_line, self.t.taskrc_content)
|
||||||
|
|
||||||
# Assert that the write context was not set at all
|
# Assert that the write context was not set at all
|
||||||
self.assertNotIn('context.work.write=', self.t.taskrc_content)
|
self.assertNotIn('context.urgent.write=', self.t.taskrc_content)
|
||||||
|
|
||||||
# Assert that legacy style was not used
|
# Assert that legacy style was not used
|
||||||
# Assert the config contains read context definition
|
# Assert the config contains read context definition
|
||||||
context_line = 'context.work=due.before:today\n'
|
context_line = 'context.urgent=due.before:today\n'
|
||||||
self.assertNotIn(context_line, self.t.taskrc_content)
|
self.assertNotIn(context_line, self.t.taskrc_content)
|
||||||
|
|
||||||
def test_context_define_invalid_for_write_due_to_operator(self):
|
def test_context_define_invalid_for_write_due_to_operator(self):
|
||||||
@@ -146,15 +146,40 @@ class ContextManagementTest(TestCase):
|
|||||||
self.assertEqual(self.t.taskrc_content.count(context_line), 1)
|
self.assertEqual(self.t.taskrc_content.count(context_line), 1)
|
||||||
|
|
||||||
# Assert the config does not contain write context definition
|
# Assert the config does not contain write context definition
|
||||||
context_line = 'context.work.write=due:today or +next\n'
|
context_line = 'context.urgent.write=due:today or +next\n'
|
||||||
self.assertNotIn(context_line, self.t.taskrc_content)
|
self.assertNotIn(context_line, self.t.taskrc_content)
|
||||||
|
|
||||||
# Assert that the write context was not set at all
|
# Assert that the write context was not set at all
|
||||||
self.assertNotIn('context.work.write=', self.t.taskrc_content)
|
self.assertNotIn('context.urgent.write=', self.t.taskrc_content)
|
||||||
|
|
||||||
# Assert that legacy style was not used
|
# Assert that legacy style was not used
|
||||||
# Assert the config contains read context definition
|
# Assert the config contains read context definition
|
||||||
context_line = 'context.work=due:today or +next\n'
|
context_line = 'context.urgent=due:today or +next\n'
|
||||||
|
self.assertNotIn(context_line, self.t.taskrc_content)
|
||||||
|
|
||||||
|
def test_context_define_invalid_for_write_due_to_tag_exclusion(self):
|
||||||
|
"""Test definition of a context that is not a valid write context because it contains a tag exclusion."""
|
||||||
|
self.t.config("confirmation", "off")
|
||||||
|
code, out, err = self.t('context define nowork due:today -work')
|
||||||
|
self.assertIn("Context 'nowork' defined", out)
|
||||||
|
|
||||||
|
# Assert the config contains read context definition
|
||||||
|
context_line = 'context.nowork.read=due:today -work\n'
|
||||||
|
self.assertIn(context_line, self.t.taskrc_content)
|
||||||
|
|
||||||
|
# Assert that it contains the definition only once
|
||||||
|
self.assertEqual(self.t.taskrc_content.count(context_line), 1)
|
||||||
|
|
||||||
|
# Assert the config does not contain write context definition
|
||||||
|
context_line = 'context.nowork.write=due:today -work\n'
|
||||||
|
self.assertNotIn(context_line, self.t.taskrc_content)
|
||||||
|
|
||||||
|
# Assert that the write context was not set at all
|
||||||
|
self.assertNotIn('context.nowork.write=', self.t.taskrc_content)
|
||||||
|
|
||||||
|
# Assert that legacy style was not used
|
||||||
|
# Assert the config contains read context definition
|
||||||
|
context_line = 'context.nowork=due:today -work\n'
|
||||||
self.assertNotIn(context_line, self.t.taskrc_content)
|
self.assertNotIn(context_line, self.t.taskrc_content)
|
||||||
|
|
||||||
def test_context_delete(self):
|
def test_context_delete(self):
|
||||||
@@ -206,6 +231,16 @@ class ContextManagementTest(TestCase):
|
|||||||
self.assertEqual(len(list(filter(contains_work, out.splitlines()))), 1)
|
self.assertEqual(len(list(filter(contains_work, out.splitlines()))), 1)
|
||||||
self.assertEqual(len(list(filter(contains_home, out.splitlines()))), 1)
|
self.assertEqual(len(list(filter(contains_home, out.splitlines()))), 1)
|
||||||
|
|
||||||
|
def test_context_list_legacy(self):
|
||||||
|
"""Test the determination of legacy context definition."""
|
||||||
|
self.t('config context.old project:Old', input='y\n')
|
||||||
|
self.t('context old')
|
||||||
|
code, out, err = self.t('context list')
|
||||||
|
|
||||||
|
# Assert that "old" context has only the read component defined
|
||||||
|
self.assertRegex(out, r'read\s+project:Old\s+yes')
|
||||||
|
self.assertRegex(out, r'write\s+yes')
|
||||||
|
|
||||||
def test_context_initially_empty(self):
|
def test_context_initially_empty(self):
|
||||||
"""Test that no context is set initially."""
|
"""Test that no context is set initially."""
|
||||||
self.t('context define work project:Work', input='y\ny\n')
|
self.t('context define work project:Work', input='y\ny\n')
|
||||||
|
|||||||
@@ -145,6 +145,22 @@ class TestDependencies(TestCase):
|
|||||||
code, out, err = self.t("_get 1.tags.BLOCKED")
|
code, out, err = self.t("_get 1.tags.BLOCKED")
|
||||||
self.assertEqual("\n", out)
|
self.assertEqual("\n", out)
|
||||||
|
|
||||||
|
def test_dependency_bulk_removal(self):
|
||||||
|
"""2655: Check that one can bulk undepend a task"""
|
||||||
|
self.t("add three")
|
||||||
|
self.t("1 modify dep:2,3")
|
||||||
|
|
||||||
|
code, out, err = self.t("_get 1.tags.BLOCKED")
|
||||||
|
self.assertEqual("BLOCKED\n", out)
|
||||||
|
|
||||||
|
self.t("1 modify depends:")
|
||||||
|
|
||||||
|
code, out, err = self.t("_get 1.tags.BLOCKED")
|
||||||
|
self.assertEqual("\n", out)
|
||||||
|
|
||||||
|
code, out, err = self.t("_get 1.depends")
|
||||||
|
self.assertEqual("\n", out)
|
||||||
|
|
||||||
def test_chain_repair(self):
|
def test_chain_repair(self):
|
||||||
"""Check that a broken chain is repaired"""
|
"""Check that a broken chain is repaired"""
|
||||||
self.t("add three")
|
self.t("add three")
|
||||||
@@ -169,7 +185,6 @@ class TestDependencies(TestCase):
|
|||||||
self.assertNotIn("Would you like the dependency chain fixed?", out)
|
self.assertNotIn("Would you like the dependency chain fixed?", out)
|
||||||
self.assertIn("Deleted 1 task", out)
|
self.assertIn("Deleted 1 task", out)
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_id_range_dep(self):
|
def test_id_range_dep(self):
|
||||||
"""Check that an ID range can be used for deps"""
|
"""Check that an ID range can be used for deps"""
|
||||||
self.t("add three")
|
self.t("add three")
|
||||||
@@ -178,7 +193,7 @@ class TestDependencies(TestCase):
|
|||||||
self.t("3 modify dep:1-2")
|
self.t("3 modify dep:1-2")
|
||||||
code, out, err = self.t("_get 1.tags.BLOCKING")
|
code, out, err = self.t("_get 1.tags.BLOCKING")
|
||||||
self.assertEqual("BLOCKING\n", out)
|
self.assertEqual("BLOCKING\n", out)
|
||||||
code, out, err = self.t("_get 2.tag.BLOCKING")
|
code, out, err = self.t("_get 2.tags.BLOCKING")
|
||||||
self.assertEqual("BLOCKING\n", out)
|
self.assertEqual("BLOCKING\n", out)
|
||||||
|
|
||||||
def test_id_uuid_dep(self):
|
def test_id_uuid_dep(self):
|
||||||
@@ -196,6 +211,22 @@ class TestDependencies(TestCase):
|
|||||||
code, out, err = self.t("3 modify dep:-1,-%s" % uuid)
|
code, out, err = self.t("3 modify dep:-1,-%s" % uuid)
|
||||||
self.assertIn("Modifying task 3 'three'.", out)
|
self.assertIn("Modifying task 3 'three'.", out)
|
||||||
|
|
||||||
|
def test_id_uuid_short_dep(self):
|
||||||
|
"""Check that short UUIDs are usable for deps"""
|
||||||
|
|
||||||
|
# Get 2.uuid
|
||||||
|
code, out, err = self.t("_get 2.uuid")
|
||||||
|
short_uuid = out.strip().split("-")[0]
|
||||||
|
|
||||||
|
# Add a mix of IDs and UUID
|
||||||
|
code, out, err = self.t("add three dep:%s" % short_uuid)
|
||||||
|
self.assertIn("Created task 3.", out)
|
||||||
|
|
||||||
|
# Remove a mix of IЅs and UUID
|
||||||
|
code, out, err = self.t("3 modify dep:-%s" % short_uuid)
|
||||||
|
self.assertIn("Modifying task 3 'three'.", out)
|
||||||
|
|
||||||
|
|
||||||
class TestBug697(TestCase):
|
class TestBug697(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Executed before each test in the class"""
|
"""Executed before each test in the class"""
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
FROM centos:8
|
FROM centos:8
|
||||||
|
|
||||||
|
# Fix missing repo metadata
|
||||||
|
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-Linux-*
|
||||||
|
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-Linux-*
|
||||||
|
|
||||||
RUN dnf update -y
|
RUN dnf update -y
|
||||||
RUN dnf install python3 git gcc gcc-c++ make gnutls-devel libuuid-devel glibc-langpack-en -y
|
RUN dnf install python3 git gcc gcc-c++ make gnutls-devel libuuid-devel glibc-langpack-en -y
|
||||||
RUN dnf install epel-release -y
|
RUN dnf install epel-release -y
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM fedora:31
|
FROM fedora:35
|
||||||
|
|
||||||
RUN dnf update -y
|
RUN dnf update -y
|
||||||
RUN dnf install python3 git gcc gcc-c++ cmake make gnutls-devel libuuid-devel libfaketime glibc-langpack-en -y
|
RUN dnf install python3 git gcc gcc-c++ cmake make gnutls-devel libuuid-devel libfaketime glibc-langpack-en -y
|
||||||
27
test/docker/ubuntu1604
Normal file
27
test/docker/ubuntu1604
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y build-essential cmake git uuid-dev libgnutls28-dev faketime locales python3
|
||||||
|
|
||||||
|
# Setup language environment
|
||||||
|
RUN locale-gen en_US.UTF-8
|
||||||
|
ENV LC_ALL en_US.UTF-8
|
||||||
|
ENV LANG en_US.UTF-8
|
||||||
|
ENV LANGUAGE en_US.UTF-8
|
||||||
|
|
||||||
|
# Setup taskwarrior
|
||||||
|
ADD . /root/code/
|
||||||
|
WORKDIR /root/code/
|
||||||
|
RUN git clean -dfx
|
||||||
|
RUN git submodule init
|
||||||
|
RUN git submodule update
|
||||||
|
RUN cmake -DCMAKE_BUILD_TYPE=debug .
|
||||||
|
RUN make -j2
|
||||||
|
RUN make install
|
||||||
|
RUN task --version
|
||||||
|
|
||||||
|
# Setup tests
|
||||||
|
WORKDIR /root/code/test/
|
||||||
|
RUN make
|
||||||
|
|
||||||
|
CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems"]
|
||||||
27
test/docker/ubuntu2110
Normal file
27
test/docker/ubuntu2110
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
FROM ubuntu:21.10
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN DEBIAN_FRONTEND="noninteractive" apt-get install -y build-essential cmake git uuid-dev libgnutls28-dev faketime locales python3
|
||||||
|
|
||||||
|
# Setup language environment
|
||||||
|
RUN locale-gen en_US.UTF-8
|
||||||
|
ENV LC_ALL en_US.UTF-8
|
||||||
|
ENV LANG en_US.UTF-8
|
||||||
|
ENV LANGUAGE en_US.UTF-8
|
||||||
|
|
||||||
|
# Setup taskwarrior
|
||||||
|
ADD . /root/code/
|
||||||
|
WORKDIR /root/code/
|
||||||
|
RUN git clean -dfx
|
||||||
|
RUN git submodule init
|
||||||
|
RUN git submodule update
|
||||||
|
RUN cmake -DCMAKE_BUILD_TYPE=debug .
|
||||||
|
RUN make -j8
|
||||||
|
RUN make install
|
||||||
|
RUN task --version
|
||||||
|
|
||||||
|
# Setup tests
|
||||||
|
WORKDIR /root/code/test/
|
||||||
|
RUN make -j8
|
||||||
|
|
||||||
|
CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems"]
|
||||||
48
test/ids.t
48
test/ids.t
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
# Ensure python finds the local simpletap module
|
# Ensure python finds the local simpletap module
|
||||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||||
@@ -117,6 +118,53 @@ class TestIDMisParse(TestCase):
|
|||||||
self.assertNotIn("three", out)
|
self.assertNotIn("three", out)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIDRangeParsing(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
"""Executed before each test in the class"""
|
||||||
|
self.t = Task()
|
||||||
|
|
||||||
|
def generate_tasks(self, n):
|
||||||
|
"""Generates n tasks for testing purposes"""
|
||||||
|
with tempfile.NamedTemporaryFile(mode='w') as f:
|
||||||
|
f.write('\n'.join([f'{{"description": "test task {i+1}"}}' for i in range(n)]))
|
||||||
|
f.flush()
|
||||||
|
code, out, err = self.t(f'import {f.name}')
|
||||||
|
|
||||||
|
def test_single_digit_range(self):
|
||||||
|
"""Test that parsing single digit ID range works"""
|
||||||
|
self.generate_tasks(20)
|
||||||
|
code, out, err = self.t("4-6 count")
|
||||||
|
self.assertEqual("3", out.strip())
|
||||||
|
|
||||||
|
def test_double_digit_range(self):
|
||||||
|
"""Test that parsing double digit ID range works"""
|
||||||
|
self.generate_tasks(30)
|
||||||
|
code, out, err = self.t("14-26 count")
|
||||||
|
self.assertEqual("13", out.strip())
|
||||||
|
|
||||||
|
def test_triple_digit_range(self):
|
||||||
|
"""Test that parsing triple digit ID range works"""
|
||||||
|
self.generate_tasks(150)
|
||||||
|
code, out, err = self.t("110-128 count")
|
||||||
|
self.assertEqual("19", out.strip())
|
||||||
|
|
||||||
|
def test_quadruple_digit_range(self):
|
||||||
|
"""Test that parsing four digit ID range works"""
|
||||||
|
self.generate_tasks(1200)
|
||||||
|
|
||||||
|
# Full range
|
||||||
|
code, out, err = self.t("1100-1189 count")
|
||||||
|
self.assertEqual("90", out.strip())
|
||||||
|
|
||||||
|
# Partially existing range, 1200 is the last ID
|
||||||
|
code, out, err = self.t("1100-1289 count")
|
||||||
|
self.assertEqual("101", out.strip())
|
||||||
|
|
||||||
|
# Also if the range resembles time
|
||||||
|
code, out, err = self.t("1100-1140 count")
|
||||||
|
self.assertEqual("41", out.strip())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from simpletap import TAPTestRunner
|
from simpletap import TAPTestRunner
|
||||||
unittest.main(testRunner=TAPTestRunner())
|
unittest.main(testRunner=TAPTestRunner())
|
||||||
|
|||||||
@@ -500,17 +500,9 @@ class TestBug1900(TestCase):
|
|||||||
|
|
||||||
def test_project_eval(self):
|
def test_project_eval(self):
|
||||||
"""1900: Project name can contain dashes"""
|
"""1900: Project name can contain dashes"""
|
||||||
self.t("add foo project:due-b")
|
self.t("add foo project:doo-bee")
|
||||||
code, out, err = self.t("_get 1.project")
|
code, out, err = self.t("_get 1.project")
|
||||||
self.assertEqual("due-b\n", out)
|
self.assertEqual("doo-bee\n", out)
|
||||||
|
|
||||||
self.t("add foo project:scheduled-home")
|
|
||||||
code, out, err = self.t("_get 2.project")
|
|
||||||
self.assertEqual("scheduled-home\n", out)
|
|
||||||
|
|
||||||
self.t("add foo project:entry-work")
|
|
||||||
code, out, err = self.t("_get 3.project")
|
|
||||||
self.assertEqual("entry-work\n", out)
|
|
||||||
|
|
||||||
|
|
||||||
class TestBug1904(TestCase):
|
class TestBug1904(TestCase):
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ class TestRecurrenceWeekdays(TestCase):
|
|||||||
# The due dates should be Friday and Monday, three days apart,
|
# The due dates should be Friday and Monday, three days apart,
|
||||||
# having skipped the weekend.
|
# having skipped the weekend.
|
||||||
# Note: On daylight savings in the fall, this '3' becomes '2.9583'.
|
# Note: On daylight savings in the fall, this '3' becomes '2.9583'.
|
||||||
self.assertTrue(int(monday.strip()) - int(friday.strip()) >= 2)
|
# Note: when monday is next year, friday+2 > 365
|
||||||
|
self.assertTrue(int(monday.strip()) >= (int(friday.strip()) + 2) % 365)
|
||||||
|
|
||||||
|
|
||||||
class TestRecurrenceUntil(TestCase):
|
class TestRecurrenceUntil(TestCase):
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ TODO Task::decode
|
|||||||
test.is (task.get ("three"), "four", "three=four");
|
test.is (task.get ("three"), "four", "three=four");
|
||||||
|
|
||||||
// Task::set
|
// Task::set
|
||||||
task.data.clear ();
|
task = Task();
|
||||||
task.set ("name", "value");
|
task.set ("name", "value");
|
||||||
test.is (task.composeF4 (), "[name:\"value\"]", "Task::set");
|
test.is (task.composeF4 (), "[name:\"value\"]", "Task::set");
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ TODO Task::decode
|
|||||||
test.is (task.composeF4 (), "[name:\"value\"]", "Task::remove");
|
test.is (task.composeF4 (), "[name:\"value\"]", "Task::remove");
|
||||||
|
|
||||||
// Task::all
|
// Task::all
|
||||||
test.is (task.data.size (), (size_t)1, "Task::all size");
|
test.is (task.all ().size (), (size_t)1, "Task::all size");
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|||||||
18
test/tag.t
18
test/tag.t
@@ -36,13 +36,10 @@ from basetest import Task, TestCase
|
|||||||
|
|
||||||
|
|
||||||
class TestTags(TestCase):
|
class TestTags(TestCase):
|
||||||
@classmethod
|
|
||||||
def setUpClass(cls):
|
|
||||||
"""Executed once before any test in the class"""
|
|
||||||
cls.t = Task()
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Executed before each test in the class"""
|
"""Executed before each test in the class"""
|
||||||
|
self.t = Task()
|
||||||
|
|
||||||
def split_tags(self, tags):
|
def split_tags(self, tags):
|
||||||
return sorted(tags.strip().split(','))
|
return sorted(tags.strip().split(','))
|
||||||
@@ -81,6 +78,19 @@ class TestTags(TestCase):
|
|||||||
code, out, err = self.t("1 modify -missing")
|
code, out, err = self.t("1 modify -missing")
|
||||||
self.assertIn("Modified 0 tasks", out)
|
self.assertIn("Modified 0 tasks", out)
|
||||||
|
|
||||||
|
def test_tag_bulk_removal(self):
|
||||||
|
"""2655: Test bulk removal of tags"""
|
||||||
|
self.t("add +one This +two is a test +three")
|
||||||
|
code, out, err = self.t("_get 1.tags")
|
||||||
|
self.assertEqual(
|
||||||
|
sorted(["one", "two", "three"]),
|
||||||
|
self.split_tags(out))
|
||||||
|
|
||||||
|
# Remove all tags in bulk
|
||||||
|
self.t("1 modify tags:")
|
||||||
|
code, out, err = self.t("_get 1.tags")
|
||||||
|
self.assertEqual("\n", out)
|
||||||
|
|
||||||
|
|
||||||
class TestVirtualTags(TestCase):
|
class TestVirtualTags(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
27
test/test_certs/api.cert.pem
Normal file
27
test/test_certs/api.cert.pem
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIErDCCAxSgAwIBAgIUImT6dvD09I4yGowOKIyYCFwCU/IwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwdDEVMBMGA1UEAxMMbG9jYWxob3N0IENBMR4wHAYDVQQKDBVHw7Z0ZWJvcmcg
|
||||||
|
Qml0IEZhY3RvcnkxEjAQBgNVBAcMCUfDtnRlYm9yZzEaMBgGA1UECAwRVsOkc3Ry
|
||||||
|
YSBHw7Z0YWxhbmQxCzAJBgNVBAYTAlNFMB4XDTE5MDMwMzE1MDAzOVoXDTIwMDMw
|
||||||
|
MjE1MDAzOVowNDESMBAGA1UEAxMJbG9jYWxob3N0MR4wHAYDVQQKDBVHw7Z0ZWJv
|
||||||
|
cmcgQml0IEZhY3RvcnkwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDm
|
||||||
|
SHBv3zILItaJrG+3y7dWgvsX6X3FzLVXOrhFOBNbsrHSsktt20yHZhofoelkgtlc
|
||||||
|
kBsft5GUYGEBZuJIIFcOvpbXXTz/cYge8WhpcFo64APNc7zxykaTeIHMmEqjxqtO
|
||||||
|
efyOmuEyWya2XbCA4aZ6emyirkem952wBJNYLIWoy53YQ79dFvH2SOWKPlXCa1B/
|
||||||
|
ih7b9qYZE2XHoLQSbLCJqDWoQTxmOe13/1aKnJIuIy/igGsM7ygmphG4kzvyfbiA
|
||||||
|
o+Nd50USVeeeF8P+X2YZfXFKmbzJTg4q6UUB4vqn4XegW065eIyN1Xw3Z/l8CiP0
|
||||||
|
G27iuk/ZfRuz00+d9oTG5OtvyCMcc/kDI4Db1Xu9C5z9UpF5IIM85Ky91YxMMqPu
|
||||||
|
ChQQoDXJ7mdtC7zRvn6t0erMVbpaqyXxKll/ybPFAZYIgV7jtSPPJDAcTsCZQLRc
|
||||||
|
VcggScYSiWkRgW+DKsECczo++6577q++cyRBtENPOXUZ6J74eKBHizYda0chVzcC
|
||||||
|
AwEAAaN2MHQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAjAPBgNV
|
||||||
|
HQ8BAf8EBQMDB6AAMB0GA1UdDgQWBBQuQdj0wAQOzML5AQ13xsb4E8Vh9DAfBgNV
|
||||||
|
HSMEGDAWgBSmHbkkwFmCruE7I7TSI0SlD1hLiDANBgkqhkiG9w0BAQsFAAOCAYEA
|
||||||
|
CD77JzLXB0YbgJrrkotw0I8rmrb8mw0tHkDGH70UyG6VhEt3vaYcYioxs3TIo23U
|
||||||
|
dhOTApGdHzjrZePa0y2Kh7YtnPLAUml6hHTATE1D7Hufdtamd56URgBrEylKkpKl
|
||||||
|
6UnwHWzlkdRWzPRo+RD9RMBzTUMiooZaP9zzzYQNEfCmMTlHqztOLPNfFR6kFLr5
|
||||||
|
Xnc04EV/hvkByoBmo9/i4qAa3AW4y6cUHYpxVS9nBF2h364aDIIA0mn9hEewRJBq
|
||||||
|
3odng4d+e9v9b+G1ExQXM3en39REo/b73P2VATZyMxmq5gxL1OmbOa13A+S2D0Og
|
||||||
|
OkqNq6vzRhTxLbkqc0fjKv2TUFrnYCsCROvrMF+TAN0mG4NcfgeeziBTmHJq0D3I
|
||||||
|
LNTRMU/BoMYG3wGu0BUak83a9JhwViR3o0iFnctuMbD2Mz6QOawgWz8BuTcwIur6
|
||||||
|
USeERs3+G2XX499wWswGgWK5JGZ1skD1PiRsZfuaCMJHBiWolv4/G+My5IYg6B8a
|
||||||
|
-----END CERTIFICATE-----
|
||||||
182
test/test_certs/api.key.pem
Normal file
182
test/test_certs/api.key.pem
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
Public Key Info:
|
||||||
|
Public Key Algorithm: RSA
|
||||||
|
Key Security Level: High (3072 bits)
|
||||||
|
|
||||||
|
modulus:
|
||||||
|
00:e6:48:70:6f:df:32:0b:22:d6:89:ac:6f:b7:cb:b7
|
||||||
|
56:82:fb:17:e9:7d:c5:cc:b5:57:3a:b8:45:38:13:5b
|
||||||
|
b2:b1:d2:b2:4b:6d:db:4c:87:66:1a:1f:a1:e9:64:82
|
||||||
|
d9:5c:90:1b:1f:b7:91:94:60:61:01:66:e2:48:20:57
|
||||||
|
0e:be:96:d7:5d:3c:ff:71:88:1e:f1:68:69:70:5a:3a
|
||||||
|
e0:03:cd:73:bc:f1:ca:46:93:78:81:cc:98:4a:a3:c6
|
||||||
|
ab:4e:79:fc:8e:9a:e1:32:5b:26:b6:5d:b0:80:e1:a6
|
||||||
|
7a:7a:6c:a2:ae:47:a6:f7:9d:b0:04:93:58:2c:85:a8
|
||||||
|
cb:9d:d8:43:bf:5d:16:f1:f6:48:e5:8a:3e:55:c2:6b
|
||||||
|
50:7f:8a:1e:db:f6:a6:19:13:65:c7:a0:b4:12:6c:b0
|
||||||
|
89:a8:35:a8:41:3c:66:39:ed:77:ff:56:8a:9c:92:2e
|
||||||
|
23:2f:e2:80:6b:0c:ef:28:26:a6:11:b8:93:3b:f2:7d
|
||||||
|
b8:80:a3:e3:5d:e7:45:12:55:e7:9e:17:c3:fe:5f:66
|
||||||
|
19:7d:71:4a:99:bc:c9:4e:0e:2a:e9:45:01:e2:fa:a7
|
||||||
|
e1:77:a0:5b:4e:b9:78:8c:8d:d5:7c:37:67:f9:7c:0a
|
||||||
|
23:f4:1b:6e:e2:ba:4f:d9:7d:1b:b3:d3:4f:9d:f6:84
|
||||||
|
c6:e4:eb:6f:c8:23:1c:73:f9:03:23:80:db:d5:7b:bd
|
||||||
|
0b:9c:fd:52:91:79:20:83:3c:e4:ac:bd:d5:8c:4c:32
|
||||||
|
a3:ee:0a:14:10:a0:35:c9:ee:67:6d:0b:bc:d1:be:7e
|
||||||
|
ad:d1:ea:cc:55:ba:5a:ab:25:f1:2a:59:7f:c9:b3:c5
|
||||||
|
01:96:08:81:5e:e3:b5:23:cf:24:30:1c:4e:c0:99:40
|
||||||
|
b4:5c:55:c8:20:49:c6:12:89:69:11:81:6f:83:2a:c1
|
||||||
|
02:73:3a:3e:fb:ae:7b:ee:af:be:73:24:41:b4:43:4f
|
||||||
|
39:75:19:e8:9e:f8:78:a0:47:8b:36:1d:6b:47:21:57
|
||||||
|
37:
|
||||||
|
|
||||||
|
public exponent:
|
||||||
|
01:00:01:
|
||||||
|
|
||||||
|
private exponent:
|
||||||
|
00:8b:e2:40:fa:93:f8:10:2f:af:66:9d:ea:97:19:16
|
||||||
|
5b:64:e1:26:1b:5d:9d:43:c6:7c:20:5d:43:1e:d7:13
|
||||||
|
82:ae:e6:30:0c:05:c5:8a:ed:4c:a6:5d:c4:ba:c3:a5
|
||||||
|
80:67:eb:d9:ae:20:92:3c:31:77:7b:a4:85:9c:0e:99
|
||||||
|
13:89:ce:93:30:3e:17:65:5d:ac:7e:34:50:a8:41:07
|
||||||
|
36:80:d8:d2:8f:59:c8:e7:aa:39:2f:8f:9a:8a:ec:85
|
||||||
|
88:15:f9:9f:e2:f8:4e:07:8a:bb:2f:58:26:19:83:f8
|
||||||
|
de:b9:73:38:36:e9:ab:91:0a:a6:9b:80:ed:b4:cd:d4
|
||||||
|
45:2b:b2:ed:24:57:65:d2:c1:2a:72:d4:d1:1c:c3:26
|
||||||
|
f1:15:28:4f:aa:8a:5f:47:28:33:51:5a:5b:48:3d:e1
|
||||||
|
d7:1c:e8:cb:36:25:7c:6b:7f:c6:be:c2:51:1c:de:e7
|
||||||
|
4b:d4:90:a0:35:66:fb:f7:c5:d2:67:3d:59:a2:b6:a0
|
||||||
|
8a:c6:03:8b:db:3a:39:32:28:21:ba:11:3b:a3:77:90
|
||||||
|
59:0d:72:81:01:ad:5f:66:92:b5:6c:61:d2:8c:60:eb
|
||||||
|
e5:62:8d:5c:71:72:99:7c:12:b8:1c:c6:ba:ee:64:17
|
||||||
|
41:04:b6:d2:59:f0:1a:0f:74:ca:d5:19:1e:98:f4:61
|
||||||
|
75:c3:e1:50:27:af:fa:48:87:3d:c9:11:aa:70:3e:56
|
||||||
|
64:a1:dc:42:d9:16:a6:d2:14:98:48:cd:ad:d2:09:33
|
||||||
|
00:10:5f:3c:69:36:81:96:75:44:f8:56:95:d2:e5:76
|
||||||
|
85:41:85:8d:f1:64:14:05:6b:f7:2a:26:6a:d9:f0:b9
|
||||||
|
d0:de:d6:3d:7e:7c:6c:2c:26:49:22:5e:2a:04:21:4f
|
||||||
|
c9:d7:3c:a1:1b:7b:d1:27:1d:80:38:25:57:7f:a2:99
|
||||||
|
46:d7:60:56:e6:5d:50:71:36:b6:af:a6:5b:d0:92:d8
|
||||||
|
19:0e:86:4b:3b:34:cf:cd:ea:e5:35:e4:4e:65:e3:20
|
||||||
|
91:
|
||||||
|
|
||||||
|
prime1:
|
||||||
|
00:f7:07:aa:be:24:f1:2f:26:ea:0e:45:86:b0:45:05
|
||||||
|
df:b8:59:d6:3b:40:5c:dd:c8:bf:18:3e:76:74:e8:31
|
||||||
|
35:ca:b0:d4:63:df:4d:4c:d5:0c:46:6e:31:71:3c:17
|
||||||
|
5e:45:4e:5c:a1:96:4f:69:5e:92:bd:e8:09:27:85:50
|
||||||
|
e3:29:1d:bb:8e:f9:2c:41:af:0f:c8:e0:d3:70:6a:d4
|
||||||
|
b9:67:43:08:e4:4a:c9:12:f6:d2:7e:7d:bc:69:52:ba
|
||||||
|
48:96:0a:7e:42:e7:6e:82:e8:0c:6c:1b:a5:01:f0:36
|
||||||
|
2c:ae:a4:2f:d8:62:ef:ab:1c:47:3a:98:79:40:68:dd
|
||||||
|
de:6a:b4:8c:53:03:09:78:11:27:36:6f:e4:2b:fb:f4
|
||||||
|
4d:bf:13:30:37:1f:51:fd:2f:84:d9:b9:62:ea:91:a8
|
||||||
|
e8:72:9d:78:14:bd:5a:9e:1f:06:12:70:19:bd:3b:80
|
||||||
|
b2:5c:33:8b:d6:5b:9c:2f:f9:12:46:55:4a:5a:10:bc
|
||||||
|
f5:
|
||||||
|
|
||||||
|
prime2:
|
||||||
|
00:ee:a5:18:9e:e5:9a:59:d4:d9:0c:42:4c:cf:a1:d7
|
||||||
|
ca:8f:b5:45:24:59:f9:83:1f:f4:f2:82:01:50:3c:e0
|
||||||
|
ae:bf:17:39:09:cd:5a:71:dd:ab:9e:b6:d6:1e:47:dc
|
||||||
|
34:eb:28:c0:4c:77:e5:05:5d:e3:0a:57:bf:65:1f:f8
|
||||||
|
29:68:08:45:ee:da:01:bc:57:c6:35:a7:2c:82:62:64
|
||||||
|
2a:cd:46:eb:54:eb:27:e2:eb:d5:d3:d3:04:ef:05:a1
|
||||||
|
4c:63:ec:d4:23:6f:60:02:71:a8:c3:ab:a5:2f:26:4e
|
||||||
|
ea:e1:a3:f5:e4:d2:59:19:c9:26:18:c5:4d:45:1e:61
|
||||||
|
1d:53:7c:6a:83:d2:18:40:dd:10:af:e8:24:09:1a:06
|
||||||
|
9b:f1:51:33:8e:13:e0:ce:18:b3:f0:8b:f3:9d:12:b3
|
||||||
|
e7:88:01:a1:c1:38:0d:c9:c6:0e:49:99:37:2f:be:60
|
||||||
|
e3:37:9d:c6:a8:cb:4b:c5:c0:49:2a:5d:fb:f2:fb:e7
|
||||||
|
fb:
|
||||||
|
|
||||||
|
coefficient:
|
||||||
|
22:52:c4:c2:c3:dd:30:13:54:c7:95:54:b2:cb:24:b5
|
||||||
|
0c:88:f4:22:a7:6a:13:b3:17:5f:0b:b2:8c:4f:2c:e6
|
||||||
|
d3:b6:ca:cd:e6:70:e4:37:5d:65:16:50:ae:b8:cc:bf
|
||||||
|
80:81:3d:e5:5c:0e:6d:ec:f9:4e:f5:49:00:fd:63:28
|
||||||
|
2a:ab:03:92:ae:b6:a6:97:ed:f0:97:25:55:06:3f:15
|
||||||
|
be:cf:70:22:bd:af:f8:2c:3f:ce:d5:e5:e6:5f:94:d7
|
||||||
|
d2:0a:fb:99:d7:ad:ab:d1:3a:b8:fb:6c:b0:47:1c:60
|
||||||
|
81:b1:8c:5e:df:25:8b:93:82:8c:28:52:99:5e:e7:e7
|
||||||
|
f8:fc:30:48:bd:43:82:9e:39:2b:7b:14:6b:fb:1b:8a
|
||||||
|
7d:f1:1e:06:01:ca:7d:59:54:79:00:fa:76:bd:a9:a1
|
||||||
|
02:ad:c4:7e:0b:56:c2:37:6b:7d:20:5f:53:ef:46:88
|
||||||
|
cf:24:e2:4c:25:fc:98:49:40:38:10:19:6f:3c:18:4c
|
||||||
|
|
||||||
|
|
||||||
|
exp1:
|
||||||
|
00:8b:1e:3a:3e:13:37:f0:c2:0d:96:33:f9:82:53:9c
|
||||||
|
d7:3d:4e:fa:a3:2b:c0:20:f6:e9:07:92:45:cb:d8:e7
|
||||||
|
bd:cf:84:7e:58:30:6d:ac:13:5f:72:5a:a4:65:8c:dd
|
||||||
|
ec:2d:43:d0:4f:00:03:80:e7:cd:e4:3d:44:ca:88:fd
|
||||||
|
e0:b0:4b:1a:51:8e:6a:2a:23:98:d4:1c:29:77:69:f2
|
||||||
|
9a:e7:58:8d:2d:64:20:91:19:87:b9:cc:bd:ca:e2:d8
|
||||||
|
1e:00:c1:b0:11:a5:9c:4b:04:bb:da:36:47:5b:2c:18
|
||||||
|
96:59:54:05:cd:eb:09:e6:67:6a:85:c9:50:9f:c1:6f
|
||||||
|
11:cf:2e:16:c8:b9:31:1f:f9:29:08:33:43:60:b1:e8
|
||||||
|
07:d0:cf:d1:9b:79:7c:07:06:37:df:15:d4:6b:1d:d4
|
||||||
|
ed:f3:7e:53:1d:fa:f5:89:8f:17:30:53:09:6b:d4:92
|
||||||
|
c9:df:ba:f7:c9:a4:95:f5:3e:63:d8:50:38:2b:38:b9
|
||||||
|
f1:
|
||||||
|
|
||||||
|
exp2:
|
||||||
|
00:ed:06:45:41:ec:c2:35:5e:d6:84:fa:84:d7:e4:e3
|
||||||
|
33:69:30:9d:8f:d1:5d:a5:02:e4:82:c8:e5:0d:10:aa
|
||||||
|
08:65:fb:66:c7:79:92:cf:6d:5f:bb:af:d5:53:16:04
|
||||||
|
7c:fa:e3:ea:bb:08:8a:0b:9e:88:96:09:39:2b:f3:68
|
||||||
|
c3:97:74:40:21:4f:9e:51:b6:cc:43:15:db:7b:54:c6
|
||||||
|
30:4c:da:97:7a:2c:65:dd:58:67:74:90:2e:62:48:b1
|
||||||
|
3f:f2:2f:93:33:ee:b6:e9:36:82:6c:75:db:06:cd:81
|
||||||
|
ac:80:98:1c:ee:3c:8e:0a:b2:62:88:4f:ce:c3:4b:bd
|
||||||
|
21:27:7e:77:3c:9e:3b:40:91:50:b5:a6:57:c4:42:79
|
||||||
|
36:01:a4:a9:14:00:62:53:d0:ed:47:89:79:59:14:ee
|
||||||
|
62:94:0f:2a:dd:82:13:0f:c9:0a:ff:c6:91:ad:75:e5
|
||||||
|
3d:48:4c:08:b8:35:d2:f8:82:57:29:21:57:d0:aa:aa
|
||||||
|
69:
|
||||||
|
|
||||||
|
|
||||||
|
Public Key PIN:
|
||||||
|
pin-sha256:SSdvX3918szw/veSWFuQJD3lGynf9mFLiTxpZPj/Jz4=
|
||||||
|
Public Key ID:
|
||||||
|
sha256:49276f5f7f75f2ccf0fef792585b90243de51b29dff6614b893c6964f8ff273e
|
||||||
|
sha1:2e41d8f4c0040eccc2f9010d77c6c6f813c561f4
|
||||||
|
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIG5QIBAAKCAYEA5khwb98yCyLWiaxvt8u3VoL7F+l9xcy1Vzq4RTgTW7Kx0rJL
|
||||||
|
bdtMh2YaH6HpZILZXJAbH7eRlGBhAWbiSCBXDr6W1108/3GIHvFoaXBaOuADzXO8
|
||||||
|
8cpGk3iBzJhKo8arTnn8jprhMlsmtl2wgOGmenpsoq5HpvedsASTWCyFqMud2EO/
|
||||||
|
XRbx9kjlij5VwmtQf4oe2/amGRNlx6C0Emywiag1qEE8Zjntd/9WipySLiMv4oBr
|
||||||
|
DO8oJqYRuJM78n24gKPjXedFElXnnhfD/l9mGX1xSpm8yU4OKulFAeL6p+F3oFtO
|
||||||
|
uXiMjdV8N2f5fAoj9Btu4rpP2X0bs9NPnfaExuTrb8gjHHP5AyOA29V7vQuc/VKR
|
||||||
|
eSCDPOSsvdWMTDKj7goUEKA1ye5nbQu80b5+rdHqzFW6Wqsl8SpZf8mzxQGWCIFe
|
||||||
|
47UjzyQwHE7AmUC0XFXIIEnGEolpEYFvgyrBAnM6Pvuue+6vvnMkQbRDTzl1Geie
|
||||||
|
+HigR4s2HWtHIVc3AgMBAAECggGBAIviQPqT+BAvr2ad6pcZFltk4SYbXZ1Dxnwg
|
||||||
|
XUMe1xOCruYwDAXFiu1Mpl3EusOlgGfr2a4gkjwxd3ukhZwOmROJzpMwPhdlXax+
|
||||||
|
NFCoQQc2gNjSj1nI56o5L4+aiuyFiBX5n+L4TgeKuy9YJhmD+N65czg26auRCqab
|
||||||
|
gO20zdRFK7LtJFdl0sEqctTRHMMm8RUoT6qKX0coM1FaW0g94dcc6Ms2JXxrf8a+
|
||||||
|
wlEc3udL1JCgNWb798XSZz1ZoragisYDi9s6OTIoIboRO6N3kFkNcoEBrV9mkrVs
|
||||||
|
YdKMYOvlYo1ccXKZfBK4HMa67mQXQQS20lnwGg90ytUZHpj0YXXD4VAnr/pIhz3J
|
||||||
|
EapwPlZkodxC2Ram0hSYSM2t0gkzABBfPGk2gZZ1RPhWldLldoVBhY3xZBQFa/cq
|
||||||
|
JmrZ8LnQ3tY9fnxsLCZJIl4qBCFPydc8oRt70ScdgDglV3+imUbXYFbmXVBxNrav
|
||||||
|
plvQktgZDoZLOzTPzerlNeROZeMgkQKBwQD3B6q+JPEvJuoORYawRQXfuFnWO0Bc
|
||||||
|
3ci/GD52dOgxNcqw1GPfTUzVDEZuMXE8F15FTlyhlk9pXpK96AknhVDjKR27jvks
|
||||||
|
Qa8PyODTcGrUuWdDCORKyRL20n59vGlSukiWCn5C526C6AxsG6UB8DYsrqQv2GLv
|
||||||
|
qxxHOph5QGjd3mq0jFMDCXgRJzZv5Cv79E2/EzA3H1H9L4TZuWLqkajocp14FL1a
|
||||||
|
nh8GEnAZvTuAslwzi9ZbnC/5EkZVSloQvPUCgcEA7qUYnuWaWdTZDEJMz6HXyo+1
|
||||||
|
RSRZ+YMf9PKCAVA84K6/FzkJzVpx3auettYeR9w06yjATHflBV3jCle/ZR/4KWgI
|
||||||
|
Re7aAbxXxjWnLIJiZCrNRutU6yfi69XT0wTvBaFMY+zUI29gAnGow6ulLyZO6uGj
|
||||||
|
9eTSWRnJJhjFTUUeYR1TfGqD0hhA3RCv6CQJGgab8VEzjhPgzhiz8IvznRKz54gB
|
||||||
|
ocE4DcnGDkmZNy++YOM3ncaoy0vFwEkqXfvy++f7AoHBAIseOj4TN/DCDZYz+YJT
|
||||||
|
nNc9TvqjK8Ag9ukHkkXL2Oe9z4R+WDBtrBNfclqkZYzd7C1D0E8AA4DnzeQ9RMqI
|
||||||
|
/eCwSxpRjmoqI5jUHCl3afKa51iNLWQgkRmHucy9yuLYHgDBsBGlnEsEu9o2R1ss
|
||||||
|
GJZZVAXN6wnmZ2qFyVCfwW8Rzy4WyLkxH/kpCDNDYLHoB9DP0Zt5fAcGN98V1Gsd
|
||||||
|
1O3zflMd+vWJjxcwUwlr1JLJ37r3yaSV9T5j2FA4Kzi58QKBwQDtBkVB7MI1XtaE
|
||||||
|
+oTX5OMzaTCdj9FdpQLkgsjlDRCqCGX7Zsd5ks9tX7uv1VMWBHz64+q7CIoLnoiW
|
||||||
|
CTkr82jDl3RAIU+eUbbMQxXbe1TGMEzal3osZd1YZ3SQLmJIsT/yL5Mz7rbpNoJs
|
||||||
|
ddsGzYGsgJgc7jyOCrJiiE/Ow0u9ISd+dzyeO0CRULWmV8RCeTYBpKkUAGJT0O1H
|
||||||
|
iXlZFO5ilA8q3YITD8kK/8aRrXXlPUhMCLg10viCVykhV9CqqmkCgcAiUsTCw90w
|
||||||
|
E1THlVSyyyS1DIj0IqdqE7MXXwuyjE8s5tO2ys3mcOQ3XWUWUK64zL+AgT3lXA5t
|
||||||
|
7PlO9UkA/WMoKqsDkq62ppft8JclVQY/Fb7PcCK9r/gsP87V5eZflNfSCvuZ162r
|
||||||
|
0Tq4+2ywRxxggbGMXt8li5OCjChSmV7n5/j8MEi9Q4KeOSt7FGv7G4p98R4GAcp9
|
||||||
|
WVR5APp2vamhAq3EfgtWwjdrfSBfU+9GiM8k4kwl/JhJQDgQGW88GEw=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
0
test/tw-1837.t
Executable file → Normal file
0
test/tw-1837.t
Executable file → Normal file
89
test/tw-2689.t.cpp
Normal file
89
test/tw-2689.t.cpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright 2006 - 2021, Tomas Babej, Paul Beckingham, Federico Hernandez.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// https://www.opensource.org/licenses/mit-license.php
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cmake.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <main.h>
|
||||||
|
#include <test.h>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int main (int, char**)
|
||||||
|
{
|
||||||
|
UnitTest test (12);
|
||||||
|
|
||||||
|
// Ensure environment has no influence.
|
||||||
|
unsetenv ("TASKDATA");
|
||||||
|
unsetenv ("TASKRC");
|
||||||
|
|
||||||
|
// Inform Task about the attributes in the JSON below
|
||||||
|
Task::attributes["depends"] = "string";
|
||||||
|
Task::attributes["uuid"] = "string";
|
||||||
|
|
||||||
|
// depends in [..] string from a taskserver (issue#2689)
|
||||||
|
auto sample = "{"
|
||||||
|
"\"depends\":\"[\\\"92a40a34-37f3-4785-8ca1-ff89cfbfd105\\\",\\\"e08e35fa-e42b-4de0-acc4-518fca8f6365\\\"]\","
|
||||||
|
"\"uuid\":\"00000000-0000-0000-0000-000000000000\""
|
||||||
|
"}";
|
||||||
|
auto json = Task (sample);
|
||||||
|
auto value = json.get ("uuid");
|
||||||
|
test.is (value, "00000000-0000-0000-0000-000000000000", "json [..] uuid");
|
||||||
|
value = json.get ("depends");
|
||||||
|
test.is (value, "92a40a34-37f3-4785-8ca1-ff89cfbfd105,e08e35fa-e42b-4de0-acc4-518fca8f6365", "json [..] depends");
|
||||||
|
test.ok (json.has ("dep_92a40a34-37f3-4785-8ca1-ff89cfbfd105"), "json [..] dep attr");
|
||||||
|
test.ok (json.has ("dep_e08e35fa-e42b-4de0-acc4-518fca8f6365"), "json [..] dep attr");
|
||||||
|
|
||||||
|
// depends in comma-delimited string from a taskserver (deprecated format)
|
||||||
|
sample = "{"
|
||||||
|
"\"depends\":\"92a40a34-37f3-4785-8ca1-ff89cfbfd105,e08e35fa-e42b-4de0-acc4-518fca8f6365\","
|
||||||
|
"\"uuid\":\"00000000-0000-0000-0000-000000000000\""
|
||||||
|
"}";
|
||||||
|
json = Task (sample);
|
||||||
|
value = json.get ("uuid");
|
||||||
|
test.is (value, "00000000-0000-0000-0000-000000000000", "json comma-separated uuid");
|
||||||
|
value = json.get ("depends");
|
||||||
|
test.is (value, "92a40a34-37f3-4785-8ca1-ff89cfbfd105,e08e35fa-e42b-4de0-acc4-518fca8f6365", "json comma-separated depends");
|
||||||
|
test.ok (json.has ("dep_92a40a34-37f3-4785-8ca1-ff89cfbfd105"), "json comma-separated dep attr");
|
||||||
|
test.ok (json.has ("dep_e08e35fa-e42b-4de0-acc4-518fca8f6365"), "json comma-separated dep attr");
|
||||||
|
|
||||||
|
// depends in a JSON array from a taskserver
|
||||||
|
sample = "{"
|
||||||
|
"\"depends\":[\"92a40a34-37f3-4785-8ca1-ff89cfbfd105\",\"e08e35fa-e42b-4de0-acc4-518fca8f6365\"],"
|
||||||
|
"\"uuid\":\"00000000-0000-0000-0000-000000000000\""
|
||||||
|
"}";
|
||||||
|
json = Task (sample);
|
||||||
|
value = json.get ("uuid");
|
||||||
|
test.is (value, "00000000-0000-0000-0000-000000000000", "json array uuid");
|
||||||
|
value = json.get ("depends");
|
||||||
|
test.is (value, "92a40a34-37f3-4785-8ca1-ff89cfbfd105,e08e35fa-e42b-4de0-acc4-518fca8f6365", "json array depends");
|
||||||
|
test.ok (json.has ("dep_92a40a34-37f3-4785-8ca1-ff89cfbfd105"), "json array dep attr");
|
||||||
|
test.ok (json.has ("dep_e08e35fa-e42b-4de0-acc4-518fca8f6365"), "json array dep attr");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -314,7 +314,7 @@ class Test1447(TestCase):
|
|||||||
self.t = Task()
|
self.t = Task()
|
||||||
|
|
||||||
def test_filter_uda(self):
|
def test_filter_uda(self):
|
||||||
"""1447: Verify ability to filter on empty UDA"""
|
"""1447: Verify ability to filter on empty UDA that resembles named date"""
|
||||||
self.t.config('uda.sep.type', 'string')
|
self.t.config('uda.sep.type', 'string')
|
||||||
self.t('add one')
|
self.t('add one')
|
||||||
self.t('add two sep:foo')
|
self.t('add two sep:foo')
|
||||||
|
|||||||
@@ -82,6 +82,24 @@ class TestUDAOrphans(TestCase):
|
|||||||
code, out, err = self.t("_get 1.description")
|
code, out, err = self.t("_get 1.description")
|
||||||
self.assertIn("one extra:foo", out)
|
self.assertIn("one extra:foo", out)
|
||||||
|
|
||||||
|
def test_orphan_identification(self):
|
||||||
|
"""Verify that orphans are identified by +ORPHAN tag and udas command"""
|
||||||
|
|
||||||
|
# Create one task with legitimate orphan attribute and others without
|
||||||
|
self.t("rc.uda.extra.type:string rc.uda.extra.label:Extra add one extra:foo")
|
||||||
|
self.t("add two no attributes")
|
||||||
|
self.t("add three +test ")
|
||||||
|
self.t("add four +test depends:3")
|
||||||
|
self.t("4 annotate annotation content")
|
||||||
|
|
||||||
|
# Only the first task should be identified as orphan
|
||||||
|
code, out, err = self.t("+ORPHAN ids")
|
||||||
|
self.assertEqual("1", out.strip())
|
||||||
|
|
||||||
|
# Only the first task should be identified as orphan
|
||||||
|
code, out, err = self.t("udas")
|
||||||
|
self.assertRegex(out, r'extra\s+1\s+1 Orphan UDA')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from simpletap import TAPTestRunner
|
from simpletap import TAPTestRunner
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ int main (int, char**)
|
|||||||
Task rightAgain (right);
|
Task rightAgain (right);
|
||||||
|
|
||||||
std::string output = left.diff (right);
|
std::string output = left.diff (right);
|
||||||
t.ok (left.data != right.data, "Detected changes");
|
t.ok (!(left == right), "Detected changes");
|
||||||
t.ok (output.find ("Zero will be changed from '0' to '00'") != std::string::npos, "Detected change zero:0 -> zero:00");
|
t.ok (output.find ("Zero will be changed from '0' to '00'") != std::string::npos, "Detected change zero:0 -> zero:00");
|
||||||
t.ok (output.find ("One will be deleted") != std::string::npos, "Detected deletion one:1 ->");
|
t.ok (output.find ("One will be deleted") != std::string::npos, "Detected deletion one:1 ->");
|
||||||
t.ok (output.find ("Two") == std::string::npos, "Detected no change two:2 -> two:2");
|
t.ok (output.find ("Two") == std::string::npos, "Detected no change two:2 -> two:2");
|
||||||
|
|||||||
@@ -77,11 +77,6 @@ class TestVersion(TestCase):
|
|||||||
self.assertIn("MIT license", out)
|
self.assertIn("MIT license", out)
|
||||||
self.assertIn("https://taskwarrior.org", out)
|
self.assertIn("https://taskwarrior.org", out)
|
||||||
|
|
||||||
def slurp_git(self):
|
|
||||||
git_cmd = ("git", "rev-parse", "--short", "--verify", "HEAD")
|
|
||||||
_, hash, _ = run_cmd_wait(git_cmd)
|
|
||||||
return hash.rstrip("\n")
|
|
||||||
|
|
||||||
def test_under_version(self):
|
def test_under_version(self):
|
||||||
"""_version and diagnostics output expected version and syntax"""
|
"""_version and diagnostics output expected version and syntax"""
|
||||||
code, out, err = self.t("_version")
|
code, out, err = self.t("_version")
|
||||||
@@ -94,8 +89,7 @@ class TestVersion(TestCase):
|
|||||||
if os.path.exists("../.git"):
|
if os.path.exists("../.git"):
|
||||||
if 2 >= len(version) > 0:
|
if 2 >= len(version) > 0:
|
||||||
git = version[1]
|
git = version[1]
|
||||||
git_expected = "({0})".format(self.slurp_git())
|
self.assertRegex(git, r'\([a-f0-9]*\)'))
|
||||||
self.assertEqual(git_expected, git)
|
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unexpected output from _version '{0}'".format(
|
raise ValueError("Unexpected output from _version '{0}'".format(
|
||||||
out))
|
out))
|
||||||
|
|||||||
12
test/wait.t
12
test/wait.t
@@ -87,14 +87,18 @@ class Test1486(TestCase):
|
|||||||
|
|
||||||
def test_waiting(self):
|
def test_waiting(self):
|
||||||
"""1486: Verify waiting report shows waiting tasks"""
|
"""1486: Verify waiting report shows waiting tasks"""
|
||||||
self.t.config('uda.sep.type', 'string')
|
|
||||||
|
|
||||||
self.t('add regular')
|
self.t('add regular')
|
||||||
self.t('add waited wait:later')
|
self.t('add waited and pending wait:later')
|
||||||
|
self.t('add waited but deleted wait:later')
|
||||||
|
self.t('add waited but done wait:later')
|
||||||
|
self.t('rc.confirmation=off 3 delete')
|
||||||
|
self.t('4 done')
|
||||||
|
|
||||||
code, out, err = self.t('waiting')
|
code, out, err = self.t('waiting')
|
||||||
self.assertEqual(0, code, "Exit code was non-zero ({0})".format(code))
|
self.assertEqual(0, code, "Exit code was non-zero ({0})".format(code))
|
||||||
self.assertIn('waited', out)
|
self.assertIn('waited and pending', out)
|
||||||
|
self.assertNotIn('waited but deleted', out)
|
||||||
|
self.assertNotIn('waited but done', out)
|
||||||
self.assertNotIn('regular', out)
|
self.assertNotIn('regular', out)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user