Compare commits
1164 Commits
Author | SHA1 | Date | |
---|---|---|---|
d8044ababe | |||
32b526b729 | |||
7f6515dbe4 | |||
a39390b8b4 | |||
63a3dd1919 | |||
7a5a4de6ea | |||
664d4e701e | |||
a4ba8d8288 | |||
392bf7a97b | |||
34687049b1 | |||
9337ec6706 | |||
5bcb6962c4 | |||
0617b43190 | |||
ed28234cfb | |||
9c4455ca03 | |||
9ec7837275 | |||
549b5a6488 | |||
2652f37453 | |||
0eaff22145 | |||
2f5393b9d0 | |||
e28480a8e4 | |||
fcef6321fc | |||
35e792c5de | |||
c08b632b51 | |||
cac800bfd8 | |||
2eb8173951 | |||
75abf2c124 | |||
d40a18d6c5 | |||
a74fdc588c | |||
25b0ec6eff | |||
04e8982d33 | |||
58bd449db8 | |||
c984e9b5d6 | |||
ddd319369a | |||
de3c336213 | |||
6e94e9bff1 | |||
93b8d9e454 | |||
6d46081864 | |||
41032aaac2 | |||
4e08f28246 | |||
46c57e120f | |||
6b52ee61ae | |||
61fbc5a791 | |||
22365205f9 | |||
c6515c1dad | |||
8201d1df02 | |||
ddf168c536 | |||
c9f81f56e9 | |||
570264e1e9 | |||
325e58d98c | |||
23a2960aa3 | |||
888a87463e | |||
2ebaf46095 | |||
3a95a3b7c1 | |||
c4edffb388 | |||
5eec7cc788 | |||
fb4cf0b75d | |||
5584884fe6 | |||
3bb1068ef0 | |||
b1b85313ae | |||
aec3e7b0fc | |||
243600b75b | |||
3d89d126d0 | |||
54281e53a1 | |||
6befd2be81 | |||
1f0ca9ed92 | |||
f3db9c3920 | |||
83ceb26151 | |||
32cdfb871c | |||
801e7da5ee | |||
2cf1ab7ec5 | |||
d049c1afaf | |||
9f45389bc1 | |||
d875481969 | |||
17a1e1245c | |||
06d28c3eec | |||
684982c25c | |||
421522a61a | |||
f3b29d67f4 | |||
2ee5c6b2a1 | |||
5083772c6f | |||
fd51e5df47 | |||
3405fd91c6 | |||
194822f11e | |||
98963d4cdf | |||
804ef36b20 | |||
3c6ff8fddf | |||
511893d535 | |||
e05fe77bfe | |||
2b7b9a2abb | |||
6db3f68ae1 | |||
3773f2e7a5 | |||
1f8bffc15a | |||
afaef4e83b | |||
b746f723cb | |||
cfaf44f57b | |||
eed541201e | |||
a8bcb85f7b | |||
981e9cf290 | |||
3ac398ac49 | |||
2d0728395f | |||
722194405a | |||
0868a5e534 | |||
a86b9c82ce | |||
f8642548c8 | |||
27873f7ed4 | |||
b3eda6bcbb | |||
1c7799e292 | |||
aecd158d3c | |||
87d35f0d16 | |||
c089f9b59f | |||
82d7f9f5a4 | |||
8bc529be3d | |||
924c1634d3 | |||
03d077e915 | |||
303628bb05 | |||
3b92ec8e82 | |||
545944cb0d | |||
c90a88b6b6 | |||
89e45a61b3 | |||
2aff7bac4a | |||
124097d3a5 | |||
c520faed6d | |||
5bdb3703ed | |||
2901039a48 | |||
dfa220ef02 | |||
f26be00571 | |||
83654a193e | |||
b2a5d8daf4 | |||
19ee736e1d | |||
fda3f1352e | |||
d194b02e28 | |||
aaba99dc10 | |||
93a2e0f777 | |||
71f3c6b461 | |||
aabcca5059 | |||
7e67fd8c79 | |||
fecf1ffcb9 | |||
fafc9cf9ca | |||
3111e6a721 | |||
e436f471a0 | |||
28f84902f6 | |||
ebee50eedc | |||
e0ef09dfe1 | |||
d7992ab29d | |||
60f19f305e | |||
d99976f5d7 | |||
db158a5735 | |||
ea3be17220 | |||
f26049009e | |||
787234a53a | |||
fc3a64056c | |||
6ebc9abb80 | |||
80e9eed35a | |||
23b3990f99 | |||
41276403df | |||
e3e9e39498 | |||
f315025a8d | |||
8e43d97133 | |||
c97a47dc62 | |||
7ccafdc993 | |||
0dca9cb6b8 | |||
be3d780720 | |||
0f59a1dde1 | |||
7c6bb80cee | |||
62841c5b23 | |||
aad4f8d1f7 | |||
11c44c676c | |||
370c3aa598 | |||
1cdadafdf8 | |||
dd6f670dec | |||
9ff364b0d3 | |||
58a5331f7b | |||
ed261f0af9 | |||
c01b475cbf | |||
3d4feeec8d | |||
a1800ec23f | |||
8a4f1c66f8 | |||
b187231b0e | |||
60b38de69f | |||
600c49f7f0 | |||
e7380e70a3 | |||
3df8594f19 | |||
ee4a829293 | |||
1862f3c124 | |||
777ab3416f | |||
ecf5ab75e7 | |||
4f6d964217 | |||
06019f01e3 | |||
ddde885084 | |||
be8c6f218c | |||
9eb35ea7c8 | |||
d2fdbec41d | |||
2dd372600c | |||
eda6cf11ef | |||
68facd6b93 | |||
87002fb8f8 | |||
6a50fa35ec | |||
6541570969 | |||
4b0ceea894 | |||
8c0816c166 | |||
be769d07f1 | |||
3a9d58e31c | |||
7024acac06 | |||
6131346e2f | |||
eed73c9078 | |||
795d6f35ee | |||
ebd46705d5 | |||
72d2ca234e | |||
2246c3359b | |||
242fb156a2 | |||
208ed73e59 | |||
4441b37338 | |||
941d75824a | |||
ec9ddc4f22 | |||
98b6f90172 | |||
7e280de361 | |||
7bd8bd13fe | |||
09e85e948c | |||
9ec1c00887 | |||
c6bcb6228b | |||
a24d589845 | |||
ebbcc9f6da | |||
23fc453fae | |||
aad6f74db6 | |||
07dcefabcb | |||
40c68595d7 | |||
fe9a4fece4 | |||
098327f128 | |||
0873b8d304 | |||
c9eb584ac8 | |||
10493bd44a | |||
9e35230467 | |||
81e326571b | |||
1b2a7de4e2 | |||
11216d200c | |||
777be6a48d | |||
5765a1fdf1 | |||
29dcb9d274 | |||
8674ac4f68 | |||
684b8f24f3 | |||
1ca2be0039 | |||
8c41ff68f7 | |||
931d6c280a | |||
ee0fb2d0e0 | |||
c496ad1237 | |||
277fa21f5f | |||
1cf949226e | |||
be3fae6511 | |||
5932f36285 | |||
30abb65368 | |||
64a06b5ed6 | |||
69d18f17a5 | |||
4c7d3a103c | |||
10320bdeb4 | |||
4261dcff39 | |||
a091245793 | |||
ca282f9fb3 | |||
7cf2c3be0f | |||
f65d506f26 | |||
333dbca01e | |||
42eb265624 | |||
8a65726e9d | |||
1b0ca47682 | |||
8e3f5c3305 | |||
3c0a6987cd | |||
e37f70b9f7 | |||
03c148ce50 | |||
4817f0312d | |||
b70a82c609 | |||
25d1e0c4e6 | |||
8e3356f11a | |||
1b559c7776 | |||
d5583f0f02 | |||
bedd3c50b6 | |||
43a7af3f44 | |||
9db27c6acc | |||
42c81395b3 | |||
3b13e692d2 | |||
0331f5a1eb | |||
8a7e117f6b | |||
9b984cedac | |||
dd9e30b24a | |||
6a93688b2e | |||
3ab17a97a8 | |||
f21ae66265 | |||
afa1a5e932 | |||
050768c266 | |||
cda2bfc240 | |||
2f167b1512 | |||
ba3ac85356 | |||
ec29cedeb7 | |||
064ae49d2b | |||
247f99ce2f | |||
7b6d269904 | |||
87a0482b8b | |||
e899699918 | |||
bdf464e792 | |||
c410bb4ecb | |||
a720bcc637 | |||
369a8cdc74 | |||
3f4e55be4f | |||
9171f471ab | |||
2186b134a4 | |||
f371ec210c | |||
afcd669d2f | |||
fbf542d205 | |||
13184eb8e9 | |||
ddf1e1ccee | |||
5ac4e73697 | |||
6be59b53f1 | |||
bb54fec907 | |||
0b81b283bf | |||
e2ab2aea32 | |||
c3ceefbafb | |||
e7cf9932a9 | |||
0c9d03f5df | |||
92aa24ae34 | |||
97a74d5c1f | |||
256f8094f5 | |||
1e2f0ab308 | |||
af2cf2734d | |||
ec62d8e973 | |||
3225f514f6 | |||
2d63c86022 | |||
2dcff83be7 | |||
afb9ebcd99 | |||
92d7e44525 | |||
a517f442ea | |||
311758233b | |||
6e086eb808 | |||
7e8644430c | |||
70a8f6743a | |||
69eafd0e11 | |||
6b6a095b91 | |||
d5a2185030 | |||
26f31e9288 | |||
e654e66839 | |||
bb4861cf0d | |||
01505910f4 | |||
ab766a0598 | |||
51c664a678 | |||
3c4b45c9e7 | |||
93507a263b | |||
1175461030 | |||
2f5e55bea0 | |||
c375e7b4df | |||
5d188c69ed | |||
6bff7751d0 | |||
1a5986abe0 | |||
cebac3c10e | |||
a5da3db966 | |||
cd30f75173 | |||
94df4ceb36 | |||
a14476c5fb | |||
d82bb29919 | |||
33af0c6a7c | |||
68f3f98bc3 | |||
f873cd5b1a | |||
fa8df286d9 | |||
76aa0c434a | |||
78dc0cfdf3 | |||
9654728bfb | |||
123d1864f4 | |||
96a91e988d | |||
19ecb1701e | |||
8085b2728d | |||
56cad31a36 | |||
3275bc4e93 | |||
8963378039 | |||
c7d435bb7a | |||
06cc7e4ea0 | |||
fba20e2cfb | |||
358f080c76 | |||
8cea57ff0f | |||
7b27f200b1 | |||
f4b207220c | |||
d835e1d14e | |||
75f92de8f8 | |||
293c1deee5 | |||
4dee05a967 | |||
8d6414d74a | |||
362ecdb583 | |||
058b9f9272 | |||
355762aa30 | |||
be4fb65470 | |||
4ed296bad4 | |||
a8aa862919 | |||
31ba1de53b | |||
bca1fef2b2 | |||
f33b31e048 | |||
0d10ebb7ca | |||
4a8abc948e | |||
6fd3672618 | |||
abd090bd48 | |||
bd9140f1f3 | |||
9d78b2d259 | |||
9c9528838a | |||
77b640b76b | |||
a8dfe98b1a | |||
cee41b87f7 | |||
7a95314e42 | |||
6aaf1f4f21 | |||
368a0ddd44 | |||
0808a10b7b | |||
6f052baa94 | |||
5bc67d3f6b | |||
74c6c5cfbc | |||
158b7fd166 | |||
c3f647dc96 | |||
5936c7b65c | |||
a8bcd85c93 | |||
127b558f95 | |||
6e9a27f40f | |||
4a13dbe3bb | |||
0f61f5ba03 | |||
5f1efbeb67 | |||
9c105914f0 | |||
579582740e | |||
b15544c163 | |||
94a63e3859 | |||
842b7e6c39 | |||
22f5011451 | |||
74120fe1f3 | |||
b4e8abd0ad | |||
336f1f4f50 | |||
1c256d8876 | |||
1ce0f0e7a5 | |||
fbf1901d86 | |||
0382f33c46 | |||
13372f3f99 | |||
e741cb7f0a | |||
fb289c6b17 | |||
75a7ea55d4 | |||
86573a5ccd | |||
6fe55a79f1 | |||
1a6cb9ee99 | |||
a495d9eca5 | |||
65a945f968 | |||
a9e8ed5087 | |||
00520b6a0e | |||
e6f2a3893a | |||
24c034ff6a | |||
631a93bcd8 | |||
b1763353ea | |||
f95bcf45ad | |||
15ec1abb6a | |||
cfda8dbb2b | |||
3aa2003951 | |||
0e473f4570 | |||
bfa824ee71 | |||
1157436a24 | |||
4596e78df0 | |||
813dfbd2d3 | |||
ba7dfb360c | |||
6aad750fe0 | |||
5e443ae347 | |||
c65f5f7728 | |||
74b62727af | |||
2e94562f79 | |||
061ea5648e | |||
439e7bbf4e | |||
0f1d51f866 | |||
75cfaf0672 | |||
ceaa732e5f | |||
deb2a2bd14 | |||
33853b6107 | |||
ab6e1b112b | |||
220e823c8d | |||
c666c3e251 | |||
9cc1773fa7 | |||
e78c7af715 | |||
b96e76134a | |||
fd2b206997 | |||
2d53c7c5b2 | |||
28ae5d710e | |||
7a13412ec7 | |||
c86610b917 | |||
502750492c | |||
8fc1653b0c | |||
6841ebc31d | |||
8757281467 | |||
20b1723e78 | |||
be78afeee5 | |||
3746a2566d | |||
0cb47cf7d7 | |||
dec81c4f27 | |||
54b335711a | |||
6bb8332b4b | |||
de9e304236 | |||
650af5eb64 | |||
47bdcb6050 | |||
58dc3e93d3 | |||
79b0a16f7a | |||
2b65ee433f | |||
001bbef9ee | |||
c4316e81e6 | |||
fac63541a4 | |||
dfd6cb29be | |||
5f75e531e6 | |||
a7648d60ce | |||
52c45c2d32 | |||
fd6755c93f | |||
a53ee2e35c | |||
4e6978ff6f | |||
91a5c4bdcb | |||
9a07ede615 | |||
dfab55112b | |||
1709b47bb7 | |||
2d10c246a8 | |||
6e2869834f | |||
b8b71c7dd2 | |||
c3f6c3dd82 | |||
844b245776 | |||
4bcf8e6975 | |||
0e52112016 | |||
32a9545360 | |||
9a44c92211 | |||
dd6aabf9ab | |||
91776311c7 | |||
882c82f82c | |||
43b9db6e45 | |||
032ceefa1d | |||
05fa266e6b | |||
56085310cb | |||
6a1d611fd1 | |||
c8a72c876d | |||
ec87a8ddfc | |||
33e34ebb83 | |||
dce435c882 | |||
396b3c3952 | |||
8cf42f4e15 | |||
17ea51ce27 | |||
04818ca626 | |||
6732b77594 | |||
3e4346e321 | |||
4dfc01899a | |||
b0b8ccfd4a | |||
4d35c66af3 | |||
509f7bd018 | |||
42b9b3d72a | |||
e280f9fe3e | |||
89493a2f1d | |||
e259bffca6 | |||
ba9164022d | |||
a4672ba00f | |||
c0bf267bae | |||
1a26a53659 | |||
8f4d7ac655 | |||
c5625d8d32 | |||
548a2a1d64 | |||
df01a58099 | |||
ac8ee9f981 | |||
b1805b70ea | |||
eae8a2914e | |||
03429db528 | |||
10f27250ee | |||
aed7963d11 | |||
2810413112 | |||
31fd92e071 | |||
b3b76d5d56 | |||
cd948dceae | |||
eb33a87ff5 | |||
bf560f4594 | |||
d77237ca5d | |||
211d596fdd | |||
f464b347b2 | |||
203c3ec233 | |||
e2a74dfc30 | |||
4e99da7b62 | |||
eb5ed50824 | |||
3b4539de79 | |||
3e4d1c04de | |||
fdf5748029 | |||
3562e94650 | |||
15c5bbcf22 | |||
c363423718 | |||
e58158c3cd | |||
ff2cd50bfa | |||
984692dc62 | |||
a7fc23dd96 | |||
c1bcbf8c63 | |||
9e69b8fe1b | |||
e0ae631d59 | |||
3b187b5246 | |||
20666763f0 | |||
f591c87665 | |||
e6fe701727 | |||
35a698ef72 | |||
998271414e | |||
1749f25420 | |||
4ab0e70a9a | |||
08989bde5e | |||
87cbff391c | |||
962923bbce | |||
311b081e60 | |||
4103948132 | |||
906f26698b | |||
8a1a583afe | |||
9e19b73ce6 | |||
e11706d99d | |||
301b811310 | |||
273cf3d565 | |||
f432cfd73a | |||
ffa756ccee | |||
e210a4b244 | |||
f1902a4471 | |||
04b865adae | |||
00df092a99 | |||
cad581388f | |||
e7ed3abb79 | |||
e5f6dc1b14 | |||
145da82cd8 | |||
64776d6bac | |||
64d123f524 | |||
0ec4ade683 | |||
4bfc445cf8 | |||
4232b1cedb | |||
474d77ac57 | |||
3c40355d7c | |||
cbc1aad58d | |||
89a30a47c5 | |||
881a5603dc | |||
68c48b2c8a | |||
0f9260869b | |||
412fdb0f7b | |||
81d52b6169 | |||
278d2169da | |||
5599b5a337 | |||
471d6d6031 | |||
b90d6b0f26 | |||
cd22da9c62 | |||
fb75c23f4e | |||
7f22994f68 | |||
7aba7b6064 | |||
e32030f364 | |||
b40619bcbd | |||
fe2e1d931f | |||
2e17e78052 | |||
f2fa82fd3c | |||
8cec4b60a6 | |||
bf9888099c | |||
02201631e7 | |||
8e80b4bfc1 | |||
63dfc0633f | |||
50f1847904 | |||
79840f0fca | |||
06bf7b0f31 | |||
dbb63b97bd | |||
3039cb5c02 | |||
b5d2570fe2 | |||
5f951e8f21 | |||
286f82cc99 | |||
ed5415aeb8 | |||
bef79df6bb | |||
2edabe0f99 | |||
91b5f0228d | |||
d639da741b | |||
84bd5ace6c | |||
63589d2ba9 | |||
d6f4ff26b5 | |||
b606a2e040 | |||
f685139d89 | |||
68d6ce60a9 | |||
2bba64fe3a | |||
774ed044fc | |||
9cc235cde0 | |||
91375e4c6d | |||
0ef8da64e0 | |||
9ef38171e2 | |||
455e4de6f3 | |||
4e319254dd | |||
04e8780dd0 | |||
0fe4384067 | |||
bdfcd0b99e | |||
5da87d1904 | |||
821edf0f51 | |||
04e822acfb | |||
c31fce3621 | |||
5c05cf2206 | |||
d4e544c62c | |||
d232248268 | |||
90025ed45d | |||
964151d9c7 | |||
409c9bf9d2 | |||
a135c06bcf | |||
efb1f4abf2 | |||
036a826b3a | |||
8d2b66a0fd | |||
31d6278b31 | |||
5558d7eef8 | |||
6103d86a47 | |||
b8899a534d | |||
fa6829a6a1 | |||
5335540c33 | |||
7f62de3854 | |||
0afa2e92d5 | |||
6d1b166ad7 | |||
4b6ddfb89b | |||
9ec260619b | |||
4c6ac9e4fe | |||
08fc3ea2e0 | |||
03e454b71d | |||
c527ea83fb | |||
8b9ac63657 | |||
0ba02f0830 | |||
1f6cef6f8a | |||
251942323e | |||
8e3efec40f | |||
3d0740f80e | |||
707a68cb4f | |||
e6b1a1fa76 | |||
3e8d450741 | |||
d0881b7420 | |||
27239b2dde | |||
3fbbaddece | |||
effe46db86 | |||
ba939c92ec | |||
e25cdd9d12 | |||
d394235ee0 | |||
349fc4143d | |||
4be9e6a0bc | |||
cb258146c4 | |||
9f039cef72 | |||
d08815bbc1 | |||
c04e38d011 | |||
794022d399 | |||
8e43190984 | |||
2212a6e40f | |||
63b69c0b0c | |||
278219b1d8 | |||
2ce4ce9064 | |||
4448418b63 | |||
9f1f37e780 | |||
40ccd1a469 | |||
a4ef0940ed | |||
2ff0aa09e3 | |||
32217a774f | |||
8856c8cd62 | |||
e843b8e188 | |||
c4f2e3a955 | |||
91301ec7fe | |||
13b03e7e50 | |||
8a0aa5a0c8 | |||
2bd8e7dca4 | |||
d75571ffa1 | |||
8683d529fc | |||
2ee4b6768d | |||
a9f0a85590 | |||
37160f973f | |||
9bbf50e864 | |||
51258ab28c | |||
29e5a213a5 | |||
2d261607df | |||
54144154f9 | |||
81daffe68e | |||
2ea20a8b29 | |||
2257c875f5 | |||
8a2e8ad953 | |||
fa5b1d9978 | |||
529fb07b42 | |||
4a261cac1a | |||
b3c8f9d508 | |||
1b878030aa | |||
46e403b20b | |||
1b1f728c58 | |||
309013efb3 | |||
705cf6499e | |||
f2ed4a92e2 | |||
0c8ca1b3c0 | |||
6ee5ee496e | |||
7f8aa2099c | |||
1d9797660b | |||
cd0d8a76c5 | |||
3f1251e78b | |||
89d4405563 | |||
8966364648 | |||
1c60e9b4fc | |||
843c860d98 | |||
6587e39992 | |||
757fa1410c | |||
dd6d8e0002 | |||
cd49406bfe | |||
7a3acc3249 | |||
db1c804812 | |||
493d58f358 | |||
fcd56dddc2 | |||
91b85f9919 | |||
4cecba8787 | |||
5930acc418 | |||
61d36c1723 | |||
c2a43c6f40 | |||
1ab00ca8b2 | |||
778baa6dbe | |||
25ab121e42 | |||
cf4949b4f5 | |||
4ca634d229 | |||
ca21b31696 | |||
38ff76d2b8 | |||
147bde5294 | |||
1a004f0c4d | |||
7d21bf15e8 | |||
a88ad8025b | |||
e06bf17d13 | |||
04a3669fc4 | |||
795075f90d | |||
2727df704f | |||
8ce8aadd9b | |||
2999e69f0f | |||
7ac16ed073 | |||
3585e4764b | |||
065e38c6aa | |||
9054ee18a1 | |||
9d8b95107d | |||
8731c86d0d | |||
d7fad4bd04 | |||
2746251dcd | |||
73e46e569f | |||
4f0f74d201 | |||
adf1e1982a | |||
f5405e835e | |||
85ee7fb3a4 | |||
ee00a5d8ee | |||
65d23fc9b9 | |||
3448d7cb70 | |||
db1abb02d6 | |||
36d78577e2 | |||
20832682ef | |||
8e6c592ad9 | |||
0b3115997a | |||
b07c5982e1 | |||
4a0b0d8735 | |||
7b9f67f4b4 | |||
577f17c916 | |||
d4c1d62781 | |||
80da1f1bb9 | |||
febdb85f96 | |||
96b76c8f5c | |||
411bf3be03 | |||
a98b6663e1 | |||
e7f35e6ca3 | |||
f0ec165d42 | |||
abd240468e | |||
b5e00027d1 | |||
1698554024 | |||
f4604bbf79 | |||
699ad316f0 | |||
fcbe233fdb | |||
4af8a9ed2d | |||
80627b4f89 | |||
83078cd49a | |||
53e0d13142 | |||
85901082a2 | |||
f19e27e875 | |||
c864046cee | |||
2d68235e55 | |||
2be8100e7c | |||
ab3e2562db | |||
123d6c72e4 | |||
0ea2135aa5 | |||
48e20cb5f7 | |||
0ffe0b6894 | |||
338156500b | |||
bfd9bd43c9 | |||
283e50e670 | |||
6fb5bb6a5e | |||
5d3bef32ca | |||
3ff26d5cfe | |||
88c1e504b0 | |||
0263677e1f | |||
940455f81c | |||
f541ea659c | |||
938cae1130 | |||
7f73e57c67 | |||
e50ec31351 | |||
a28fa219d7 | |||
8a1ba03bcb | |||
f8e7fb3d48 | |||
e8b7e70ec9 | |||
67c5aa0be9 | |||
e644380160 | |||
c5eb6fe6fb | |||
ae2ef324f2 | |||
d0337da8ea | |||
17b30b2ae2 | |||
5e17d53c7f | |||
22e0527502 | |||
ca3c6c5e8a | |||
4bd30f5e72 | |||
3cc26b15a1 | |||
9673dac22b | |||
0426149580 | |||
fce5c57548 | |||
4ee5264e24 | |||
101ca60b2b | |||
f28a0aa666 | |||
997bf91442 | |||
5a1de15332 | |||
42f8ec5b14 | |||
2fc1b99911 | |||
3a923060ce | |||
0985adfd74 | |||
59d628208b | |||
5c5699bba5 | |||
67e0214fa5 | |||
e17b6804a7 | |||
96e36f0604 | |||
a99858c64d | |||
ba50765c30 | |||
d7f6b36990 | |||
4439666e67 | |||
23febc6d94 | |||
fab4a7a602 | |||
092d2f8917 | |||
e9fb566c07 | |||
5a34e8fd7c | |||
fcfb2cfc3d | |||
e93b9560b5 | |||
8e4438b375 | |||
eaa5ce4467 | |||
c86c719e1a | |||
b30b88716e | |||
c3e6b1aa8a | |||
6d0ea13f97 | |||
dca4ea5cea | |||
be1e2c07ec | |||
2a0018e730 | |||
ac4497a1f2 | |||
d72c75db23 | |||
6821a45b7f | |||
f24cdd6564 | |||
cb69869836 | |||
0b85051a23 | |||
f2e2053134 | |||
b181f4bc30 | |||
f00dbdc215 | |||
309dcc82ca | |||
0922a7f410 | |||
7d91db607f | |||
2be583ad4d | |||
efcba698ac | |||
b191291737 | |||
c988b4d213 | |||
90007e2d9d | |||
29ef1e2c4b | |||
fbe84f9e47 | |||
b036d95bab | |||
bfffcb3910 | |||
3bc02b9662 | |||
bc450e4cee | |||
de02deac98 | |||
e2ad3b0183 | |||
caf6d02728 | |||
35f71f5793 | |||
b2a89ee4b9 | |||
b84d52be3d | |||
305973c0e7 | |||
7c251efc47 | |||
166f872712 | |||
8f2c485c92 | |||
613f2fc447 | |||
9a0d6124f3 | |||
2646ae29f0 | |||
b4707f46ad | |||
482e049ac7 | |||
c04adf7452 | |||
92e8aaf36f | |||
b1f486518e | |||
3cab0e69f1 | |||
1ec7878c07 | |||
cdd83c279c | |||
12cadf3af0 | |||
2bc6da038d | |||
3b4b34b369 | |||
6542f5f15a | |||
30b56dbcbd | |||
cbc8c1aed6 | |||
6afe59e76b | |||
88a93945d4 | |||
2847cefff7 | |||
96f16069a9 | |||
188c5aaa35 | |||
f5f59203a2 | |||
c329730de8 | |||
97a83c9b7a | |||
1e6df7eec0 | |||
f3c72f4f08 | |||
05cd30ac06 | |||
34adcec616 | |||
f9f46609ee | |||
b5bdfa6c2e | |||
ea4ef1655b | |||
7eb61a28be | |||
92b913ca37 | |||
3806f23b02 | |||
36045a8b0a | |||
943090db98 | |||
77caaca50d | |||
f66e0fa0e8 | |||
441075f610 | |||
b2878dca1d | |||
b883ce5c51 | |||
127dfadc6c | |||
ff9f3cb31f | |||
a21bd41580 | |||
8e9f1bcf18 | |||
4b06fc5323 | |||
cc27bb3231 | |||
c1700054f4 | |||
cc13310083 | |||
1012912272 | |||
edbd90a4e6 | |||
ddc3b5eb0b | |||
17bbfe8d89 | |||
96deb5b09d | |||
9b387d73e5 | |||
c02a6780b0 | |||
85ec9d95a4 | |||
6dfec4db40 | |||
2e9d7f5c3d | |||
696a711e39 | |||
887246a66b | |||
2993318d19 | |||
2b52cf01f5 | |||
cd9e0e0cc0 | |||
f66598db8a | |||
cf5c752dda | |||
a6d2c5e181 | |||
82760f4b91 | |||
62e099ace5 | |||
e92b7bd25e | |||
e7bb3b2776 | |||
ec3c882a44 | |||
66ce5a4a2d | |||
a110d445ac | |||
a67f3131e7 | |||
7f305aad1b | |||
80908efdcb | |||
e5d0097116 | |||
6d78ea5a45 | |||
550d6a6a9b | |||
9be8160bf2 | |||
3070565fa3 | |||
7194bb1b81 | |||
78cf0c73c8 | |||
4adc61bda9 | |||
93e0041d0e | |||
682a7fb6ba | |||
5f2398fe59 | |||
3abf466632 | |||
4bb429a0fb | |||
4a0e4fdb85 | |||
a43f882d48 | |||
9731e06728 | |||
8e764fc8fb | |||
4745ed2818 | |||
49de5d9b07 | |||
365cc198ba | |||
9899a0e098 | |||
5ea8cec16f | |||
9dd70ca9ae | |||
4fda35b466 | |||
31988f0529 | |||
db03846358 | |||
c6b3eccbdf | |||
3f259eb97a | |||
fac0b027b3 | |||
84b962f256 | |||
123ed5bd2e | |||
c3336251e0 | |||
c054d0f329 | |||
8dd68580a6 | |||
067484a6a8 | |||
c83e16aba4 | |||
d85fc456a9 | |||
dd2b324d8f | |||
0bce08d30f | |||
57d65177c8 | |||
040ee919e5 | |||
efa3fbff39 | |||
8c8eabf7ac | |||
3aea639fe4 | |||
046f1e6e58 | |||
37e8f495b4 | |||
512d7b07d0 | |||
527fa7ba9c | |||
288e7bc9c5 | |||
649b8ac7c6 | |||
96b2758169 | |||
40e0252d7d | |||
5171d99fe5 | |||
ea9d61c21c | |||
da25f3b84e | |||
1e34de98ab | |||
7b46f50cf1 | |||
cab40026f2 | |||
ac66bddeda | |||
f4237be9bd | |||
dd11ccb3fd | |||
c4549a5375 | |||
e9b3140d12 | |||
bdd2d57808 | |||
22f5128e39 | |||
ae1aa6f63e | |||
29a53d7e95 | |||
2fbb7be23b | |||
f7f39854f8 | |||
113528e1f2 | |||
6bffa06063 | |||
dcc41ef885 | |||
e909cc363d | |||
9a87ae575e | |||
860a7af679 | |||
4fdb21b414 | |||
eeb5297284 | |||
8de63b60b1 | |||
0b38d878a1 | |||
d29720fbce | |||
0556ae4749 | |||
1a86f72690 | |||
25d380f051 | |||
546d394868 | |||
8110040f86 | |||
239e4adf29 | |||
5662d41062 | |||
1e03ef484d | |||
1d95f10090 | |||
6768768373 | |||
dac801c8ac | |||
ece5ca52b2 | |||
3205d9e9da | |||
b931dc0f93 | |||
efe4e7df06 | |||
b94f70ea96 | |||
bd946c78f3 | |||
a507907443 | |||
0507b56bed | |||
ac405aa564 | |||
aad7c63282 | |||
1ff459d995 | |||
52454ca77b | |||
884f772362 | |||
bc06571dba | |||
1e8ad3d979 | |||
b0a469baab | |||
c968c1be78 | |||
a0bafa4952 | |||
e56f0db11b | |||
8bcbe07c87 | |||
ba9059c7c8 | |||
45783c1661 | |||
71777e7a6f | |||
c86ec0bd36 | |||
08b1b2669a | |||
94a655b055 | |||
717067e9eb | |||
5a5797d914 | |||
75826aca13 | |||
f52b7c030f | |||
c1386bcb04 | |||
234a9e48e9 | |||
908e6364c9 | |||
3ec511010f | |||
b3e1691c01 |
16
.clang-format
Normal file
16
.clang-format
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Chromium
|
||||
IndentWidth: 4
|
||||
AlignConsecutiveMacros: false
|
||||
AlignConsecutiveAssignments: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBraces: Custom
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
ColumnLimit: 140
|
||||
Cpp11BracedListStyle: false
|
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
open_collective: polymc
|
14
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
14
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -23,6 +23,20 @@ body:
|
||||
- macOS
|
||||
- Linux
|
||||
- Other
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Version of PolyMC
|
||||
description: The version of PolyMC used in the bug report.
|
||||
placeholder: PolyMC 1.4.1
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Version of Qt
|
||||
description: The version of Qt used in the bug report. You can find it in Help -> About PolyMC -> About Qt.
|
||||
placeholder: Qt 6.3.0
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description of bug
|
||||
|
3
.github/codeql/codeql-config.yml
vendored
Normal file
3
.github/codeql/codeql-config.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
query-filters:
|
||||
- exclude:
|
||||
id: cpp/fixme-comment
|
2
.github/dco.yml
vendored
Normal file
2
.github/dco.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
allowRemediationCommits:
|
||||
individual: true
|
19
.github/workflows/backport.yml
vendored
19
.github/workflows/backport.yml
vendored
@ -1,19 +0,0 @@
|
||||
name: Backport PR to stable
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ develop ]
|
||||
types: [ closed ]
|
||||
jobs:
|
||||
release_pull_request:
|
||||
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'backport')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Backport PR by cherry-pick-ing
|
||||
uses: Nathanmalnoury/gh-backport-action@master
|
||||
with:
|
||||
pr_branch: 'stable'
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
268
.github/workflows/build.yml
vendored
268
.github/workflows/build.yml
vendored
@ -7,6 +7,10 @@ on:
|
||||
description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
|
||||
type: string
|
||||
default: Debug
|
||||
secrets:
|
||||
SPARKLE_ED25519_KEY:
|
||||
description: Private key for signing Sparkle updates
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -16,17 +20,39 @@ jobs:
|
||||
include:
|
||||
|
||||
- os: ubuntu-20.04
|
||||
qt_ver: 5
|
||||
|
||||
- os: ubuntu-20.04
|
||||
qt_ver: 6
|
||||
qt_host: linux
|
||||
qt_version: '6.2.4'
|
||||
qt_modules: 'qt5compat qtimageformats'
|
||||
|
||||
- os: windows-2022
|
||||
name: "Windows-i686"
|
||||
msystem: mingw32
|
||||
name: "Windows-Legacy"
|
||||
msystem: clang32
|
||||
qt_ver: 5
|
||||
|
||||
- os: windows-2022
|
||||
name: "Windows-x86_64"
|
||||
msystem: mingw64
|
||||
name: "Windows"
|
||||
msystem: clang64
|
||||
qt_ver: 6
|
||||
|
||||
- os: macos-11
|
||||
- os: macos-12
|
||||
name: macOS
|
||||
macosx_deployment_target: 10.15
|
||||
qt_ver: 6
|
||||
qt_host: mac
|
||||
qt_version: '6.3.0'
|
||||
qt_modules: 'qt5compat qtimageformats'
|
||||
|
||||
- os: macos-12
|
||||
name: macOS-Legacy
|
||||
macosx_deployment_target: 10.13
|
||||
qt_ver: 5
|
||||
qt_host: mac
|
||||
qt_version: '5.15.2'
|
||||
qt_modules: ''
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@ -36,6 +62,7 @@ jobs:
|
||||
INSTALL_PORTABLE_DIR: "install-portable"
|
||||
INSTALL_APPIMAGE_DIR: "install-appdir"
|
||||
BUILD_DIR: "build"
|
||||
CCACHE_VAR: ""
|
||||
|
||||
steps:
|
||||
##
|
||||
@ -46,6 +73,14 @@ jobs:
|
||||
with:
|
||||
submodules: 'true'
|
||||
|
||||
- name: Initialize CodeQL
|
||||
if: runner.os == 'Linux' && matrix.qt_ver == 6
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
queries: security-and-quality
|
||||
languages: cpp, java
|
||||
|
||||
- name: 'Setup MSYS2'
|
||||
if: runner.os == 'Windows'
|
||||
uses: msys2/setup-msys2@v2
|
||||
@ -54,11 +89,49 @@ jobs:
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
mingw-w64-x86_64-binutils
|
||||
pacboy: >-
|
||||
toolchain:p
|
||||
cmake:p
|
||||
extra-cmake-modules:p
|
||||
ninja:p
|
||||
qt5:p
|
||||
qt${{ matrix.qt_ver }}-base:p
|
||||
qt${{ matrix.qt_ver }}-svg:p
|
||||
qt${{ matrix.qt_ver }}-imageformats:p
|
||||
quazip-qt${{ matrix.qt_ver }}:p
|
||||
ccache:p
|
||||
${{ matrix.qt_ver == 6 && 'qt6-5compat:p' || '' }}
|
||||
|
||||
- name: Setup ccache
|
||||
if: runner.os != 'Windows' && inputs.build_type == 'Debug'
|
||||
uses: hendrikmuhs/ccache-action@v1.2.3
|
||||
with:
|
||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
||||
|
||||
- name: Setup ccache (Windows)
|
||||
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
|
||||
ccache --set-config=max_size='500M'
|
||||
ccache --set-config=compression=true
|
||||
ccache -p # Show config
|
||||
ccache -z # Zero stats
|
||||
|
||||
- name: Use ccache on Debug builds only
|
||||
if: inputs.build_type == 'Debug'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "CCACHE_VAR=ccache" >> $GITHUB_ENV
|
||||
|
||||
- name: Retrieve ccache cache (Windows)
|
||||
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
||||
uses: actions/cache@v3.0.11
|
||||
with:
|
||||
path: '${{ github.workspace }}\.ccache'
|
||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
||||
|
||||
- name: Set short version
|
||||
shell: bash
|
||||
@ -66,30 +139,36 @@ jobs:
|
||||
ver_short=`git rev-parse --short HEAD`
|
||||
echo "VERSION=$ver_short" >> $GITHUB_ENV
|
||||
|
||||
- name: Install OpenJDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Install Qt (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew update
|
||||
brew install qt@5
|
||||
|
||||
- name: Install Qt (Linux)
|
||||
- name: Install Dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
|
||||
sudo apt-get -y install ninja-build extra-cmake-modules scdoc
|
||||
|
||||
- name: Install Ninja
|
||||
if: runner.os != 'Windows'
|
||||
uses: urkle/action-get-ninja@v1
|
||||
- name: Install Dependencies (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew update
|
||||
brew install ninja extra-cmake-modules
|
||||
|
||||
- name: Install Qt (Linux)
|
||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||
run: |
|
||||
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
|
||||
|
||||
- name: Install Qt (macOS and AppImage)
|
||||
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ matrix.qt_version }}
|
||||
host: ${{ matrix.qt_host }}
|
||||
target: 'desktop'
|
||||
modules: ${{ matrix.qt_modules }}
|
||||
cache: true
|
||||
cache-key-prefix: ${{ matrix.qt_host }}-${{ matrix.qt_version }}-"${{ matrix.qt_modules }}"-qt_cache
|
||||
|
||||
- name: Prepare AppImage (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||
run: |
|
||||
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
|
||||
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage"
|
||||
@ -102,20 +181,25 @@ jobs:
|
||||
##
|
||||
|
||||
- name: Configure CMake (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
if: runner.os == 'macOS' && matrix.qt_ver == 6
|
||||
run: |
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DQt5_DIR=/usr/local/opt/qt@5 -DCMAKE_PREFIX_PATH=/usr/local/opt/qt@5 -DLauncher_BUILD_PLATFORM=macOS -G Ninja
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
|
||||
|
||||
- name: Configure CMake (macOS-Legacy)
|
||||
if: runner.os == 'macOS' && matrix.qt_ver == 5
|
||||
run: |
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja
|
||||
|
||||
- name: Configure CMake (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -G Ninja
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -G Ninja
|
||||
|
||||
- name: Configure CMake (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=Linux -G Ninja
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=Linux -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -G Ninja
|
||||
|
||||
##
|
||||
# BUILD
|
||||
@ -132,6 +216,29 @@ jobs:
|
||||
run: |
|
||||
cmake --build ${{ env.BUILD_DIR }}
|
||||
|
||||
##
|
||||
# TEST
|
||||
##
|
||||
|
||||
- name: Test
|
||||
if: runner.os != 'Windows'
|
||||
run: |
|
||||
ctest --test-dir build --output-on-failure
|
||||
|
||||
- name: Test (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
ctest --test-dir build --output-on-failure
|
||||
|
||||
##
|
||||
# CODE SCAN
|
||||
##
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
if: runner.os == 'Linux' && matrix.qt_ver == 6
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
##
|
||||
# PACKAGE BUILDS
|
||||
##
|
||||
@ -142,9 +249,29 @@ jobs:
|
||||
cmake --install ${{ env.BUILD_DIR }}
|
||||
|
||||
cd ${{ env.INSTALL_DIR }}
|
||||
chmod +x "PolyMC.app/Contents/MacOS/polymc"
|
||||
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PolyMC.app/Contents/MacOS/polymc"
|
||||
tar -czf ../PolyMC.tar.gz *
|
||||
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||
mv "PrismLauncher.app" "Prism Launcher.app"
|
||||
tar -czf ../PrismLauncher.tar.gz *
|
||||
|
||||
- name: Make Sparkle signature (macOS)
|
||||
if: matrix.name == 'macOS'
|
||||
run: |
|
||||
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
||||
brew install openssl@3
|
||||
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
|
||||
signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.tar.gz -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
||||
rm ed25519-priv.pem
|
||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||
### Artifact Information :information_source:
|
||||
- :memo: Sparkle Signature (ed25519): \`$signature\`
|
||||
EOF
|
||||
else
|
||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||
### Artifact Information :information_source:
|
||||
- :warning: Sparkle Signature (ed25519): No private key available (likely a pull request or fork)
|
||||
EOF
|
||||
fi
|
||||
|
||||
- name: Package (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
@ -153,10 +280,8 @@ jobs:
|
||||
cmake --install ${{ env.BUILD_DIR }}
|
||||
|
||||
cd ${{ env.INSTALL_DIR }}
|
||||
if [ "${{ matrix.msystem }}" == "mingw32" ]; then
|
||||
cp /mingw32/bin/libcrypto-1_1.dll /mingw32/bin/libssl-1_1.dll ./
|
||||
elif [ "${{ matrix.msystem }}" == "mingw64" ]; then
|
||||
cp /mingw64/bin/libcrypto-1_1-x64.dll /mingw64/bin/libssl-1_1-x64.dll ./
|
||||
if [ "${{ matrix.qt_ver }}" == "5" ]; then
|
||||
cp /clang32/bin/libcrypto-1_1.dll /clang32/bin/libssl-1_1.dll ./
|
||||
fi
|
||||
|
||||
- name: Package (Windows, portable)
|
||||
@ -166,13 +291,19 @@ jobs:
|
||||
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||
|
||||
- name: Package (Windows, installer)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
cd ${{ env.INSTALL_DIR }}
|
||||
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
||||
|
||||
- name: Package (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }}
|
||||
|
||||
cd ${{ env.INSTALL_DIR }}
|
||||
tar --owner root --group root -czf ../PolyMC.tar.gz *
|
||||
tar --owner root --group root -czf ../PrismLauncher.tar.gz *
|
||||
|
||||
- name: Package (Linux, portable)
|
||||
if: runner.os == 'Linux'
|
||||
@ -181,24 +312,30 @@ jobs:
|
||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||
|
||||
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
||||
tar -czf ../PolyMC-portable.tar.gz *
|
||||
tar -czf ../PrismLauncher-portable.tar.gz *
|
||||
|
||||
- name: Package AppImage (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||
shell: bash
|
||||
run: |
|
||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
|
||||
|
||||
export OUTPUT="PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
||||
export OUTPUT="PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
||||
|
||||
chmod +x linuxdeploy-*.AppImage
|
||||
|
||||
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-{8,17}-openjdk
|
||||
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
||||
|
||||
cp -r ${{ github.workspace }}/JREs/jre8/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk
|
||||
|
||||
cp -r ${{ github.workspace }}/JREs/jre17/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk
|
||||
|
||||
cp -r /home/runner/work/PrismLauncher/Qt/${{ matrix.qt_version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
||||
|
||||
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
||||
cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}//usr/lib/
|
||||
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib"
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64/server"
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64"
|
||||
@ -206,7 +343,7 @@ jobs:
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib"
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.polymc.PolyMC.svg
|
||||
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.prismlauncher.PrismLauncher.svg
|
||||
|
||||
##
|
||||
# UPLOAD BUILDS
|
||||
@ -216,42 +353,63 @@ jobs:
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PolyMC.tar.gz
|
||||
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PrismLauncher.tar.gz
|
||||
|
||||
- name: Upload binary zip (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: ${{ env.INSTALL_DIR }}/**
|
||||
|
||||
- name: Upload binary zip (Windows, portable)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
||||
|
||||
- name: Upload binary tarball (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
- name: Upload installer (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PolyMC.tar.gz
|
||||
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PrismLauncher-Setup.exe
|
||||
|
||||
- name: Upload binary tarball (Linux, portable)
|
||||
if: runner.os == 'Linux'
|
||||
- name: Upload binary tarball (Linux, Qt 5)
|
||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ runner.os }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PolyMC-portable.tar.gz
|
||||
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PrismLauncher.tar.gz
|
||||
|
||||
- name: Upload binary tarball (Linux, portable, Qt 5)
|
||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PrismLauncher-${{ runner.os }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PrismLauncher-portable.tar.gz
|
||||
|
||||
- name: Upload binary tarball (Linux, Qt 6)
|
||||
if: runner.os == 'Linux' && matrix.qt_ver !=5
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PrismLauncher.tar.gz
|
||||
|
||||
- name: Upload binary tarball (Linux, portable, Qt 6)
|
||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PrismLauncher-portable.tar.gz
|
||||
|
||||
- name: Upload AppImage (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||
path: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||
|
||||
|
||||
|
61
.github/workflows/pr-comment.yml
vendored
61
.github/workflows/pr-comment.yml
vendored
@ -1,61 +0,0 @@
|
||||
name: Comment on pull request
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['Test workflow with upload']
|
||||
types: [completed]
|
||||
jobs:
|
||||
pr_comment:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v5
|
||||
with:
|
||||
# This snippet is public-domain, taken from
|
||||
# https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml
|
||||
script: |
|
||||
async function upsertComment(owner, repo, issue_number, purpose, body) {
|
||||
const {data: comments} = await github.rest.issues.listComments(
|
||||
{owner, repo, issue_number});
|
||||
|
||||
const marker = `<!-- bot: ${purpose} -->`;
|
||||
body = marker + "\n" + body;
|
||||
|
||||
const existing = comments.filter((c) => c.body.includes(marker));
|
||||
if (existing.length > 0) {
|
||||
const last = existing[existing.length - 1];
|
||||
core.info(`Updating comment ${last.id}`);
|
||||
await github.rest.issues.updateComment({
|
||||
owner, repo,
|
||||
body,
|
||||
comment_id: last.id,
|
||||
});
|
||||
} else {
|
||||
core.info(`Creating a comment in issue / PR #${issue_number}`);
|
||||
await github.rest.issues.createComment({issue_number, body, owner, repo});
|
||||
}
|
||||
}
|
||||
|
||||
const {owner, repo} = context.repo;
|
||||
const run_id = ${{github.event.workflow_run.id}};
|
||||
|
||||
const pull_requests = ${{ toJSON(github.event.workflow_run.pull_requests) }};
|
||||
if (!pull_requests.length) {
|
||||
return core.error("This workflow doesn't match any pull requests!");
|
||||
}
|
||||
|
||||
const artifacts = await github.paginate(
|
||||
github.rest.actions.listWorkflowRunArtifacts, {owner, repo, run_id});
|
||||
if (!artifacts.length) {
|
||||
return core.error(`No artifacts found`);
|
||||
}
|
||||
let body = `Download the artifacts for this pull request:\n`;
|
||||
for (const art of artifacts) {
|
||||
body += `\n* [${art.name}.zip](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||
}
|
||||
|
||||
core.info("Review thread message body:", body);
|
||||
|
||||
for (const pr of pull_requests) {
|
||||
await upsertComment(owner, repo, pr.number,
|
||||
"nightly-link", body);
|
||||
}
|
4
.github/workflows/trigger_builds.yml
vendored
4
.github/workflows/trigger_builds.yml
vendored
@ -11,6 +11,7 @@ on:
|
||||
- '**.nix'
|
||||
- 'packages/**'
|
||||
- '.github/ISSUE_TEMPLATE/**'
|
||||
- '.markdownlint**'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
@ -19,6 +20,7 @@ on:
|
||||
- '**.nix'
|
||||
- 'packages/**'
|
||||
- '.github/ISSUE_TEMPLATE/**'
|
||||
- '.markdownlint**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@ -28,3 +30,5 @@ jobs:
|
||||
uses: ./.github/workflows/build.yml
|
||||
with:
|
||||
build_type: Debug
|
||||
secrets:
|
||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||
|
55
.github/workflows/trigger_release.yml
vendored
55
.github/workflows/trigger_release.yml
vendored
@ -12,6 +12,8 @@ jobs:
|
||||
uses: ./.github/workflows/build.yml
|
||||
with:
|
||||
build_type: Release
|
||||
secrets:
|
||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||
|
||||
create_release:
|
||||
needs: build_release
|
||||
@ -23,7 +25,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'true'
|
||||
path: 'PolyMC-source'
|
||||
path: 'PrismLauncher-source'
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
- name: Grab and store version
|
||||
@ -32,21 +34,27 @@ jobs:
|
||||
echo "VERSION=$tag_name" >> $GITHUB_ENV
|
||||
- name: Package artifacts properly
|
||||
run: |
|
||||
mv ${{ github.workspace }}/PolyMC-source PolyMC-${{ env.VERSION }}
|
||||
mv PolyMC-Linux-Portable*/PolyMC-portable.tar.gz PolyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||
mv PolyMC-Linux*/PolyMC.tar.gz PolyMC-Linux-${{ env.VERSION }}.tar.gz
|
||||
mv PolyMC-*.AppImage/PolyMC-*.AppImage PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||
mv PolyMC-macOS*/PolyMC.tar.gz PolyMC-macOS-${{ env.VERSION }}.tar.gz
|
||||
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }}
|
||||
mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||
mv PrismLauncher-Linux-Qt6*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
||||
mv PrismLauncher-Linux-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||
mv PrismLauncher-Linux*/PrismLauncher.tar.gz PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
|
||||
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||
mv PrismLauncher-macOS-Legacy*/PrismLauncher.tar.gz PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
||||
mv PrismLauncher-macOS*/PrismLauncher.tar.gz PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
||||
|
||||
tar -czf PolyMC-${{ env.VERSION }}.tar.gz PolyMC-${{ env.VERSION }}
|
||||
tar -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
||||
|
||||
for d in PolyMC-Windows-*; do
|
||||
for d in PrismLauncher-Windows-*; do
|
||||
cd "${d}" || continue
|
||||
ARCH="$(echo -n ${d} | cut -d '-' -f 3)"
|
||||
LEGACY="$(echo -n ${d} | grep -o Legacy || true)"
|
||||
INST="$(echo -n ${d} | grep -o Setup || true)"
|
||||
PORT="$(echo -n ${d} | grep -o Portable || true)"
|
||||
NAME="PolyMC-Windows-${ARCH}"
|
||||
NAME="PrismLauncher-Windows"
|
||||
test -z "${LEGACY}" || NAME="${NAME}-Legacy"
|
||||
test -z "${PORT}" || NAME="${NAME}-Portable"
|
||||
zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
|
||||
test -z "${INST}" || mv PrismLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe
|
||||
test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
|
||||
cd ..
|
||||
done
|
||||
|
||||
@ -57,16 +65,21 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
name: PolyMC ${{ env.VERSION }}
|
||||
name: Prism Launcher ${{ env.VERSION }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
files: |
|
||||
PolyMC-Linux-${{ env.VERSION }}.tar.gz
|
||||
PolyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||
PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||
PolyMC-Windows-i686-${{ env.VERSION }}.zip
|
||||
PolyMC-Windows-i686-Portable-${{ env.VERSION }}.zip
|
||||
PolyMC-Windows-x86_64-${{ env.VERSION }}.zip
|
||||
PolyMC-Windows-x86_64-Portable-${{ env.VERSION }}.zip
|
||||
PolyMC-macOS-${{ env.VERSION }}.tar.gz
|
||||
PolyMC-${{ env.VERSION }}.tar.gz
|
||||
PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
|
||||
PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||
PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||
PrismLauncher-Windows-Legacy-${{ env.VERSION }}.zip
|
||||
PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
||||
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||
PrismLauncher-Windows-Legacy-Portable-${{ env.VERSION }}.zip
|
||||
PrismLauncher-Windows-Legacy-Setup-${{ env.VERSION }}.exe
|
||||
PrismLauncher-Windows-${{ env.VERSION }}.zip
|
||||
PrismLauncher-Windows-Portable-${{ env.VERSION }}.zip
|
||||
PrismLauncher-Windows-Setup-${{ env.VERSION }}.exe
|
||||
PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
||||
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
||||
PrismLauncher-${{ env.VERSION }}.tar.gz
|
||||
|
15
.github/workflows/winget.yml
vendored
Normal file
15
.github/workflows/winget.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
name: Publish to WinGet
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: vedantmgoyal2009/winget-releaser@v1
|
||||
with:
|
||||
identifier: PrismLauncher.PrismLauncher
|
||||
version: ${{ github.event.release.tag_name }}
|
||||
installers-regex: 'PrismLauncher-Windows-Setup-.+\.exe$'
|
||||
token: ${{ secrets.WINGET_TOKEN }}
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,6 +14,7 @@ CMakeLists.txt.user.*
|
||||
/.project
|
||||
/.settings
|
||||
/.idea
|
||||
/.vscode
|
||||
cmake-build-*/
|
||||
Debug
|
||||
|
||||
|
14
.gitmodules
vendored
14
.gitmodules
vendored
@ -1,8 +1,12 @@
|
||||
[submodule "depends/libnbtplusplus"]
|
||||
path = libraries/libnbtplusplus
|
||||
url = https://github.com/PolyMC/libnbtplusplus.git
|
||||
pushurl = git@github.com:PolyMC/libnbtplusplus.git
|
||||
|
||||
[submodule "libraries/quazip"]
|
||||
path = libraries/quazip
|
||||
url = https://github.com/stachenov/quazip.git
|
||||
[submodule "libraries/tomlplusplus"]
|
||||
path = libraries/tomlplusplus
|
||||
url = https://github.com/marzer/tomlplusplus.git
|
||||
[submodule "libraries/filesystem"]
|
||||
path = libraries/filesystem
|
||||
url = https://github.com/gulrak/filesystem
|
||||
[submodule "libraries/libnbtplusplus"]
|
||||
path = libraries/libnbtplusplus
|
||||
url = https://github.com/PrismLauncher/libnbtplusplus.git
|
||||
|
12
.markdownlint.yaml
Normal file
12
.markdownlint.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
# MD013/line-length - Line length
|
||||
MD013: false
|
||||
|
||||
# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content
|
||||
MD024:
|
||||
siblings-only: true
|
||||
|
||||
# MD033/no-inline-html Inline HTML
|
||||
MD033: false
|
||||
|
||||
# MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading
|
||||
MD041: false
|
2
.markdownlintignore
Normal file
2
.markdownlintignore
Normal file
@ -0,0 +1,2 @@
|
||||
libraries/nbtplusplus
|
||||
libraries/quazip
|
52
BUILD.md
52
BUILD.md
@ -1,5 +1,53 @@
|
||||
# Build Instructions
|
||||
|
||||
Build instructions are available on [the website](https://polymc.org/wiki/development/build-instructions/).
|
||||
Full build instructions will be available on [the website](https://prismlauncher.org/wiki/development/build-instructions/).
|
||||
|
||||
If you would like to contribute or fix an issue with the Build instructions you will be able to do so [here](https://github.com/PrismLauncher/website/blob/master/src/wiki/development/build-instructions.md).
|
||||
|
||||
## Getting the source
|
||||
|
||||
Clone the source code using git, and grab all the submodules. This is generic for all platforms you want to build on.
|
||||
```
|
||||
git clone --recursive https://github.com/PrismLauncher/PrismLauncher
|
||||
cd PrismLauncher
|
||||
```
|
||||
|
||||
## Linux
|
||||
|
||||
This guide will mostly mention dependant packages by their Debian naming and commands are done by a user in the sudoers file.
|
||||
### Dependencies
|
||||
|
||||
- A C++ compiler capable of building C++17 code (can be found in the package `build-essential`).
|
||||
- Qt Development tools 5.12 or newer (on Debian 11 or Debian-based distributions, `qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5`).
|
||||
- `cmake` 3.15 or newer.
|
||||
- `extra-cmake-modules`.
|
||||
- zlib (`zlib1g-dev` on Debian 11 or Debian-based distributions).
|
||||
- Java Development Kit (Java JDK) (`openjdk-17-jdk` on Debian 11 or Debian-based distributions).
|
||||
- Mesa GL headers (`libgl1-mesa-dev` on Debian 11 or Debian-based distributions).
|
||||
- (Optional) `scdoc` to generate man pages.
|
||||
|
||||
In conclusion, to check if all you need is installed (including optional):
|
||||
|
||||
```
|
||||
sudo apt install build-essential qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 cmake extra-cmake-modules zlib1g-dev openjdk-17-jdk libgl1-mesa-dev scdoc
|
||||
```
|
||||
|
||||
### Compiling
|
||||
#### Building and installing on the system
|
||||
This is usually the suggested way to build the client.
|
||||
|
||||
```
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="/usr" -DENABLE_LTO=ON
|
||||
cmake --build build -j$(nproc)
|
||||
sudo cmake --install build
|
||||
```
|
||||
|
||||
#### Building a portable binary
|
||||
|
||||
```
|
||||
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=install
|
||||
cmake --build build -j$(nproc)
|
||||
cmake --install build
|
||||
cmake --install build --component portable
|
||||
```
|
||||
|
||||
If you would like to contribute or fix an issue with the Build instructions you can do so [here](https://github.com/PolyMC/polymc.github.io/blob/master/src/wiki/development/build-instructions.md).
|
||||
|
184
CMakeLists.txt
184
CMakeLists.txt
@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.9.4)
|
||||
cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip
|
||||
|
||||
if(WIN32)
|
||||
# In Qt 5.1+ we have our own main() function, don't autolink to qtmain on Windows
|
||||
@ -6,14 +6,12 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
project(Launcher)
|
||||
include(CTest)
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
|
||||
if(IS_IN_SOURCE_BUILD)
|
||||
message(FATAL_ERROR "You are building the Launcher in-source. Please separate the build tree from the source tree.")
|
||||
endif()
|
||||
|
||||
|
||||
##################################### Set CMake options #####################################
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
@ -31,18 +29,19 @@ set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/jars)
|
||||
######## Set compiler flags ########
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED true)
|
||||
set(CMAKE_C_STANDARD_REQUIRED true)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
include(GenerateExportHeader)
|
||||
set(CMAKE_CXX_FLAGS " -Wall -pedantic -Werror -Wno-deprecated-declarations -D_GLIBCXX_USE_CXX11_ABI=0 -fstack-protector-strong --param=ssp-buffer-size=4 -O3 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS}")
|
||||
if(UNIX AND APPLE)
|
||||
set(CMAKE_CXX_FLAGS " -stdlib=libc++ ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror=return-type")
|
||||
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
||||
|
||||
# Fix build with Qt 5.13
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
|
||||
|
||||
# set CXXFLAGS for build targets
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
|
||||
option(ENABLE_LTO "Enable Link Time Optimization" off)
|
||||
|
||||
if(ENABLE_LTO)
|
||||
@ -59,20 +58,30 @@ if(ENABLE_LTO)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTING "Build the testing tree." ON)
|
||||
|
||||
find_package(ECM REQUIRED NO_MODULE)
|
||||
set(CMAKE_MODULE_PATH "${ECM_MODULE_PATH};${CMAKE_MODULE_PATH}")
|
||||
include(CTest)
|
||||
include(ECMAddTests)
|
||||
if(BUILD_TESTING)
|
||||
enable_testing()
|
||||
endif()
|
||||
|
||||
##################################### Set Application options #####################################
|
||||
|
||||
######## Set URLs ########
|
||||
set(Launcher_NEWS_RSS_URL "https://polymc.org/feed/feed.xml" CACHE STRING "URL to fetch PolyMC's news RSS feed from.")
|
||||
set(Launcher_NEWS_OPEN_URL "https://polymc.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
||||
set(Launcher_HELP_URL "https://polymc.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
||||
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
|
||||
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
||||
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
||||
|
||||
######## Set version numbers ########
|
||||
set(Launcher_VERSION_MAJOR 1)
|
||||
set(Launcher_VERSION_MINOR 2)
|
||||
set(Launcher_VERSION_HOTFIX 1)
|
||||
set(Launcher_VERSION_MAJOR 5)
|
||||
set(Launcher_VERSION_MINOR 1)
|
||||
|
||||
# Build number
|
||||
set(Launcher_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
|
||||
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
||||
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
||||
set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},0,0")
|
||||
|
||||
# Build platform.
|
||||
set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.")
|
||||
@ -81,85 +90,117 @@ set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the plat
|
||||
set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.")
|
||||
|
||||
# The metadata server
|
||||
set(Launcher_META_URL "https://meta.polymc.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
||||
set(Launcher_META_URL "https://meta.prismlauncher.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
||||
|
||||
# Imgur API Client ID
|
||||
set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can get from Imgur when you register an application")
|
||||
|
||||
# MSA Client ID
|
||||
set(Launcher_MSA_CLIENT_ID "549033b2-1532-4d4e-ae77-1bbaa46f9d74" CACHE STRING "Client ID you can get from Microsoft Identity Platform when you register an application")
|
||||
|
||||
# Bug tracker URL
|
||||
set(Launcher_BUG_TRACKER_URL "https://github.com/PolyMC/PolyMC/issues" CACHE STRING "URL for the bug tracker.")
|
||||
set(Launcher_BUG_TRACKER_URL "https://github.com/PrismLauncher/PrismLauncher/issues" CACHE STRING "URL for the bug tracker.")
|
||||
|
||||
# Translations Platform URL
|
||||
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/polymc/polymc/" CACHE STRING "URL for the translations platform.")
|
||||
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/prismlauncher/launcher/" CACHE STRING "URL for the translations platform.")
|
||||
|
||||
# Matrix Space
|
||||
set(Launcher_MATRIX_URL "https://matrix.to/#/#polymc:matrix.org" CACHE STRING "URL to the Matrix Space")
|
||||
set(Launcher_MATRIX_URL "https://matrix.to/#/#prismlauncher:matrix.org" CACHE STRING "URL to the Matrix Space")
|
||||
|
||||
# Discord URL
|
||||
set(Launcher_DISCORD_URL "https://discord.gg/Z52pwxWCHP" CACHE STRING "URL for the Discord guild.")
|
||||
|
||||
|
||||
set(Launcher_DISCORD_URL "https://discord.gg/prismlauncher" CACHE STRING "URL for the Discord guild.")
|
||||
|
||||
# Subreddit URL
|
||||
set(Launcher_SUBREDDIT_URL "https://www.reddit.com/r/PolyMCLauncher/" CACHE STRING "URL for the subreddit.")
|
||||
set(Launcher_SUBREDDIT_URL "https://www.reddit.com/r/PrismLauncher/" CACHE STRING "URL for the subreddit.")
|
||||
|
||||
# Builds
|
||||
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
|
||||
set(Launcher_QT_VERSION_MAJOR "5" CACHE STRING "Major Qt version to build against")
|
||||
|
||||
# API Keys
|
||||
# NOTE: These API keys are here for convenience. If you rebrand this software or intend to break the terms of service
|
||||
# of these platforms, please change these API keys beforehand.
|
||||
# Be aware that if you were to use these API keys for malicious purposes they might get revoked, which might cause
|
||||
# breakage to thousands of users.
|
||||
# If you don't plan to use these features of this software, you can just remove these values.
|
||||
|
||||
# By using this key in your builds you accept the terms of use laid down in
|
||||
# https://docs.microsoft.com/en-us/legal/microsoft-identity-platform/terms-of-use
|
||||
set(Launcher_MSA_CLIENT_ID "c36a9fb6-4f2a-41ff-90bd-ae7cc92031eb" CACHE STRING "Client ID you can get from Microsoft Identity Platform when you register an application")
|
||||
|
||||
# By using this key in your builds you accept the terms and conditions laid down in
|
||||
# https://support.curseforge.com/en/support/solutions/articles/9000207405-curse-forge-3rd-party-api-terms-and-conditions
|
||||
# NOTE: CurseForge requires you to change this if you make any kind of derivative work.
|
||||
# This key was issued specifically for Prism Launcher
|
||||
set(Launcher_CURSEFORGE_API_KEY "$2a$10$wuAJuNZuted3NORVmpgUC.m8sI.pv1tOPKZyBgLFGjxFp/br0lZCC" CACHE STRING "API key for the CurseForge platform")
|
||||
|
||||
|
||||
#### Check the current Git commit and branch
|
||||
include(GetGitRevisionDescription)
|
||||
git_get_exact_tag(Launcher_GIT_TAG)
|
||||
get_git_head_revision(Launcher_GIT_REFSPEC Launcher_GIT_COMMIT)
|
||||
|
||||
message(STATUS "Git commit: ${Launcher_GIT_COMMIT}")
|
||||
message(STATUS "Git tag: ${Launcher_GIT_TAG}")
|
||||
message(STATUS "Git refspec: ${Launcher_GIT_REFSPEC}")
|
||||
|
||||
set(Launcher_RELEASE_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||
string(TIMESTAMP TODAY "%Y-%m-%d")
|
||||
set(Launcher_RELEASE_TIMESTAMP "${TODAY}")
|
||||
|
||||
#### Custom target to just print the version.
|
||||
add_custom_target(version echo "Version: ${Launcher_RELEASE_VERSION_NAME}")
|
||||
add_custom_target(tcversion echo "\\#\\#teamcity[setParameter name=\\'env.LAUNCHER_VERSION\\' value=\\'${Launcher_RELEASE_VERSION_NAME}\\']")
|
||||
set(Launcher_BUILD_TIMESTAMP "${TODAY}")
|
||||
|
||||
################################ 3rd Party Libs ################################
|
||||
|
||||
# Find the required Qt parts
|
||||
include(QtVersionlessBackport)
|
||||
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
||||
set(QT_VERSION_MAJOR 5)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml)
|
||||
|
||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||
find_package(QuaZip-Qt5 1.3)
|
||||
find_package(QuaZip-Qt5 1.3 QUIET)
|
||||
endif()
|
||||
if (NOT QuaZip-Qt5_FOUND)
|
||||
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
|
||||
set(FORCE_BUNDLED_QUAZIP 1)
|
||||
endif()
|
||||
|
||||
# Qt 6 sets these by default. Notably causes Windows APIs to use UNICODE strings.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
|
||||
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
||||
set(QT_VERSION_MAJOR 6)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml Core5Compat)
|
||||
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
|
||||
|
||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||
find_package(QuaZip-Qt6 1.3 QUIET)
|
||||
endif()
|
||||
if (NOT QuaZip-Qt6_FOUND)
|
||||
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
|
||||
set(FORCE_BUNDLED_QUAZIP 1)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
|
||||
endif()
|
||||
|
||||
# The Qt5 cmake files don't provide its install paths, so ask qmake.
|
||||
include(QMakeQuery)
|
||||
query_qmake(QT_INSTALL_PLUGINS QT_PLUGINS_DIR)
|
||||
query_qmake(QT_INSTALL_IMPORTS QT_IMPORTS_DIR)
|
||||
query_qmake(QT_INSTALL_LIBS QT_LIBS_DIR)
|
||||
query_qmake(QT_INSTALL_LIBEXECS QT_LIBEXECS_DIR)
|
||||
query_qmake(QT_HOST_DATA QT_DATA_DIR)
|
||||
include(ECMQueryQt)
|
||||
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
|
||||
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
|
||||
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
|
||||
ecm_query_qt(QT_DATA_DIR QT_HOST_DATA)
|
||||
set(QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs)
|
||||
|
||||
# NOTE: Qt 6 already sets this by default
|
||||
if (Qt5_POSITION_INDEPENDENT_CODE)
|
||||
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||
# Find toml++
|
||||
find_package(tomlplusplus 3.2.0 QUIET)
|
||||
|
||||
# Find ghc_filesystem
|
||||
find_package(ghc_filesystem QUIET)
|
||||
endif()
|
||||
|
||||
####################################### Program Info #######################################
|
||||
|
||||
set(Launcher_APP_BINARY_NAME "polymc" CACHE STRING "Name of the Launcher binary")
|
||||
set(Launcher_APP_BINARY_NAME "prismlauncher" CACHE STRING "Name of the Launcher binary")
|
||||
add_subdirectory(program_info)
|
||||
|
||||
####################################### Install layout #######################################
|
||||
@ -173,6 +214,7 @@ if(UNIX AND APPLE)
|
||||
set(BINARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
||||
set(LIBRARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
||||
set(PLUGIN_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
||||
set(FRAMEWORK_DEST_DIR "${Launcher_Name}.app/Contents/Frameworks")
|
||||
set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources")
|
||||
set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars")
|
||||
|
||||
@ -180,17 +222,23 @@ if(UNIX AND APPLE)
|
||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.app")
|
||||
|
||||
# Mac bundle settings
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}")
|
||||
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.polymc.${Launcher_Name}")
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_DisplayName}")
|
||||
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_DisplayName}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.prismlauncher.${Launcher_Name}")
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2021-2022 ${Launcher_Copyright}")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "© 2022 ${Launcher_Copyright_Mac}")
|
||||
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=")
|
||||
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml")
|
||||
|
||||
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.1.0/Sparkle-2.1.0.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
||||
set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
||||
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
||||
|
||||
# directories to look for dependencies
|
||||
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${MACOSX_SPARKLE_DIR})
|
||||
|
||||
# install as bundle
|
||||
set(INSTALL_BUNDLE "full")
|
||||
@ -201,7 +249,7 @@ if(UNIX AND APPLE)
|
||||
elseif(UNIX)
|
||||
set(BINARY_DEST_DIR "bin")
|
||||
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
||||
set(JARS_DEST_DIR "share/jars")
|
||||
set(JARS_DEST_DIR "share/${Launcher_APP_BINARY_NAME}")
|
||||
set(LAUNCHER_DESKTOP_DEST_DIR "share/applications" CACHE STRING "Path to the desktop file directory")
|
||||
set(LAUNCHER_METAINFO_DEST_DIR "share/metainfo" CACHE STRING "Path to the metainfo directory")
|
||||
set(LAUNCHER_ICON_DEST_DIR "share/icons/hicolor/scalable/apps" CACHE STRING "Path to the scalable icon directory")
|
||||
@ -213,13 +261,13 @@ elseif(UNIX)
|
||||
# Set RPATH
|
||||
SET(Launcher_BINARY_RPATH "$ORIGIN/")
|
||||
|
||||
# jars path is determined on runtime, relative to "Application root path", generally /usr or the root of the portable bundle
|
||||
set(Launcher_APP_BINARY_DEFS "-DLAUNCHER_JARS_LOCATION=${JARS_DEST_DIR}")
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${LAUNCHER_DESKTOP_DEST_DIR})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${LAUNCHER_METAINFO_DEST_DIR})
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION ${LAUNCHER_ICON_DEST_DIR})
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_ManPage} DESTINATION ${LAUNCHER_MAN_DEST_DIR} RENAME "${Launcher_APP_BINARY_NAME}.6")
|
||||
|
||||
if(Launcher_ManPage)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION ${LAUNCHER_MAN_DEST_DIR})
|
||||
endif()
|
||||
|
||||
# Install basic runner script if component "portable" is selected
|
||||
configure_file(launcher/Launcher.in "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" @ONLY)
|
||||
@ -258,7 +306,6 @@ add_subdirectory(libraries/systeminfo) # system information library
|
||||
add_subdirectory(libraries/hoedown) # markdown parser
|
||||
add_subdirectory(libraries/launcher) # java based launcher part for Minecraft
|
||||
add_subdirectory(libraries/javacheck) # java compatibility checker
|
||||
add_subdirectory(libraries/xz-embedded) # xz compression
|
||||
if (FORCE_BUNDLED_QUAZIP)
|
||||
message(STATUS "Using bundled QuaZip")
|
||||
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
|
||||
@ -268,16 +315,31 @@ else()
|
||||
message(STATUS "Using system QuaZip")
|
||||
endif()
|
||||
add_subdirectory(libraries/rainbow) # Qt extension for colors
|
||||
add_subdirectory(libraries/iconfix) # fork of Qt's QIcon loader
|
||||
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
|
||||
add_subdirectory(libraries/classparser) # class parser library
|
||||
add_subdirectory(libraries/optional-bare)
|
||||
add_subdirectory(libraries/tomlc99) # toml parser
|
||||
if(NOT tomlplusplus_FOUND)
|
||||
message(STATUS "Using bundled tomlplusplus")
|
||||
add_subdirectory(libraries/tomlplusplus) # toml parser
|
||||
else()
|
||||
message(STATUS "Using system tomlplusplus")
|
||||
endif()
|
||||
add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much
|
||||
add_subdirectory(libraries/gamemode)
|
||||
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
||||
if (NOT ghc_filesystem_FOUND)
|
||||
message(STATUS "Using bundled ghc_filesystem")
|
||||
set(GHC_FILESYSTEM_WITH_INSTALL OFF) # Workaround ghc::filesystem bug
|
||||
add_subdirectory(libraries/filesystem) # Implementation of std::filesystem for old C++, for usage in old macOS
|
||||
add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
|
||||
else()
|
||||
message(STATUS "Using system ghc_filesystem")
|
||||
endif()
|
||||
|
||||
############################### Built Artifacts ###############################
|
||||
|
||||
add_subdirectory(buildconfig)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
# NOTE: this must always be last to appease the CMake deity of quirky install command evaluation order.
|
||||
add_subdirectory(launcher)
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
This is a modified version of the Contributor Covenant.
|
||||
See commit history to see our changes.
|
||||
|
||||
@ -62,7 +63,7 @@ representative at an online or offline event.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement via email at
|
||||
[polymc-enforcement@scrumplex.net](mailto:polymc-enforcement@scrumplex.net) (Email
|
||||
[coc@scrumplex.net](mailto:coc@scrumplex.net) (Email
|
||||
address subject to change).
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
@ -133,4 +134,3 @@ For answers to common questions about this code of conduct, see the FAQ at
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
||||
|
63
CONTRIBUTING.md
Normal file
63
CONTRIBUTING.md
Normal file
@ -0,0 +1,63 @@
|
||||
# Contributions Guidelines
|
||||
|
||||
## Code formatting
|
||||
|
||||
Try to follow the existing formatting.
|
||||
If there is no existing formatting, you may use `clang-format` with our included `.clang-format` configuration.
|
||||
|
||||
In general, in order of importance:
|
||||
|
||||
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
|
||||
- Prefer readability over dogma.
|
||||
- Keep to the existing formatting.
|
||||
- Indent with 4 space unless it's in a submodule.
|
||||
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
|
||||
|
||||
## Signing your work
|
||||
|
||||
In an effort to ensure that the code you contribute is actually compatible with the licenses in this codebase, we require you to sign-off all your contributions.
|
||||
|
||||
This can be done by appending `-s` to your `git commit` call, or by manually appending the following text to your commit message:
|
||||
|
||||
```
|
||||
<commit message>
|
||||
|
||||
Signed-off-by: Author name <Author email>
|
||||
```
|
||||
|
||||
By signing off your work, you agree to the terms below:
|
||||
|
||||
```
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
||||
These terms will be enforced once you create a pull request, and you will be informed automatically if any of your commits aren't signed-off by you.
|
||||
|
||||
As a bonus, you can also [cryptographically sign your commits][gh-signing-commits] and enable [vigilant mode][gh-vigilant-mode] on GitHub.
|
||||
|
||||
[gh-signing-commits]: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits
|
||||
[gh-vigilant-mode]: https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits
|
374
COPYING.md
374
COPYING.md
@ -1,64 +1,121 @@
|
||||
# PolyMC
|
||||
## Prism Launcher
|
||||
|
||||
Copyright (C) 2012-2021 MultiMC Contributors
|
||||
Copyright (C) 2021-2022 PolyMC Contributors
|
||||
Prism Launcher - Minecraft Launcher
|
||||
Copyright (C) 2022 Prism Launcher Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3.
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Launcher (https://github.com/MultiMC/Launcher)
|
||||
Copyright 2012-2021 MultiMC Contributors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Copyright 2013-2021 MultiMC Contributors
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
# MinGW runtime (Windows)
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Copyright (c) 2012 MinGW.org project
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
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:
|
||||
## PolyMC
|
||||
|
||||
The above copyright notice, this permission notice and the below disclaimer
|
||||
shall be included in all copies or substantial portions of the Software.
|
||||
PolyMC - Minecraft Launcher
|
||||
Copyright (C) 2021-2022 PolyMC Contributors
|
||||
|
||||
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.
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3.
|
||||
|
||||
# Qt 5
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
Contact: http://www.qt-project.org/legal
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Licensed under LGPL v2.1
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice:
|
||||
|
||||
# libnbt++
|
||||
Copyright 2013-2021 MultiMC Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
## MinGW-w64 runtime (Windows)
|
||||
|
||||
Copyright (c) 2009, 2010, 2011, 2012, 2013 by the mingw-w64 project
|
||||
|
||||
This license has been certified as open source. It has also been designated
|
||||
as GPL compatible by the Free Software Foundation (FSF).
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions in source code must retain the accompanying copyright
|
||||
notice, this list of conditions, and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the accompanying
|
||||
copyright notice, this list of conditions, and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
3. Names of the copyright holders must not be used to endorse or promote
|
||||
products derived from this software without prior written permission
|
||||
from the copyright holders.
|
||||
4. The right to distribute this software or to use it for any purpose does
|
||||
not give you the right to use Servicemarks (sm) or Trademarks (tm) of
|
||||
the copyright holders. Use of them is covered by separate agreement
|
||||
with the copyright holders.
|
||||
5. If any files are modified, you must cause the modified files to carry
|
||||
prominent notices stating that you changed the files and the date of
|
||||
any change.
|
||||
|
||||
Disclaimer
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt.
|
||||
|
||||
## Qt 5/6
|
||||
|
||||
Copyright (C) 2022 The Qt Company Ltd and other contributors.
|
||||
Contact: https://www.qt.io/licensing
|
||||
|
||||
Licensed under LGPL v3
|
||||
|
||||
## libnbt++
|
||||
|
||||
libnbt++ - A library for the Minecraft Named Binary Tag format.
|
||||
Copyright (C) 2013, 2015 ljfa-ag
|
||||
@ -76,7 +133,7 @@
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with libnbt++. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# rainbow (KGuiAddons)
|
||||
## rainbow (KGuiAddons)
|
||||
|
||||
Copyright (C) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
|
||||
Copyright (C) 2007 Olaf Schmidt <ojschmidt@kde.org>
|
||||
@ -99,7 +156,7 @@
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
|
||||
# Hoedown
|
||||
## Hoedown
|
||||
|
||||
Copyright (c) 2008, Natacha Porté
|
||||
Copyright (c) 2011, Vicent Martí
|
||||
@ -117,7 +174,7 @@
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# Batch icon set
|
||||
## Batch icon set
|
||||
|
||||
You are free to use Batch (the "icon set") or any part thereof (the "icons")
|
||||
in any personal, open-source or commercial work without obligation of payment
|
||||
@ -133,7 +190,7 @@
|
||||
PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THE USE OF THE ICONS,
|
||||
EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
# Material Design Icons
|
||||
## Material Design Icons
|
||||
|
||||
Copyright (c) 2014, Austin Andrews (http://materialdesignicons.com/),
|
||||
with Reserved Font Name Material Design Icons.
|
||||
@ -144,76 +201,82 @@
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
# Quazip
|
||||
## Quazip
|
||||
|
||||
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||
Copyright (C) 2005-2021 Sergey A. Tachenov
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version.
|
||||
The QuaZip library is licensed under the GNU Lesser General Public
|
||||
License V2.1 plus a static linking exception.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
The original ZIP/UNZIP package (MiniZip) is copyrighted by Gilles
|
||||
Vollant and contributors, see quazip/(un)zip.h files for details.
|
||||
Basically it's the zlib license.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
STATIC LINKING EXCEPTION
|
||||
|
||||
The copyright holders give you permission to link this library with
|
||||
independent modules to produce an executable, regardless of the license
|
||||
terms of these independent modules, and to copy and distribute the
|
||||
resulting executable under terms of your choice, provided that you also
|
||||
meet, for each linked independent module, the terms and conditions of
|
||||
the license of that module. An independent module is a module which is
|
||||
not derived from or based on this library. If you modify this library,
|
||||
you must extend this exception to your version of the library.
|
||||
|
||||
See COPYING file for the full LGPL text.
|
||||
|
||||
Original ZIP package is copyrighted by Gilles Vollant, see
|
||||
quazip/(un)zip.h files for details, basically it's zlib license.
|
||||
## launcher (`libraries/launcher`)
|
||||
|
||||
# xz-minidec
|
||||
PolyMC - Minecraft Launcher
|
||||
Copyright (C) 2021-2022 PolyMC Contributors
|
||||
|
||||
XZ decompressor
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3.
|
||||
|
||||
Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
Igor Pavlov <http://7-zip.org/>
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
This file has been put into the public domain.
|
||||
You can do whatever you want with this file.
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
# ColumnResizer
|
||||
As a special exception, the copyright holders of this library give
|
||||
you permission to link this library with independent modules to
|
||||
produce an executable, regardless of the license terms of these
|
||||
independent modules, and to copy and distribute the resulting
|
||||
executable under terms of your choice, provided that you also meet,
|
||||
for each linked independent module, the terms and conditions of the
|
||||
license of that module. An independent module is a module which is
|
||||
not derived from or based on this library. If you modify this
|
||||
library, you may extend this exception to your version of the
|
||||
library, but you are not obliged to do so. If you do not wish to do
|
||||
so, delete this exception statement from your version.
|
||||
|
||||
Copyright (c) 2011-2016 Aurélien Gâteau and contributors.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
All rights reserved.
|
||||
This file incorporates work covered by the following copyright and
|
||||
permission notice:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted (subject to the limitations in the
|
||||
disclaimer below) provided that the following conditions are met:
|
||||
Copyright 2013-2021 MultiMC Contributors
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the
|
||||
distribution.
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
* The name of the contributors may not be used to endorse or
|
||||
promote products derived from this software without specific prior
|
||||
written permission.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
|
||||
GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
|
||||
HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# lionshead
|
||||
## lionshead
|
||||
|
||||
Code has been taken from https://github.com/natefoo/lionshead and loosely
|
||||
translated to C++ laced with Qt.
|
||||
@ -240,60 +303,26 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
# optional-bare
|
||||
|
||||
Code from https://github.com/martinmoene/optional-bare/
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# tomlc99
|
||||
## tomlplusplus
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 CK Tan
|
||||
https://github.com/cktan/tomlc99
|
||||
Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
|
||||
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:
|
||||
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 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.
|
||||
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.
|
||||
|
||||
# O2 (Katabasis fork)
|
||||
## O2 (Katabasis fork)
|
||||
|
||||
Copyright (c) 2012, Akos Polster
|
||||
All rights reserved.
|
||||
@ -318,3 +347,54 @@
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
## Gamemode
|
||||
|
||||
Copyright (c) 2017-2022, Feral Interactive
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Feral Interactive nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
## gulrak/filesystem
|
||||
|
||||
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
|
||||
|
||||
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.
|
||||
|
85
README.md
85
README.md
@ -1,88 +1,29 @@
|
||||
<p align="center">
|
||||
<img src="./program_info/polymc-header-black.svg#gh-light-mode-only" alt="PolyMC logo"/>
|
||||
<img src="./program_info/polymc-header.svg#gh-dark-mode-only" alt="PolyMC logo"/>
|
||||
<img src="./program_info/org.prismlauncher.PrismLauncher.logo.svg#gh-light-mode-only" alt="Prism Launcher logo" width="50%"/>
|
||||
<img src="./program_info/org.prismlauncher.PrismLauncher.logo-darkmode.svg#gh-dark-mode-only" alt="Prism Launcher logo" width="50%"/>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
PolyMC is a custom launcher for Minecraft that focuses on predictability, long term stability and simplicity.
|
||||
Prism Launcher is a custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.
|
||||
|
||||
This is a **fork** of the MultiMC Launcher and not endorsed by MultiMC. The PolyMC community felt that the maintainer was not acting in the spirit of Free Software so this fork was made.
|
||||
<br>
|
||||
We are working on a website and other media, for more info we have a [Discord server](https://discord.gg/prismlauncher).
|
||||
|
||||
# Installation
|
||||
## Installation
|
||||
|
||||
- All downloads and instructions for PolyMC can be found [here](https://polymc.org/download/)
|
||||
- Last build status: https://github.com/PolyMC/PolyMC/actions
|
||||
- All downloads and instructions for Prism Launcher will soon be available.
|
||||
- Last build status can be found [here](https://github.com/PrismLauncher/PrismLauncher/actions).
|
||||
|
||||
### Development Builds
|
||||
|
||||
## Development Builds
|
||||
There are development builds available [here](https://github.com/PrismLauncher/PrismLauncher/actions). These have debug information in the binaries, so their file sizes are relatively larger.
|
||||
|
||||
There are per-commit development builds available [here](https://github.com/PolyMC/PolyMC/actions). These have debug information in the binaries, so their file sizes are relatively larger.
|
||||
Portable builds are provided for AppImage on Linux, Windows, and macOS.
|
||||
|
||||
For Debian and Arch, you can use these packages for the latest development versions:
|
||||
[](https://aur.archlinux.org/packages/polymc-git/)
|
||||
[](https://mpr.makedeb.org/packages/polymc-git)
|
||||
For flatpak, you can use [flathub-beta](https://discourse.flathub.org/t/how-to-use-flathub-beta/2111)
|
||||
## Help & Support
|
||||
|
||||
# Help & Support
|
||||
|
||||
Feel free to create an issue if you need help. However, you might find it easier to ask in the Discord server.
|
||||
[](https://discord.gg/hX4g537UNE)
|
||||
|
||||
[](https://discord.gg/xq7fxrgtMP)
|
||||
|
||||
For people who don't want to use Discord, we have a Matrix Space which is bridged to the Discord server:
|
||||
## License
|
||||
|
||||
[](https://matrix.to/#/#polymc:matrix.org)
|
||||
|
||||
If there are any issues with the space or you are using a client that does not support the feature here are the individual rooms:
|
||||
|
||||
[](https://matrix.to/#/#polymc-development:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-discussion:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-github:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-maintainers:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-news:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-offtopic:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-support:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-voice:matrix.org)
|
||||
|
||||
we also have a subreddit you can post your issues and suggestions on:
|
||||
|
||||
[r/PolyMCLauncher](https://www.reddit.com/r/PolyMCLauncher/)
|
||||
|
||||
# Development
|
||||
|
||||
If you want to contribute to PolyMC you might find it useful to join our Discord Server or Matrix Space.
|
||||
|
||||
## Building
|
||||
|
||||
If you want to build PolyMC yourself, check [Build Instructions](https://polymc.org/wiki/development/build-instructions/) for build instructions.
|
||||
|
||||
## Code formatting
|
||||
|
||||
Just follow the existing formatting.
|
||||
|
||||
In general, in order of importance:
|
||||
|
||||
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
|
||||
- Prefer readability over dogma.
|
||||
- Keep to the existing formatting.
|
||||
- Indent with 4 space unless it's in a submodule.
|
||||
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
|
||||
|
||||
## Translations
|
||||
|
||||
The translation effort for PolyMC is hosted on [Weblate](https://hosted.weblate.org/projects/polymc/polymc/) and information about translating PolyMC is available at https://github.com/PolyMC/Translations
|
||||
|
||||
## Download information
|
||||
To modify download information or change packaging information send a pull request or issue to the website [Here](https://github.com/PolyMC/polymc.github.io/blob/master/src/download.md)
|
||||
|
||||
## Forking/Redistributing/Custom builds policy
|
||||
|
||||
Do whatever you want, we don't care. Just follow the license. If you have any questions about this feel free to ask in an issue.
|
||||
|
||||
All launcher code is available under the GPL-3 license.
|
||||
|
||||
[Source for the website](https://github.com/PolyMC/polymc.github.io) is hosted under the AGPL-3 License.
|
||||
|
||||
The logo and related assets are under the CC BY-SA 4.0 license.
|
||||
All launcher code is available under the GPL-3.0-only license.
|
||||
|
@ -42,12 +42,14 @@ Config::Config()
|
||||
{
|
||||
// Name and copyright
|
||||
LAUNCHER_NAME = "@Launcher_Name@";
|
||||
LAUNCHER_APP_BINARY_NAME = "@Launcher_APP_BINARY_NAME@";
|
||||
LAUNCHER_DISPLAYNAME = "@Launcher_DisplayName@";
|
||||
LAUNCHER_COPYRIGHT = "@Launcher_Copyright@";
|
||||
LAUNCHER_DOMAIN = "@Launcher_Domain@";
|
||||
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
|
||||
LAUNCHER_GIT = "@Launcher_Git@";
|
||||
LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
|
||||
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
|
||||
|
||||
USER_AGENT = "@Launcher_UserAgent@";
|
||||
USER_AGENT_UNCACHED = USER_AGENT + " (Uncached)";
|
||||
@ -55,23 +57,36 @@ Config::Config()
|
||||
// Version information
|
||||
VERSION_MAJOR = @Launcher_VERSION_MAJOR@;
|
||||
VERSION_MINOR = @Launcher_VERSION_MINOR@;
|
||||
VERSION_HOTFIX = @Launcher_VERSION_HOTFIX@;
|
||||
VERSION_BUILD = @Launcher_VERSION_BUILD@;
|
||||
|
||||
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
||||
BUILD_DATE = "@Launcher_BUILD_TIMESTAMP@";
|
||||
UPDATER_BASE = "@Launcher_UPDATER_BASE@";
|
||||
|
||||
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
||||
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
||||
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND"))
|
||||
MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@";
|
||||
MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@";
|
||||
|
||||
if (BUILD_PLATFORM == "macOS" && !MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty())
|
||||
{
|
||||
VERSION_CHANNEL = QStringLiteral("stable");
|
||||
UPDATER_ENABLED = true;
|
||||
}
|
||||
else if(GIT_REFSPEC.startsWith("refs/heads/"))
|
||||
|
||||
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
||||
GIT_TAG = "@Launcher_GIT_TAG@";
|
||||
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
||||
|
||||
// Assume that builds outside of Git repos are "stable"
|
||||
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND")
|
||||
|| GIT_TAG == QStringLiteral("GITDIR-NOTFOUND"))
|
||||
{
|
||||
GIT_REFSPEC = "refs/heads/stable";
|
||||
GIT_TAG = versionString();
|
||||
}
|
||||
|
||||
if (GIT_REFSPEC.startsWith("refs/heads/"))
|
||||
{
|
||||
VERSION_CHANNEL = GIT_REFSPEC;
|
||||
VERSION_CHANNEL.remove("refs/heads/");
|
||||
if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty() && VERSION_BUILD >= 0) {
|
||||
if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty()) {
|
||||
UPDATER_ENABLED = true;
|
||||
}
|
||||
}
|
||||
@ -81,15 +96,15 @@ Config::Config()
|
||||
}
|
||||
else
|
||||
{
|
||||
VERSION_CHANNEL = QObject::tr("unknown");
|
||||
VERSION_CHANNEL = "unknown";
|
||||
}
|
||||
|
||||
VERSION_STR = "@Launcher_VERSION_STRING@";
|
||||
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
|
||||
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
|
||||
HELP_URL = "@Launcher_HELP_URL@";
|
||||
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
|
||||
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
|
||||
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
||||
META_URL = "@Launcher_META_URL@";
|
||||
|
||||
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
|
||||
@ -99,20 +114,19 @@ Config::Config()
|
||||
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
|
||||
}
|
||||
|
||||
QString Config::versionString() const
|
||||
{
|
||||
return QString("%1.%2").arg(VERSION_MAJOR).arg(VERSION_MINOR);
|
||||
}
|
||||
|
||||
QString Config::printableVersionString() const
|
||||
{
|
||||
QString vstr = QString("%1.%2.%3").arg(QString::number(VERSION_MAJOR), QString::number(VERSION_MINOR), QString::number(VERSION_HOTFIX));
|
||||
QString vstr = versionString();
|
||||
|
||||
// If the build is not a main release, append the channel
|
||||
if(VERSION_CHANNEL != "stable")
|
||||
if(VERSION_CHANNEL != "stable" && GIT_TAG != vstr)
|
||||
{
|
||||
vstr += "-" + VERSION_CHANNEL;
|
||||
}
|
||||
|
||||
// if a build number is set, also add it to the end
|
||||
if(VERSION_BUILD >= 0)
|
||||
{
|
||||
vstr += "-" + QString::number(VERSION_BUILD);
|
||||
}
|
||||
return vstr;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -39,26 +40,23 @@
|
||||
/**
|
||||
* \brief The Config class holds all the build-time information passed from the build system.
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
class Config {
|
||||
public:
|
||||
Config();
|
||||
QString LAUNCHER_NAME;
|
||||
QString LAUNCHER_APP_BINARY_NAME;
|
||||
QString LAUNCHER_DISPLAYNAME;
|
||||
QString LAUNCHER_COPYRIGHT;
|
||||
QString LAUNCHER_DOMAIN;
|
||||
QString LAUNCHER_CONFIGFILE;
|
||||
QString LAUNCHER_GIT;
|
||||
QString LAUNCHER_DESKTOPFILENAME;
|
||||
QString LAUNCHER_SVGFILENAME;
|
||||
|
||||
/// The major version number.
|
||||
int VERSION_MAJOR;
|
||||
/// The minor version number.
|
||||
int VERSION_MINOR;
|
||||
/// The hotfix number.
|
||||
int VERSION_HOTFIX;
|
||||
/// The build number.
|
||||
int VERSION_BUILD;
|
||||
|
||||
/**
|
||||
* The version channel
|
||||
@ -71,9 +69,17 @@ public:
|
||||
/// A short string identifying this build's platform. For example, "lin64" or "win32".
|
||||
QString BUILD_PLATFORM;
|
||||
|
||||
/// A string containing the build timestamp
|
||||
QString BUILD_DATE;
|
||||
|
||||
/// URL for the updater's channel
|
||||
QString UPDATER_BASE;
|
||||
|
||||
/// The public key used to sign releases for the Sparkle updater appcast
|
||||
QString MAC_SPARKLE_PUB_KEY;
|
||||
|
||||
/// URL for the Sparkle updater's appcast
|
||||
QString MAC_SPARKLE_APPCAST_URL;
|
||||
|
||||
/// User-Agent to use.
|
||||
QString USER_AGENT;
|
||||
@ -84,12 +90,12 @@ public:
|
||||
/// The git commit hash of this build
|
||||
QString GIT_COMMIT;
|
||||
|
||||
/// The git tag of this build
|
||||
QString GIT_TAG;
|
||||
|
||||
/// The git refspec of this build
|
||||
QString GIT_REFSPEC;
|
||||
|
||||
/// This is printed on start to standard output
|
||||
QString VERSION_STR;
|
||||
|
||||
/**
|
||||
* This is used to fetch the news RSS feed.
|
||||
* It defaults in CMakeLists.txt to "https://multimc.org/rss.xml"
|
||||
@ -116,6 +122,11 @@ public:
|
||||
*/
|
||||
QString MSA_CLIENT_ID;
|
||||
|
||||
/**
|
||||
* Client API key for CurseForge
|
||||
*/
|
||||
QString FLAME_API_KEY;
|
||||
|
||||
/**
|
||||
* Metadata repository URL prefix
|
||||
*/
|
||||
@ -131,14 +142,15 @@ public:
|
||||
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
||||
QString AUTH_BASE = "https://authserver.mojang.com/";
|
||||
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
||||
QString FMLLIBS_BASE_URL = "https://files.polymc.org/fmllibs/";
|
||||
QString TRANSLATIONS_BASE_URL = "https://i18n.polymc.org/";
|
||||
QString FMLLIBS_BASE_URL = "https://files.prismlauncher.org/fmllibs/"; // FIXME: move into CMakeLists
|
||||
QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/"; // FIXME: move into CMakeLists
|
||||
|
||||
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
||||
|
||||
QString LEGACY_FTB_CDN_BASE_URL = "https://dist.creeper.host/FTB2/";
|
||||
|
||||
QString ATL_DOWNLOAD_SERVER_URL = "https://download.nodecdn.net/containers/atl/";
|
||||
QString ATL_API_BASE_URL = "https://api.atlauncher.com/v1/";
|
||||
|
||||
QString TECHNIC_API_BASE_URL = "https://api.technicpack.net/";
|
||||
/**
|
||||
@ -146,6 +158,10 @@ public:
|
||||
*/
|
||||
QString TECHNIC_API_BUILD = "multimc";
|
||||
|
||||
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
||||
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
|
||||
|
||||
QString versionString() const;
|
||||
/**
|
||||
* \brief Converts the Version to a string.
|
||||
* \return The version number in string format (major.minor.revision.build).
|
||||
@ -154,4 +170,3 @@ public:
|
||||
};
|
||||
|
||||
extern const Config BuildConfig;
|
||||
|
||||
|
@ -7,5 +7,5 @@ add_library(BuildConfig STATIC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/BuildConfig.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(BuildConfig Qt5::Core)
|
||||
target_link_libraries(BuildConfig Qt${QT_VERSION_MAJOR}::Core)
|
||||
target_include_directories(BuildConfig PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
@ -1,786 +0,0 @@
|
||||
# - Functions to help assemble a standalone bundle application.
|
||||
# A collection of CMake utility functions useful for dealing with .app
|
||||
# bundles on the Mac and bundle-like directories on any OS.
|
||||
#
|
||||
# The following functions are provided by this module:
|
||||
# fixup_bundle
|
||||
# copy_and_fixup_bundle
|
||||
# verify_app
|
||||
# get_bundle_main_executable
|
||||
# get_dotapp_dir
|
||||
# get_bundle_and_executable
|
||||
# get_bundle_all_executables
|
||||
# get_item_key
|
||||
# clear_bundle_keys
|
||||
# set_bundle_key_values
|
||||
# get_bundle_keys
|
||||
# copy_resolved_item_into_bundle
|
||||
# copy_resolved_framework_into_bundle
|
||||
# fixup_bundle_item
|
||||
# verify_bundle_prerequisites
|
||||
# verify_bundle_symlinks
|
||||
# Requires CMake 2.6 or greater because it uses function, break and
|
||||
# PARENT_SCOPE. Also depends on GetPrerequisites.cmake.
|
||||
#
|
||||
# FIXUP_BUNDLE(<app> <libs> <dirs>)
|
||||
# Fix up a bundle in-place and make it standalone, such that it can be
|
||||
# drag-n-drop copied to another machine and run on that machine as long as all
|
||||
# of the system libraries are compatible.
|
||||
#
|
||||
# If you pass plugins to fixup_bundle as the libs parameter, you should install
|
||||
# them or copy them into the bundle before calling fixup_bundle. The "libs"
|
||||
# parameter is a list of libraries that must be fixed up, but that cannot be
|
||||
# determined by otool output analysis. (i.e., plugins)
|
||||
#
|
||||
# Gather all the keys for all the executables and libraries in a bundle, and
|
||||
# then, for each key, copy each prerequisite into the bundle. Then fix each one
|
||||
# up according to its own list of prerequisites.
|
||||
#
|
||||
# Then clear all the keys and call verify_app on the final bundle to ensure
|
||||
# that it is truly standalone.
|
||||
#
|
||||
# COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>)
|
||||
# Makes a copy of the bundle <src> at location <dst> and then fixes up the
|
||||
# new copied bundle in-place at <dst>...
|
||||
#
|
||||
# VERIFY_APP(<app>)
|
||||
# Verifies that an application <app> appears valid based on running analysis
|
||||
# tools on it. Calls "message(FATAL_ERROR" if the application is not verified.
|
||||
#
|
||||
# GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>)
|
||||
# The result will be the full path name of the bundle's main executable file
|
||||
# or an "error:" prefixed string if it could not be determined.
|
||||
#
|
||||
# GET_DOTAPP_DIR(<exe> <dotapp_dir_var>)
|
||||
# Returns the nearest parent dir whose name ends with ".app" given the full
|
||||
# path to an executable. If there is no such parent dir, then simply return
|
||||
# the dir containing the executable.
|
||||
#
|
||||
# The returned directory may or may not exist.
|
||||
#
|
||||
# GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>)
|
||||
# Takes either a ".app" directory name or the name of an executable
|
||||
# nested inside a ".app" directory and returns the path to the ".app"
|
||||
# directory in <bundle_var> and the path to its main executable in
|
||||
# <executable_var>
|
||||
#
|
||||
# GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>)
|
||||
# Scans the given bundle recursively for all executable files and accumulates
|
||||
# them into a variable.
|
||||
#
|
||||
# GET_ITEM_KEY(<item> <key_var>)
|
||||
# Given a file (item) name, generate a key that should be unique considering
|
||||
# the set of libraries that need copying or fixing up to make a bundle
|
||||
# standalone. This is essentially the file name including extension with "."
|
||||
# replaced by "_"
|
||||
#
|
||||
# This key is used as a prefix for CMake variables so that we can associate a
|
||||
# set of variables with a given item based on its key.
|
||||
#
|
||||
# CLEAR_BUNDLE_KEYS(<keys_var>)
|
||||
# Loop over the list of keys, clearing all the variables associated with each
|
||||
# key. After the loop, clear the list of keys itself.
|
||||
#
|
||||
# Caller of get_bundle_keys should call clear_bundle_keys when done with list
|
||||
# of keys.
|
||||
#
|
||||
# SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs>
|
||||
# <copyflag>)
|
||||
# Add a key to the list (if necessary) for the given item. If added,
|
||||
# also set all the variables associated with that key.
|
||||
#
|
||||
# GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>)
|
||||
# Loop over all the executable and library files within the bundle (and given
|
||||
# as extra <libs>) and accumulate a list of keys representing them. Set
|
||||
# values associated with each key such that we can loop over all of them and
|
||||
# copy prerequisite libs into the bundle and then do appropriate
|
||||
# install_name_tool fixups.
|
||||
#
|
||||
# COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
|
||||
# Copy a resolved item into the bundle if necessary. Copy is not necessary if
|
||||
# the resolved_item is "the same as" the resolved_embedded_item.
|
||||
#
|
||||
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
|
||||
# Copy a resolved framework into the bundle if necessary. Copy is not necessary
|
||||
# if the resolved_item is "the same as" the resolved_embedded_item.
|
||||
#
|
||||
# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want full
|
||||
# frameworks embedded in your bundles, set BU_COPY_FULL_FRAMEWORK_CONTENTS to
|
||||
# ON before calling fixup_bundle. By default,
|
||||
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework dylib itself plus
|
||||
# the framework Resources directory.
|
||||
#
|
||||
# FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>)
|
||||
# Get the direct/non-system prerequisites of the resolved embedded item. For
|
||||
# each prerequisite, change the way it is referenced to the value of the
|
||||
# _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely changing to
|
||||
# an "@executable_path" style reference.)
|
||||
#
|
||||
# This function requires that the resolved_embedded_item be "inside" the bundle
|
||||
# already. In other words, if you pass plugins to fixup_bundle as the libs
|
||||
# parameter, you should install them or copy them into the bundle before
|
||||
# calling fixup_bundle. The "libs" parameter is a list of libraries that must
|
||||
# be fixed up, but that cannot be determined by otool output analysis. (i.e.,
|
||||
# plugins)
|
||||
#
|
||||
# Also, change the id of the item being fixed up to its own _EMBEDDED_ITEM
|
||||
# value.
|
||||
#
|
||||
# Accumulate changes in a local variable and make *one* call to
|
||||
# install_name_tool at the end of the function with all the changes at once.
|
||||
#
|
||||
# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be
|
||||
# marked writable before install_name_tool tries to change them.
|
||||
#
|
||||
# VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>)
|
||||
# Verifies that the sum of all prerequisites of all files inside the bundle
|
||||
# are contained within the bundle or are "system" libraries, presumed to exist
|
||||
# everywhere.
|
||||
#
|
||||
# VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>)
|
||||
# Verifies that any symlinks found in the bundle point to other files that are
|
||||
# already also in the bundle... Anything that points to an external file causes
|
||||
# this function to fail the verification.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2008-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# The functions defined in this file depend on the get_prerequisites function
|
||||
# (and possibly others) found in:
|
||||
#
|
||||
get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
include("${BundleUtilities_cmake_dir}/GetPrerequisites.cmake")
|
||||
|
||||
|
||||
function(get_bundle_main_executable bundle result_var)
|
||||
set(result "error: '${bundle}/Contents/Info.plist' file does not exist")
|
||||
|
||||
if(EXISTS "${bundle}/Contents/Info.plist")
|
||||
set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file")
|
||||
set(line_is_main_executable 0)
|
||||
set(bundle_executable "")
|
||||
|
||||
# Read Info.plist as a list of lines:
|
||||
#
|
||||
set(eol_char "E")
|
||||
file(READ "${bundle}/Contents/Info.plist" info_plist)
|
||||
string(REGEX REPLACE ";" "\\\\;" info_plist "${info_plist}")
|
||||
string(REGEX REPLACE "\n" "${eol_char};" info_plist "${info_plist}")
|
||||
|
||||
# Scan the lines for "<key>CFBundleExecutable</key>" - the line after that
|
||||
# is the name of the main executable.
|
||||
#
|
||||
foreach(line ${info_plist})
|
||||
if(line_is_main_executable)
|
||||
string(REGEX REPLACE "^.*<string>(.*)</string>.*$" "\\1" bundle_executable "${line}")
|
||||
break()
|
||||
endif()
|
||||
|
||||
if(line MATCHES "^.*<key>CFBundleExecutable</key>.*$")
|
||||
set(line_is_main_executable 1)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT "${bundle_executable}" STREQUAL "")
|
||||
if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}")
|
||||
set(result "${bundle}/Contents/MacOS/${bundle_executable}")
|
||||
else()
|
||||
|
||||
# Ultimate goal:
|
||||
# If not in "Contents/MacOS" then scan the bundle for matching files. If
|
||||
# there is only one executable file that matches, then use it, otherwise
|
||||
# it's an error...
|
||||
#
|
||||
#file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}")
|
||||
|
||||
# But for now, pragmatically, it's an error. Expect the main executable
|
||||
# for the bundle to be in Contents/MacOS, it's an error if it's not:
|
||||
#
|
||||
set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
#
|
||||
# More inclusive technique... (This one would work on Windows and Linux
|
||||
# too, if a developer followed the typical Mac bundle naming convention...)
|
||||
#
|
||||
# If there is no Info.plist file, try to find an executable with the same
|
||||
# base name as the .app directory:
|
||||
#
|
||||
endif()
|
||||
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_dotapp_dir exe dotapp_dir_var)
|
||||
set(s "${exe}")
|
||||
|
||||
if(s MATCHES "^.*/.*\\.app/.*$")
|
||||
# If there is a ".app" parent directory,
|
||||
# ascend until we hit it:
|
||||
# (typical of a Mac bundle executable)
|
||||
#
|
||||
set(done 0)
|
||||
while(NOT ${done})
|
||||
get_filename_component(snamewe "${s}" NAME_WE)
|
||||
get_filename_component(sname "${s}" NAME)
|
||||
get_filename_component(sdir "${s}" PATH)
|
||||
set(s "${sdir}")
|
||||
if(sname MATCHES "\\.app$")
|
||||
set(done 1)
|
||||
set(dotapp_dir "${sdir}/${sname}")
|
||||
endif()
|
||||
endwhile()
|
||||
else()
|
||||
# Otherwise use a directory containing the exe
|
||||
# (typical of a non-bundle executable on Mac, Windows or Linux)
|
||||
#
|
||||
is_file_executable("${s}" is_executable)
|
||||
if(is_executable)
|
||||
get_filename_component(sdir "${s}" PATH)
|
||||
set(dotapp_dir "${sdir}")
|
||||
else()
|
||||
set(dotapp_dir "${s}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_bundle_and_executable app bundle_var executable_var valid_var)
|
||||
set(valid 0)
|
||||
|
||||
if(EXISTS "${app}")
|
||||
# Is it a directory ending in .app?
|
||||
if(IS_DIRECTORY "${app}")
|
||||
if(app MATCHES "\\.app$")
|
||||
get_bundle_main_executable("${app}" executable)
|
||||
if(EXISTS "${app}" AND EXISTS "${executable}")
|
||||
set(${bundle_var} "${app}" PARENT_SCOPE)
|
||||
set(${executable_var} "${executable}" PARENT_SCOPE)
|
||||
set(valid 1)
|
||||
#message(STATUS "info: handled .app directory case...")
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - .app directory case...")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - directory but not .app case...")
|
||||
endif()
|
||||
else()
|
||||
# Is it an executable file?
|
||||
is_file_executable("${app}" is_executable)
|
||||
if(is_executable)
|
||||
get_dotapp_dir("${app}" dotapp_dir)
|
||||
if(EXISTS "${dotapp_dir}")
|
||||
set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE)
|
||||
set(${executable_var} "${app}" PARENT_SCOPE)
|
||||
set(valid 1)
|
||||
#message(STATUS "info: handled executable file in .app dir case...")
|
||||
else()
|
||||
get_filename_component(app_dir "${app}" PATH)
|
||||
set(${bundle_var} "${app_dir}" PARENT_SCOPE)
|
||||
set(${executable_var} "${app}" PARENT_SCOPE)
|
||||
set(valid 1)
|
||||
#message(STATUS "info: handled executable file in any dir case...")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - not .app dir, not executable file...")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - directory/file ${app} does not exist...")
|
||||
endif()
|
||||
|
||||
if(NOT valid)
|
||||
set(${bundle_var} "error: not a bundle" PARENT_SCOPE)
|
||||
set(${executable_var} "error: not a bundle" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
set(${valid_var} ${valid} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_bundle_all_executables bundle exes_var)
|
||||
set(exes "")
|
||||
|
||||
file(GLOB_RECURSE file_list "${bundle}/*")
|
||||
foreach(f ${file_list})
|
||||
is_file_executable("${f}" is_executable)
|
||||
if(is_executable)
|
||||
set(exes ${exes} "${f}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${exes_var} "${exes}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_item_key item key_var)
|
||||
get_filename_component(item_name "${item}" NAME)
|
||||
if(WIN32)
|
||||
string(TOLOWER "${item_name}" item_name)
|
||||
endif()
|
||||
string(REGEX REPLACE "\\." "_" ${key_var} "${item_name}")
|
||||
set(${key_var} ${${key_var}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(clear_bundle_keys keys_var)
|
||||
foreach(key ${${keys_var}})
|
||||
set(${key}_ITEM PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_ITEM PARENT_SCOPE)
|
||||
set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE)
|
||||
set(${key}_EMBEDDED_ITEM PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE)
|
||||
set(${key}_COPYFLAG PARENT_SCOPE)
|
||||
endforeach()
|
||||
set(${keys_var} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(set_bundle_key_values keys_var context item exepath dirs copyflag)
|
||||
get_filename_component(item_name "${item}" NAME)
|
||||
|
||||
get_item_key("${item}" key)
|
||||
|
||||
list(LENGTH ${keys_var} length_before)
|
||||
gp_append_unique(${keys_var} "${key}")
|
||||
list(LENGTH ${keys_var} length_after)
|
||||
|
||||
if(NOT length_before EQUAL length_after)
|
||||
gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item)
|
||||
|
||||
gp_item_default_embedded_path("${item}" default_embedded_path)
|
||||
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
# For frameworks, construct the name under the embedded path from the
|
||||
# opening "${item_name}.framework/" to the closing "/${item_name}":
|
||||
#
|
||||
string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}")
|
||||
else()
|
||||
# For other items, just use the same name as the original, but in the
|
||||
# embedded path:
|
||||
#
|
||||
set(embedded_item "${default_embedded_path}/${item_name}")
|
||||
endif()
|
||||
|
||||
# Replace @executable_path and resolve ".." references:
|
||||
#
|
||||
string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}")
|
||||
get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE)
|
||||
|
||||
# *But* -- if we are not copying, then force resolved_embedded_item to be
|
||||
# the same as resolved_item. In the case of multiple executables in the
|
||||
# original bundle, using the default_embedded_path results in looking for
|
||||
# the resolved executable next to the main bundle executable. This is here
|
||||
# so that exes in the other sibling directories (like "bin") get fixed up
|
||||
# properly...
|
||||
#
|
||||
if(NOT copyflag)
|
||||
set(resolved_embedded_item "${resolved_item}")
|
||||
endif()
|
||||
|
||||
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
|
||||
set(${key}_ITEM "${item}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE)
|
||||
set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE)
|
||||
set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE)
|
||||
set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE)
|
||||
else()
|
||||
#message("warning: item key '${key}' already in the list, subsequent references assumed identical to first")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_bundle_keys app libs dirs keys_var)
|
||||
set(${keys_var} PARENT_SCOPE)
|
||||
|
||||
get_bundle_and_executable("${app}" bundle executable valid)
|
||||
if(valid)
|
||||
# Always use the exepath of the main bundle executable for @executable_path
|
||||
# replacements:
|
||||
#
|
||||
get_filename_component(exepath "${executable}" PATH)
|
||||
|
||||
# But do fixups on all executables in the bundle:
|
||||
#
|
||||
get_bundle_all_executables("${bundle}" exes)
|
||||
|
||||
# For each extra lib, accumulate a key as well and then also accumulate
|
||||
# any of its prerequisites. (Extra libs are typically dynamically loaded
|
||||
# plugins: libraries that are prerequisites for full runtime functionality
|
||||
# but that do not show up in otool -L output...)
|
||||
#
|
||||
foreach(lib ${libs})
|
||||
set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0)
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}")
|
||||
foreach(pr ${prereqs})
|
||||
set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# For each executable found in the bundle, accumulate keys as we go.
|
||||
# The list of keys should be complete when all prerequisites of all
|
||||
# binaries in the bundle have been analyzed.
|
||||
#
|
||||
foreach(exe ${exes})
|
||||
# Add the exe itself to the keys:
|
||||
#
|
||||
set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0)
|
||||
|
||||
# Add each prerequisite to the keys:
|
||||
#
|
||||
set(prereqs "")
|
||||
get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}")
|
||||
foreach(pr ${prereqs})
|
||||
set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Propagate values to caller's scope:
|
||||
#
|
||||
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
|
||||
foreach(key ${${keys_var}})
|
||||
set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE)
|
||||
set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE)
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
|
||||
if(WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item)
|
||||
if(WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
if(BU_COPY_FULL_FRAMEWORK_CONTENTS)
|
||||
# Full Framework (everything):
|
||||
get_filename_component(resolved_dir "${resolved_item}" PATH)
|
||||
get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE)
|
||||
get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH)
|
||||
get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE)
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}")
|
||||
else()
|
||||
# Framework lib itself:
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
|
||||
# Plus Resources, if they exist:
|
||||
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}")
|
||||
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}")
|
||||
if(EXISTS "${resolved_resources}")
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}")
|
||||
endif()
|
||||
endif()
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
function(fixup_bundle_item resolved_embedded_item exepath dirs)
|
||||
# This item's key is "ikey":
|
||||
#
|
||||
get_item_key("${resolved_embedded_item}" ikey)
|
||||
|
||||
# Ensure the item is "inside the .app bundle" -- it should not be fixed up if
|
||||
# it is not in the .app bundle... Otherwise, we'll modify files in the build
|
||||
# tree, or in other varied locations around the file system, with our call to
|
||||
# install_name_tool. Make sure that doesn't happen here:
|
||||
#
|
||||
get_dotapp_dir("${exepath}" exe_dotapp_dir)
|
||||
string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length)
|
||||
string(LENGTH "${resolved_embedded_item}" resolved_embedded_item_length)
|
||||
set(path_too_short 0)
|
||||
set(is_embedded 0)
|
||||
if(${resolved_embedded_item_length} LESS ${exe_dotapp_dir_length})
|
||||
set(path_too_short 1)
|
||||
endif()
|
||||
if(NOT path_too_short)
|
||||
string(SUBSTRING "${resolved_embedded_item}" 0 ${exe_dotapp_dir_length} item_substring)
|
||||
if("${exe_dotapp_dir}/" STREQUAL "${item_substring}")
|
||||
set(is_embedded 1)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT is_embedded)
|
||||
message(" exe_dotapp_dir/='${exe_dotapp_dir}/'")
|
||||
message(" item_substring='${item_substring}'")
|
||||
message(" resolved_embedded_item='${resolved_embedded_item}'")
|
||||
message("")
|
||||
message("Install or copy the item into the bundle before calling fixup_bundle.")
|
||||
message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?")
|
||||
message("")
|
||||
message(FATAL_ERROR "cannot fixup an item that is not in the bundle...")
|
||||
endif()
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}")
|
||||
|
||||
set(changes "")
|
||||
|
||||
foreach(pr ${prereqs})
|
||||
# Each referenced item's key is "rkey" in the loop:
|
||||
#
|
||||
get_item_key("${pr}" rkey)
|
||||
|
||||
if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "")
|
||||
set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}")
|
||||
else()
|
||||
message("warning: unexpected reference to '${pr}'")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(BU_CHMOD_BUNDLE_ITEMS)
|
||||
execute_process(COMMAND chmod u+w "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
# Change this item's id and all of its references in one call
|
||||
# to install_name_tool:
|
||||
#
|
||||
execute_process(COMMAND install_name_tool
|
||||
${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(fixup_bundle app libs dirs)
|
||||
message(STATUS "fixup_bundle")
|
||||
message(STATUS " app='${app}'")
|
||||
message(STATUS " libs='${libs}'")
|
||||
message(STATUS " dirs='${dirs}'")
|
||||
|
||||
get_bundle_and_executable("${app}" bundle executable valid)
|
||||
if(valid)
|
||||
get_filename_component(exepath "${executable}" PATH)
|
||||
|
||||
message(STATUS "fixup_bundle: preparing...")
|
||||
get_bundle_keys("${app}" "${libs}" "${dirs}" keys)
|
||||
|
||||
message(STATUS "fixup_bundle: copying...")
|
||||
list(LENGTH keys n)
|
||||
math(EXPR n ${n}*2)
|
||||
|
||||
set(i 0)
|
||||
foreach(key ${keys})
|
||||
math(EXPR i ${i}+1)
|
||||
if(${${key}_COPYFLAG})
|
||||
message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'")
|
||||
else()
|
||||
message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'")
|
||||
endif()
|
||||
|
||||
set(show_status 0)
|
||||
if(show_status)
|
||||
message(STATUS "key='${key}'")
|
||||
message(STATUS "item='${${key}_ITEM}'")
|
||||
message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'")
|
||||
message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'")
|
||||
message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'")
|
||||
message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'")
|
||||
message(STATUS "copyflag='${${key}_COPYFLAG}'")
|
||||
message(STATUS "")
|
||||
endif()
|
||||
|
||||
if(${${key}_COPYFLAG})
|
||||
set(item "${${key}_ITEM}")
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}"
|
||||
"${${key}_RESOLVED_EMBEDDED_ITEM}")
|
||||
else()
|
||||
copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}"
|
||||
"${${key}_RESOLVED_EMBEDDED_ITEM}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message(STATUS "fixup_bundle: fixing...")
|
||||
foreach(key ${keys})
|
||||
math(EXPR i ${i}+1)
|
||||
if(APPLE)
|
||||
message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'")
|
||||
fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}")
|
||||
else()
|
||||
message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message(STATUS "fixup_bundle: cleaning up...")
|
||||
clear_bundle_keys(keys)
|
||||
|
||||
message(STATUS "fixup_bundle: verifying...")
|
||||
verify_app("${app}")
|
||||
else()
|
||||
message(SEND_ERROR "error: fixup_bundle: not a valid bundle")
|
||||
endif()
|
||||
|
||||
message(STATUS "fixup_bundle: done")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(copy_and_fixup_bundle src dst libs dirs)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}")
|
||||
fixup_bundle("${dst}" "${libs}" "${dirs}")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(verify_bundle_prerequisites bundle result_var info_var)
|
||||
set(result 1)
|
||||
set(info "")
|
||||
set(count 0)
|
||||
|
||||
get_bundle_main_executable("${bundle}" main_bundle_exe)
|
||||
|
||||
file(GLOB_RECURSE file_list "${bundle}/*")
|
||||
foreach(f ${file_list})
|
||||
is_file_executable("${f}" is_executable)
|
||||
if(is_executable)
|
||||
get_filename_component(exepath "${f}" PATH)
|
||||
math(EXPR count "${count} + 1")
|
||||
|
||||
message(STATUS "executable file ${count}: ${f}")
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${f}" prereqs 1 1 "${exepath}" "")
|
||||
|
||||
# On the Mac,
|
||||
# "embedded" and "system" prerequisites are fine... anything else means
|
||||
# the bundle's prerequisites are not verified (i.e., the bundle is not
|
||||
# really "standalone")
|
||||
#
|
||||
# On Windows (and others? Linux/Unix/...?)
|
||||
# "local" and "system" prereqs are fine...
|
||||
#
|
||||
set(external_prereqs "")
|
||||
|
||||
foreach(p ${prereqs})
|
||||
set(p_type "")
|
||||
gp_file_type("${f}" "${p}" p_type)
|
||||
|
||||
if(APPLE)
|
||||
if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system")
|
||||
set(external_prereqs ${external_prereqs} "${p}")
|
||||
endif()
|
||||
else()
|
||||
if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system")
|
||||
set(external_prereqs ${external_prereqs} "${p}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(external_prereqs)
|
||||
# Found non-system/somehow-unacceptable prerequisites:
|
||||
set(result 0)
|
||||
set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(result)
|
||||
set(info "Verified ${count} executable files in '${bundle}'")
|
||||
endif()
|
||||
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
set(${info_var} "${info}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(verify_bundle_symlinks bundle result_var info_var)
|
||||
set(result 1)
|
||||
set(info "")
|
||||
set(count 0)
|
||||
|
||||
# TODO: implement this function for real...
|
||||
# Right now, it is just a stub that verifies unconditionally...
|
||||
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
set(${info_var} "${info}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(verify_app app)
|
||||
set(verified 0)
|
||||
set(info "")
|
||||
|
||||
get_bundle_and_executable("${app}" bundle executable valid)
|
||||
|
||||
message(STATUS "===========================================================================")
|
||||
message(STATUS "Analyzing app='${app}'")
|
||||
message(STATUS "bundle='${bundle}'")
|
||||
message(STATUS "executable='${executable}'")
|
||||
message(STATUS "valid='${valid}'")
|
||||
|
||||
# Verify that the bundle does not have any "external" prerequisites:
|
||||
#
|
||||
verify_bundle_prerequisites("${bundle}" verified info)
|
||||
message(STATUS "verified='${verified}'")
|
||||
message(STATUS "info='${info}'")
|
||||
message(STATUS "")
|
||||
|
||||
if(verified)
|
||||
# Verify that the bundle does not have any symlinks to external files:
|
||||
#
|
||||
verify_bundle_symlinks("${bundle}" verified info)
|
||||
message(STATUS "verified='${verified}'")
|
||||
message(STATUS "info='${info}'")
|
||||
message(STATUS "")
|
||||
endif()
|
||||
|
||||
if(NOT verified)
|
||||
message(FATAL_ERROR "error: verify_app failed")
|
||||
endif()
|
||||
endfunction()
|
100
cmake/ECMQueryQt.cmake
Normal file
100
cmake/ECMQueryQt.cmake
Normal file
@ -0,0 +1,100 @@
|
||||
# SPDX-FileCopyrightText: 2014 Rohan Garg <rohan16garg@gmail.com>
|
||||
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
|
||||
# SPDX-FileCopyrightText: 2014-2016 Aleix Pol <aleixpol@kde.org>
|
||||
# SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
|
||||
# SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samir78@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#[=======================================================================[.rst:
|
||||
ECMQueryQt
|
||||
---------------
|
||||
This module can be used to query the installation paths used by Qt.
|
||||
|
||||
For Qt5 this uses ``qmake``, and for Qt6 this used ``qtpaths`` (the latter has built-in
|
||||
support to query the paths of a target platform when cross-compiling).
|
||||
|
||||
This module defines the following function:
|
||||
::
|
||||
|
||||
ecm_query_qt(<result_variable> <qt_variable> [TRY])
|
||||
|
||||
Passing ``TRY`` will result in the method not making the build fail if the executable
|
||||
used for querying has not been found, but instead simply print a warning message and
|
||||
return an empty string.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
include(ECMQueryQt)
|
||||
ecm_query_qt(bin_dir QT_INSTALL_BINS)
|
||||
|
||||
If the call succeeds ``${bin_dir}`` will be set to ``<prefix>/path/to/bin/dir`` (e.g.
|
||||
``/usr/lib64/qt/bin/``).
|
||||
|
||||
Since: 5.93
|
||||
#]=======================================================================]
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
|
||||
include(CheckLanguage)
|
||||
check_language(CXX)
|
||||
if (CMAKE_CXX_COMPILER)
|
||||
# Enable the CXX language to let CMake look for config files in library dirs.
|
||||
# See: https://gitlab.kitware.com/cmake/cmake/-/issues/23266
|
||||
enable_language(CXX)
|
||||
endif()
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
# QUIET to accommodate the TRY option
|
||||
find_package(Qt${QT_MAJOR_VERSION}Core QUIET)
|
||||
if(TARGET Qt5::qmake)
|
||||
get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
|
||||
|
||||
set(QUERY_EXECUTABLE ${_qmake_executable_default}
|
||||
CACHE FILEPATH "Location of the Qt5 qmake executable")
|
||||
set(_exec_name_text "Qt5 qmake")
|
||||
set(_cli_option "-query")
|
||||
endif()
|
||||
elseif(QT_MAJOR_VERSION STREQUAL "6")
|
||||
# QUIET to accommodate the TRY option
|
||||
find_package(Qt6 COMPONENTS CoreTools QUIET CONFIG)
|
||||
if (TARGET Qt6::qtpaths)
|
||||
get_target_property(_qtpaths_executable Qt6::qtpaths LOCATION)
|
||||
|
||||
set(QUERY_EXECUTABLE ${_qtpaths_executable}
|
||||
CACHE FILEPATH "Location of the Qt6 qtpaths executable")
|
||||
set(_exec_name_text "Qt6 qtpaths")
|
||||
set(_cli_option "--query")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(ecm_query_qt result_variable qt_variable)
|
||||
set(options TRY)
|
||||
set(oneValueArgs)
|
||||
set(multiValueArgs)
|
||||
|
||||
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT QUERY_EXECUTABLE)
|
||||
if(ARGS_TRY)
|
||||
set(${result_variable} "" PARENT_SCOPE)
|
||||
message(STATUS "No ${_exec_name_text} executable found. Can't check ${qt_variable}")
|
||||
return()
|
||||
else()
|
||||
message(FATAL_ERROR "No ${_exec_name_text} executable found. Can't check ${qt_variable} as required")
|
||||
endif()
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${QUERY_EXECUTABLE} ${_cli_option} "${qt_variable}"
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE output
|
||||
)
|
||||
if(return_code EQUAL 0)
|
||||
string(STRIP "${output}" output)
|
||||
file(TO_CMAKE_PATH "${output}" output_path)
|
||||
set(${result_variable} "${output_path}" PARENT_SCOPE)
|
||||
else()
|
||||
message(WARNING "Failed call: ${_command} \"${qt_variable}\"")
|
||||
message(FATAL_ERROR "${_exec_name_text} call failed: ${return_code}")
|
||||
endif()
|
||||
endfunction()
|
@ -3,7 +3,7 @@
|
||||
# These functions force a re-configure on each git commit so that you can
|
||||
# trust the values of the variables in your build system.
|
||||
#
|
||||
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
|
||||
#
|
||||
# Returns the refspec and sha hash of the current head revision
|
||||
#
|
||||
@ -12,20 +12,33 @@
|
||||
# Returns the results of git describe on the source tree, and adjusting
|
||||
# the output so that it tests false if an error occurs.
|
||||
#
|
||||
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe on the working tree (--dirty option),
|
||||
# and adjusting the output so that it tests false if an error occurs.
|
||||
#
|
||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe --exact-match on the source tree,
|
||||
# and adjusting the output so that it tests false if there was no exact
|
||||
# matching tag.
|
||||
#
|
||||
# git_local_changes(<var>)
|
||||
#
|
||||
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||
# Does not regard untracked files.
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Copyright 2009-2013, Iowa State University.
|
||||
# Copyright 2013-2020, Ryan Pavlik
|
||||
# Copyright 2013-2020, Contributors
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
@ -39,45 +52,124 @@ set(__get_git_revision_description YES)
|
||||
# to find the path to this module rather than the path to a calling list file
|
||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
function(get_git_head_revision _refspecvar _hashvar)
|
||||
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
||||
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
||||
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
||||
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
||||
# Function _git_find_closest_git_dir finds the next closest .git directory
|
||||
# that is part of any directory in the path defined by _start_dir.
|
||||
# The result is returned in the parent scope variable whose name is passed
|
||||
# as variable _git_dir_var. If no .git directory can be found, the
|
||||
# function returns an empty string via _git_dir_var.
|
||||
#
|
||||
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
|
||||
# neither foo nor bar contain a file/directory .git. This wil return
|
||||
# C:/bla/.git
|
||||
#
|
||||
function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
||||
set(cur_dir "${_start_dir}")
|
||||
set(git_dir "${_start_dir}/.git")
|
||||
while(NOT EXISTS "${git_dir}")
|
||||
# .git dir not found, search parent directories
|
||||
set(git_previous_parent "${cur_dir}")
|
||||
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
||||
if(cur_dir STREQUAL git_previous_parent)
|
||||
# We have reached the root directory, we are not in git
|
||||
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_git_dir_var}
|
||||
""
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
set(git_dir "${cur_dir}/.git")
|
||||
endwhile()
|
||||
# check if this is a submodule
|
||||
set(${_git_dir_var}
|
||||
"${git_dir}"
|
||||
PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(get_git_head_revision _refspecvar _hashvar)
|
||||
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
|
||||
|
||||
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
|
||||
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
|
||||
else()
|
||||
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
|
||||
endif()
|
||||
if(NOT "${GIT_DIR}" STREQUAL "")
|
||||
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
|
||||
"${GIT_DIR}")
|
||||
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
|
||||
# We've gone above the CMake root dir.
|
||||
set(GIT_DIR "")
|
||||
endif()
|
||||
endif()
|
||||
if("${GIT_DIR}" STREQUAL "")
|
||||
set(${_refspecvar}
|
||||
"GITDIR-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
set(${_hashvar}
|
||||
"GITDIR-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Check if the current source dir is a git submodule or a worktree.
|
||||
# In both cases .git is a file instead of a directory.
|
||||
#
|
||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||
# The following git command will return a non empty string that
|
||||
# points to the super project working tree if the current
|
||||
# source dir is inside a git submodule.
|
||||
# Otherwise the command will return an empty string.
|
||||
#
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" rev-parse
|
||||
--show-superproject-working-tree
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT "${out}" STREQUAL "")
|
||||
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
|
||||
${submodule})
|
||||
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
|
||||
ABSOLUTE)
|
||||
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||
else()
|
||||
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
||||
file(READ ${GIT_DIR} worktree_ref)
|
||||
# The .git directory contains a path to the worktree information directory
|
||||
# inside the parent git repo of the worktree.
|
||||
#
|
||||
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
|
||||
${worktree_ref})
|
||||
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
||||
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
|
||||
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
||||
endif()
|
||||
else()
|
||||
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||
endif()
|
||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||
if(NOT EXISTS "${GIT_DATA}")
|
||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
||||
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
|
||||
return()
|
||||
endif()
|
||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
||||
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
||||
|
||||
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||
"${GIT_DATA}/grabRef.cmake"
|
||||
@ONLY)
|
||||
"${GIT_DATA}/grabRef.cmake" @ONLY)
|
||||
include("${GIT_DATA}/grabRef.cmake")
|
||||
|
||||
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
||||
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
||||
set(${_refspecvar}
|
||||
"${HEAD_REF}"
|
||||
PARENT_SCOPE)
|
||||
set(${_hashvar}
|
||||
"${HEAD_HASH}"
|
||||
PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_describe _var)
|
||||
@ -86,45 +178,107 @@ function(git_describe _var)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_var}
|
||||
"GIT-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_var}
|
||||
"HEAD-HASH-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO sanitize
|
||||
#if((${ARGN}" MATCHES "&&") OR
|
||||
# (ARGN MATCHES "||") OR
|
||||
# (ARGN MATCHES "\\;"))
|
||||
# message("Please report the following error to the project!")
|
||||
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||
# (ARGN MATCHES "||") OR
|
||||
# (ARGN MATCHES "\\;"))
|
||||
# message("Please report the following error to the project!")
|
||||
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||
#endif()
|
||||
|
||||
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
describe
|
||||
${hash}
|
||||
${ARGN}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE res
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
set(${_var}
|
||||
"${out}"
|
||||
PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_describe_working_tree _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var}
|
||||
"GIT-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE res
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(${_var}
|
||||
"${out}"
|
||||
PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_get_exact_tag _var)
|
||||
git_describe(out --exact-match ${ARGN})
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
set(${_var}
|
||||
"${out}"
|
||||
PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_local_changes _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var}
|
||||
"GIT-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var}
|
||||
"HEAD-HASH-NOTFOUND"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE res
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(res EQUAL 0)
|
||||
set(${_var}
|
||||
"CLEAN"
|
||||
PARENT_SCOPE)
|
||||
else()
|
||||
set(${_var}
|
||||
"DIRTY"
|
||||
PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
@ -8,10 +8,12 @@
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Copyright 2009-2012, Iowa State University
|
||||
# Copyright 2011-2015, Contributors
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
set(HEAD_HASH)
|
||||
|
||||
@ -19,23 +21,23 @@ file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||
|
||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||
if(HEAD_CONTENTS MATCHES "ref")
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
else()
|
||||
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
else()
|
||||
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
endif()
|
||||
|
||||
if(NOT HEAD_HASH)
|
||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
endif()
|
||||
|
@ -1,902 +0,0 @@
|
||||
# - Functions to analyze and list executable file prerequisites.
|
||||
# This module provides functions to list the .dll, .dylib or .so
|
||||
# files that an executable or shared library file depends on. (Its
|
||||
# prerequisites.)
|
||||
#
|
||||
# It uses various tools to obtain the list of required shared library files:
|
||||
# dumpbin (Windows)
|
||||
# objdump (MinGW on Windows)
|
||||
# ldd (Linux/Unix)
|
||||
# otool (Mac OSX)
|
||||
# The following functions are provided by this module:
|
||||
# get_prerequisites
|
||||
# list_prerequisites
|
||||
# list_prerequisites_by_glob
|
||||
# gp_append_unique
|
||||
# is_file_executable
|
||||
# gp_item_default_embedded_path
|
||||
# (projects can override with gp_item_default_embedded_path_override)
|
||||
# gp_resolve_item
|
||||
# (projects can override with gp_resolve_item_override)
|
||||
# gp_resolved_file_type
|
||||
# (projects can override with gp_resolved_file_type_override)
|
||||
# gp_file_type
|
||||
# Requires CMake 2.6 or greater because it uses function, break, return and
|
||||
# PARENT_SCOPE.
|
||||
#
|
||||
# GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
|
||||
# <exepath> <dirs>)
|
||||
# Get the list of shared library files required by <target>. The list in
|
||||
# the variable named <prerequisites_var> should be empty on first entry to
|
||||
# this function. On exit, <prerequisites_var> will contain the list of
|
||||
# required shared library files.
|
||||
#
|
||||
# <target> is the full path to an executable file. <prerequisites_var> is the
|
||||
# name of a CMake variable to contain the results. <exclude_system> must be 0
|
||||
# or 1 indicating whether to include or exclude "system" prerequisites. If
|
||||
# <recurse> is set to 1 all prerequisites will be found recursively, if set to
|
||||
# 0 only direct prerequisites are listed. <exepath> is the path to the top
|
||||
# level executable used for @executable_path replacment on the Mac. <dirs> is
|
||||
# a list of paths where libraries might be found: these paths are searched
|
||||
# first when a target without any path info is given. Then standard system
|
||||
# locations are also searched: PATH, Framework locations, /usr/lib...
|
||||
#
|
||||
# LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]])
|
||||
# Print a message listing the prerequisites of <target>.
|
||||
#
|
||||
# <target> is the name of a shared library or executable target or the full
|
||||
# path to a shared library or executable file. If <recurse> is set to 1 all
|
||||
# prerequisites will be found recursively, if set to 0 only direct
|
||||
# prerequisites are listed. <exclude_system> must be 0 or 1 indicating whether
|
||||
# to include or exclude "system" prerequisites. With <verbose> set to 0 only
|
||||
# the full path names of the prerequisites are printed, set to 1 extra
|
||||
# informatin will be displayed.
|
||||
#
|
||||
# LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>)
|
||||
# Print the prerequisites of shared library and executable files matching a
|
||||
# globbing pattern. <glob_arg> is GLOB or GLOB_RECURSE and <glob_exp> is a
|
||||
# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve
|
||||
# a list of matching files. If a matching file is executable, its prerequisites
|
||||
# are listed.
|
||||
#
|
||||
# Any additional (optional) arguments provided are passed along as the
|
||||
# optional arguments to the list_prerequisites calls.
|
||||
#
|
||||
# GP_APPEND_UNIQUE(<list_var> <value>)
|
||||
# Append <value> to the list variable <list_var> only if the value is not
|
||||
# already in the list.
|
||||
#
|
||||
# IS_FILE_EXECUTABLE(<file> <result_var>)
|
||||
# Return 1 in <result_var> if <file> is a binary executable, 0 otherwise.
|
||||
#
|
||||
# GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>)
|
||||
# Return the path that others should refer to the item by when the item
|
||||
# is embedded inside a bundle.
|
||||
#
|
||||
# Override on a per-project basis by providing a project-specific
|
||||
# gp_item_default_embedded_path_override function.
|
||||
#
|
||||
# GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>)
|
||||
# Resolve an item into an existing full path file.
|
||||
#
|
||||
# Override on a per-project basis by providing a project-specific
|
||||
# gp_resolve_item_override function.
|
||||
#
|
||||
# GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>)
|
||||
# Return the type of <file> with respect to <original_file>. String
|
||||
# describing type of prerequisite is returned in variable named <type_var>.
|
||||
#
|
||||
# Use <exepath> and <dirs> if necessary to resolve non-absolute <file>
|
||||
# values -- but only for non-embedded items.
|
||||
#
|
||||
# Possible types are:
|
||||
# system
|
||||
# local
|
||||
# embedded
|
||||
# other
|
||||
# Override on a per-project basis by providing a project-specific
|
||||
# gp_resolved_file_type_override function.
|
||||
#
|
||||
# GP_FILE_TYPE(<original_file> <file> <type_var>)
|
||||
# Return the type of <file> with respect to <original_file>. String
|
||||
# describing type of prerequisite is returned in variable named <type_var>.
|
||||
#
|
||||
# Possible types are:
|
||||
# system
|
||||
# local
|
||||
# embedded
|
||||
# other
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2008-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
function(gp_append_unique list_var value)
|
||||
set(contains 0)
|
||||
|
||||
foreach(item ${${list_var}})
|
||||
if("${item}" STREQUAL "${value}")
|
||||
set(contains 1)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT contains)
|
||||
set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(is_file_executable file result_var)
|
||||
#
|
||||
# A file is not executable until proven otherwise:
|
||||
#
|
||||
set(${result_var} 0 PARENT_SCOPE)
|
||||
|
||||
get_filename_component(file_full "${file}" ABSOLUTE)
|
||||
string(TOLOWER "${file_full}" file_full_lower)
|
||||
|
||||
# If file name ends in .exe on Windows, *assume* executable:
|
||||
#
|
||||
if(WIN32 AND NOT UNIX)
|
||||
if("${file_full_lower}" MATCHES "\\.exe$")
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# A clause could be added here that uses output or return value of dumpbin
|
||||
# to determine ${result_var}. In 99%+? practical cases, the exe name
|
||||
# match will be sufficient...
|
||||
#
|
||||
endif()
|
||||
|
||||
# Use the information returned from the Unix shell command "file" to
|
||||
# determine if ${file_full} should be considered an executable file...
|
||||
#
|
||||
# If the file command's output contains "executable" and does *not* contain
|
||||
# "text" then it is likely an executable suitable for prerequisite analysis
|
||||
# via the get_prerequisites macro.
|
||||
#
|
||||
if(UNIX)
|
||||
if(NOT file_cmd)
|
||||
find_program(file_cmd "file")
|
||||
mark_as_advanced(file_cmd)
|
||||
endif()
|
||||
|
||||
if(file_cmd)
|
||||
execute_process(COMMAND "${file_cmd}" "${file_full}"
|
||||
OUTPUT_VARIABLE file_ov
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Replace the name of the file in the output with a placeholder token
|
||||
# (the string " _file_full_ ") so that just in case the path name of
|
||||
# the file contains the word "text" or "executable" we are not fooled
|
||||
# into thinking "the wrong thing" because the file name matches the
|
||||
# other 'file' command output we are looking for...
|
||||
#
|
||||
string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
|
||||
string(TOLOWER "${file_ov}" file_ov)
|
||||
|
||||
#message(STATUS "file_ov='${file_ov}'")
|
||||
if("${file_ov}" MATCHES "executable")
|
||||
#message(STATUS "executable!")
|
||||
if("${file_ov}" MATCHES "text")
|
||||
#message(STATUS "but text, so *not* a binary executable!")
|
||||
else()
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Also detect position independent executables on Linux,
|
||||
# where "file" gives "shared object ... (uses shared libraries)"
|
||||
if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)")
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# "file" version 5.22 does not print "(used shared libraries)"
|
||||
# but uses "interpreter"
|
||||
if("${file_ov}" MATCHES "shared object.*interpreter")
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
else()
|
||||
message(STATUS "warning: No 'file' command, skipping execute_process...")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_item_default_embedded_path item default_embedded_path_var)
|
||||
|
||||
# On Windows and Linux, "embed" prerequisites in the same directory
|
||||
# as the executable by default:
|
||||
#
|
||||
set(path "@executable_path")
|
||||
set(overridden 0)
|
||||
|
||||
# On the Mac, relative to the executable depending on the type
|
||||
# of the thing we are embedding:
|
||||
#
|
||||
if(APPLE)
|
||||
#
|
||||
# The assumption here is that all executables in the bundle will be
|
||||
# in same-level-directories inside the bundle. The parent directory
|
||||
# of an executable inside the bundle should be MacOS or a sibling of
|
||||
# MacOS and all embedded paths returned from here will begin with
|
||||
# "@executable_path/../" and will work from all executables in all
|
||||
# such same-level-directories inside the bundle.
|
||||
#
|
||||
|
||||
# By default, embed things right next to the main bundle executable:
|
||||
#
|
||||
set(path "@executable_path/../../Contents/MacOS")
|
||||
|
||||
# Embed .dylibs right next to the main bundle executable:
|
||||
#
|
||||
if(item MATCHES "\\.dylib$")
|
||||
set(path "@executable_path/../MacOS")
|
||||
set(overridden 1)
|
||||
endif()
|
||||
|
||||
# Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS):
|
||||
#
|
||||
if(NOT overridden)
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
set(path "@executable_path/../Frameworks")
|
||||
set(overridden 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Provide a hook so that projects can override the default embedded location
|
||||
# of any given library by whatever logic they choose:
|
||||
#
|
||||
if(COMMAND gp_item_default_embedded_path_override)
|
||||
gp_item_default_embedded_path_override("${item}" path)
|
||||
endif()
|
||||
|
||||
set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_resolve_item context item exepath dirs resolved_item_var)
|
||||
set(resolved 0)
|
||||
set(resolved_item "${item}")
|
||||
|
||||
# Is it already resolved?
|
||||
#
|
||||
if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
|
||||
set(resolved 1)
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "@executable_path")
|
||||
#
|
||||
# @executable_path references are assumed relative to exepath
|
||||
#
|
||||
string(REPLACE "@executable_path" "${exepath}" ri "${item}")
|
||||
get_filename_component(ri "${ri}" ABSOLUTE)
|
||||
|
||||
if(EXISTS "${ri}")
|
||||
#message(STATUS "info: embedded item exists (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
else()
|
||||
message(STATUS "warning: embedded item does not exist '${ri}'")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "@loader_path")
|
||||
#
|
||||
# @loader_path references are assumed relative to the
|
||||
# PATH of the given "context" (presumably another library)
|
||||
#
|
||||
get_filename_component(contextpath "${context}" PATH)
|
||||
string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
|
||||
get_filename_component(ri "${ri}" ABSOLUTE)
|
||||
|
||||
if(EXISTS "${ri}")
|
||||
#message(STATUS "info: embedded item exists (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
else()
|
||||
message(STATUS "warning: embedded item does not exist '${ri}'")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "@rpath")
|
||||
#
|
||||
# @rpath references are relative to the paths built into the binaries with -rpath
|
||||
# We handle this case like we do for other Unixes
|
||||
#
|
||||
string(REPLACE "@rpath/" "" norpath_item "${item}")
|
||||
|
||||
set(ri "ri-NOTFOUND")
|
||||
find_file(ri "${norpath_item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
|
||||
if(ri)
|
||||
#message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
set(ri "ri-NOTFOUND")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
set(ri "ri-NOTFOUND")
|
||||
find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
|
||||
find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
|
||||
if(ri)
|
||||
#message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
set(ri "ri-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
set(fw "fw-NOTFOUND")
|
||||
find_file(fw "${item}"
|
||||
"~/Library/Frameworks"
|
||||
"/Library/Frameworks"
|
||||
"/System/Library/Frameworks"
|
||||
)
|
||||
if(fw)
|
||||
#message(STATUS "info: 'find_file' found framework (${fw})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${fw}")
|
||||
set(fw "fw-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Using find_program on Windows will find dll files that are in the PATH.
|
||||
# (Converting simple file names into full path names if found.)
|
||||
#
|
||||
if(WIN32 AND NOT UNIX)
|
||||
if(NOT resolved)
|
||||
set(ri "ri-NOTFOUND")
|
||||
find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH)
|
||||
find_program(ri "${item}" PATHS "${exepath};${dirs}")
|
||||
if(ri)
|
||||
#message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
set(ri "ri-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Provide a hook so that projects can override item resolution
|
||||
# by whatever logic they choose:
|
||||
#
|
||||
if(COMMAND gp_resolve_item_override)
|
||||
gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
message(STATUS "
|
||||
warning: cannot resolve item '${item}'
|
||||
|
||||
possible problems:
|
||||
need more directories?
|
||||
need to use InstallRequiredSystemLibraries?
|
||||
run in install tree instead of build tree?
|
||||
")
|
||||
# message(STATUS "
|
||||
#******************************************************************************
|
||||
#warning: cannot resolve item '${item}'
|
||||
#
|
||||
# possible problems:
|
||||
# need more directories?
|
||||
# need to use InstallRequiredSystemLibraries?
|
||||
# run in install tree instead of build tree?
|
||||
#
|
||||
# context='${context}'
|
||||
# item='${item}'
|
||||
# exepath='${exepath}'
|
||||
# dirs='${dirs}'
|
||||
# resolved_item_var='${resolved_item_var}'
|
||||
#******************************************************************************
|
||||
#")
|
||||
endif()
|
||||
|
||||
set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_resolved_file_type original_file file exepath dirs type_var)
|
||||
#message(STATUS "**")
|
||||
|
||||
if(NOT IS_ABSOLUTE "${original_file}")
|
||||
message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
|
||||
endif()
|
||||
|
||||
set(is_embedded 0)
|
||||
set(is_local 0)
|
||||
set(is_system 0)
|
||||
|
||||
set(resolved_file "${file}")
|
||||
|
||||
if("${file}" MATCHES "^@(executable|loader)_path")
|
||||
set(is_embedded 1)
|
||||
endif()
|
||||
|
||||
if(NOT is_embedded)
|
||||
if(NOT IS_ABSOLUTE "${file}")
|
||||
gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file)
|
||||
endif()
|
||||
|
||||
string(TOLOWER "${original_file}" original_lower)
|
||||
string(TOLOWER "${resolved_file}" lower)
|
||||
|
||||
if(UNIX)
|
||||
if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
string(TOLOWER "$ENV{SystemRoot}" sysroot)
|
||||
string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}")
|
||||
|
||||
string(TOLOWER "$ENV{windir}" windir)
|
||||
string(REGEX REPLACE "\\\\" "/" windir "${windir}")
|
||||
|
||||
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
# if cygwin, we can get the properly formed windows paths from cygpath
|
||||
find_program(CYGPATH_EXECUTABLE cygpath)
|
||||
|
||||
if(CYGPATH_EXECUTABLE)
|
||||
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W
|
||||
OUTPUT_VARIABLE env_windir
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S
|
||||
OUTPUT_VARIABLE env_sysdir
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(TOLOWER "${env_windir}" windir)
|
||||
string(TOLOWER "${env_sysdir}" sysroot)
|
||||
|
||||
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT is_system)
|
||||
get_filename_component(original_path "${original_lower}" PATH)
|
||||
get_filename_component(path "${lower}" PATH)
|
||||
if("${original_path}" STREQUAL "${path}")
|
||||
set(is_local 1)
|
||||
else()
|
||||
string(LENGTH "${original_path}/" original_length)
|
||||
string(LENGTH "${lower}" path_length)
|
||||
if(${path_length} GREATER ${original_length})
|
||||
string(SUBSTRING "${lower}" 0 ${original_length} path)
|
||||
if("${original_path}/" STREQUAL "${path}")
|
||||
set(is_embedded 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Return type string based on computed booleans:
|
||||
#
|
||||
set(type "other")
|
||||
|
||||
if(is_system)
|
||||
set(type "system")
|
||||
elseif(is_embedded)
|
||||
set(type "embedded")
|
||||
elseif(is_local)
|
||||
set(type "local")
|
||||
endif()
|
||||
|
||||
#message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
|
||||
#message(STATUS " type: '${type}'")
|
||||
|
||||
if(NOT is_embedded)
|
||||
if(NOT IS_ABSOLUTE "${resolved_file}")
|
||||
if(lower MATCHES "^msvc[^/]+dll" AND is_system)
|
||||
message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
|
||||
else()
|
||||
message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Provide a hook so that projects can override the decision on whether a
|
||||
# library belongs to the system or not by whatever logic they choose:
|
||||
#
|
||||
if(COMMAND gp_resolved_file_type_override)
|
||||
gp_resolved_file_type_override("${resolved_file}" type)
|
||||
endif()
|
||||
|
||||
set(${type_var} "${type}" PARENT_SCOPE)
|
||||
|
||||
#message(STATUS "**")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_file_type original_file file type_var)
|
||||
if(NOT IS_ABSOLUTE "${original_file}")
|
||||
message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
|
||||
endif()
|
||||
|
||||
get_filename_component(exepath "${original_file}" PATH)
|
||||
|
||||
set(type "")
|
||||
gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
|
||||
|
||||
set(${type_var} "${type}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
|
||||
set(verbose 0)
|
||||
set(eol_char "E")
|
||||
|
||||
if(NOT IS_ABSOLUTE "${target}")
|
||||
message("warning: target '${target}' is not absolute...")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${target}")
|
||||
message("warning: target '${target}' does not exist...")
|
||||
endif()
|
||||
|
||||
set(gp_cmd_paths ${gp_cmd_paths}
|
||||
"C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
|
||||
"C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
|
||||
"C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
|
||||
"/usr/local/bin"
|
||||
"/usr/bin"
|
||||
)
|
||||
|
||||
# <setup-gp_tool-vars>
|
||||
#
|
||||
# Try to choose the right tool by default. Caller can set gp_tool prior to
|
||||
# calling this function to force using a different tool.
|
||||
#
|
||||
if("${gp_tool}" STREQUAL "")
|
||||
set(gp_tool "ldd")
|
||||
|
||||
if(APPLE)
|
||||
set(gp_tool "otool")
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har!
|
||||
find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths})
|
||||
if(gp_dumpbin)
|
||||
set(gp_tool "dumpbin")
|
||||
else() # Try harder. Maybe we're on MinGW
|
||||
set(gp_tool "objdump")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
|
||||
|
||||
if(NOT gp_cmd)
|
||||
message(FATAL_ERROR "FATAL ERROR: could not find '${gp_tool}' - cannot analyze prerequisites!")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(gp_tool_known 0)
|
||||
|
||||
if("${gp_tool}" STREQUAL "ldd")
|
||||
set(gp_cmd_args "")
|
||||
set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$")
|
||||
set(gp_regex_error "not found${eol_char}$")
|
||||
set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$")
|
||||
set(gp_regex_cmp_count 1)
|
||||
set(gp_tool_known 1)
|
||||
endif()
|
||||
|
||||
if("${gp_tool}" STREQUAL "otool")
|
||||
set(gp_cmd_args "-L")
|
||||
set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
|
||||
set(gp_regex_error "")
|
||||
set(gp_regex_fallback "")
|
||||
set(gp_regex_cmp_count 3)
|
||||
set(gp_tool_known 1)
|
||||
endif()
|
||||
|
||||
if("${gp_tool}" STREQUAL "dumpbin")
|
||||
set(gp_cmd_args "/dependents")
|
||||
set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
|
||||
set(gp_regex_error "")
|
||||
set(gp_regex_fallback "")
|
||||
set(gp_regex_cmp_count 1)
|
||||
set(gp_tool_known 1)
|
||||
endif()
|
||||
|
||||
if("${gp_tool}" STREQUAL "objdump")
|
||||
set(gp_cmd_args "-p")
|
||||
set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$")
|
||||
set(gp_regex_error "")
|
||||
set(gp_regex_fallback "")
|
||||
set(gp_regex_cmp_count 1)
|
||||
set(gp_tool_known 1)
|
||||
endif()
|
||||
|
||||
if(NOT gp_tool_known)
|
||||
message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
|
||||
message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
|
||||
message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
if("${gp_tool}" STREQUAL "dumpbin")
|
||||
# When running dumpbin, it also needs the "Common7/IDE" directory in the
|
||||
# PATH. It will already be in the PATH if being run from a Visual Studio
|
||||
# command prompt. Add it to the PATH here in case we are running from a
|
||||
# different command prompt.
|
||||
#
|
||||
get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
|
||||
get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
|
||||
# Use cmake paths as a user may have a PATH element ending with a backslash.
|
||||
# This will escape the list delimiter and create havoc!
|
||||
if(EXISTS "${gp_cmd_dlls_dir}")
|
||||
# only add to the path if it is not already in the path
|
||||
set(gp_found_cmd_dlls_dir 0)
|
||||
file(TO_CMAKE_PATH "$ENV{PATH}" env_path)
|
||||
foreach(gp_env_path_element ${env_path})
|
||||
if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}")
|
||||
set(gp_found_cmd_dlls_dir 1)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT gp_found_cmd_dlls_dir)
|
||||
file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir)
|
||||
set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
#
|
||||
# </setup-gp_tool-vars>
|
||||
|
||||
if("${gp_tool}" STREQUAL "ldd")
|
||||
set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
|
||||
foreach(dir ${exepath} ${dirs})
|
||||
set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
||||
# Track new prerequisites at each new level of recursion. Start with an
|
||||
# empty list at each level:
|
||||
#
|
||||
set(unseen_prereqs)
|
||||
|
||||
# Run gp_cmd on the target:
|
||||
#
|
||||
execute_process(
|
||||
COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
|
||||
OUTPUT_VARIABLE gp_cmd_ov
|
||||
)
|
||||
|
||||
if("${gp_tool}" STREQUAL "ldd")
|
||||
set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
|
||||
endif()
|
||||
|
||||
if(verbose)
|
||||
message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
|
||||
message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
|
||||
message(STATUS "</RawOutput>")
|
||||
endif()
|
||||
|
||||
get_filename_component(target_dir "${target}" PATH)
|
||||
|
||||
# Convert to a list of lines:
|
||||
#
|
||||
string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}")
|
||||
string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}")
|
||||
|
||||
# check for install id and remove it from list, since otool -L can include a
|
||||
# reference to itself
|
||||
set(gp_install_id)
|
||||
if("${gp_tool}" STREQUAL "otool")
|
||||
execute_process(
|
||||
COMMAND otool -D ${target}
|
||||
OUTPUT_VARIABLE gp_install_id_ov
|
||||
)
|
||||
# second line is install name
|
||||
string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
|
||||
if(gp_install_id)
|
||||
# trim
|
||||
string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}")
|
||||
#message("INSTALL ID is \"${gp_install_id}\"")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Analyze each line for file names that match the regular expression:
|
||||
#
|
||||
foreach(candidate ${candidates})
|
||||
if("${candidate}" MATCHES "${gp_regex}")
|
||||
|
||||
# Extract information from each candidate:
|
||||
if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}")
|
||||
string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}")
|
||||
else()
|
||||
string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
|
||||
endif()
|
||||
|
||||
if(gp_regex_cmp_count GREATER 1)
|
||||
string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
|
||||
endif()
|
||||
|
||||
if(gp_regex_cmp_count GREATER 2)
|
||||
string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
|
||||
endif()
|
||||
|
||||
# Use the raw_item as the list entries returned by this function. Use the
|
||||
# gp_resolve_item function to resolve it to an actual full path file if
|
||||
# necessary.
|
||||
#
|
||||
set(item "${raw_item}")
|
||||
|
||||
# Add each item unless it is excluded:
|
||||
#
|
||||
set(add_item 1)
|
||||
|
||||
if("${item}" STREQUAL "${gp_install_id}")
|
||||
set(add_item 0)
|
||||
endif()
|
||||
|
||||
if(add_item AND ${exclude_system})
|
||||
set(type "")
|
||||
gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type)
|
||||
|
||||
if("${type}" STREQUAL "system")
|
||||
set(add_item 0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(add_item)
|
||||
list(LENGTH ${prerequisites_var} list_length_before_append)
|
||||
gp_append_unique(${prerequisites_var} "${item}")
|
||||
list(LENGTH ${prerequisites_var} list_length_after_append)
|
||||
|
||||
if(${recurse})
|
||||
# If item was really added, this is the first time we have seen it.
|
||||
# Add it to unseen_prereqs so that we can recursively add *its*
|
||||
# prerequisites...
|
||||
#
|
||||
# But first: resolve its name to an absolute full path name such
|
||||
# that the analysis tools can simply accept it as input.
|
||||
#
|
||||
if(NOT list_length_before_append EQUAL list_length_after_append)
|
||||
gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item)
|
||||
set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(verbose)
|
||||
message(STATUS "ignoring non-matching line: '${candidate}'")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(LENGTH ${prerequisites_var} prerequisites_var_length)
|
||||
if(prerequisites_var_length GREATER 0)
|
||||
list(SORT ${prerequisites_var})
|
||||
endif()
|
||||
if(${recurse})
|
||||
set(more_inputs ${unseen_prereqs})
|
||||
foreach(input ${more_inputs})
|
||||
get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(list_prerequisites target)
|
||||
if("${ARGV1}" STREQUAL "")
|
||||
set(all 1)
|
||||
else()
|
||||
set(all "${ARGV1}")
|
||||
endif()
|
||||
|
||||
if("${ARGV2}" STREQUAL "")
|
||||
set(exclude_system 0)
|
||||
else()
|
||||
set(exclude_system "${ARGV2}")
|
||||
endif()
|
||||
|
||||
if("${ARGV3}" STREQUAL "")
|
||||
set(verbose 0)
|
||||
else()
|
||||
set(verbose "${ARGV3}")
|
||||
endif()
|
||||
|
||||
set(count 0)
|
||||
set(count_str "")
|
||||
set(print_count "${verbose}")
|
||||
set(print_prerequisite_type "${verbose}")
|
||||
set(print_target "${verbose}")
|
||||
set(type_str "")
|
||||
|
||||
get_filename_component(exepath "${target}" PATH)
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
|
||||
|
||||
if(print_target)
|
||||
message(STATUS "File '${target}' depends on:")
|
||||
endif()
|
||||
|
||||
foreach(d ${prereqs})
|
||||
math(EXPR count "${count} + 1")
|
||||
|
||||
if(print_count)
|
||||
set(count_str "${count}. ")
|
||||
endif()
|
||||
|
||||
if(print_prerequisite_type)
|
||||
gp_file_type("${target}" "${d}" type)
|
||||
set(type_str " (${type})")
|
||||
endif()
|
||||
|
||||
message(STATUS "${count_str}${d}${type_str}")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(list_prerequisites_by_glob glob_arg glob_exp)
|
||||
message(STATUS "=============================================================================")
|
||||
message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
|
||||
message(STATUS "")
|
||||
file(${glob_arg} file_list ${glob_exp})
|
||||
foreach(f ${file_list})
|
||||
is_file_executable("${f}" is_f_executable)
|
||||
if(is_f_executable)
|
||||
message(STATUS "=============================================================================")
|
||||
list_prerequisites("${f}" ${ARGN})
|
||||
message(STATUS "")
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
@ -2,10 +2,10 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>A Minecraft mod wants to access your camera.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>A Minecraft mod wants to access your microphone.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>A Minecraft mod wants to access your camera.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>A Minecraft mod wants to access your microphone.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
@ -40,5 +40,9 @@
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
<key>SUPublicEDKey</key>
|
||||
<string>${MACOSX_SPARKLE_UPDATE_PUBLIC_KEY}</string>
|
||||
<key>SUFeedURL</key>
|
||||
<string>${MACOSX_SPARKLE_UPDATE_FEED_URL}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -1,14 +0,0 @@
|
||||
if(__QMAKEQUERY_CMAKE__)
|
||||
return()
|
||||
endif()
|
||||
set(__QMAKEQUERY_CMAKE__ TRUE)
|
||||
|
||||
get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION)
|
||||
|
||||
function(QUERY_QMAKE VAR RESULT)
|
||||
exec_program(${QMAKE_EXECUTABLE} ARGS "-query ${VAR}" RETURN_VALUE return_code OUTPUT_VARIABLE output )
|
||||
if(NOT return_code)
|
||||
file(TO_CMAKE_PATH "${output}" output)
|
||||
set(${RESULT} ${output} PARENT_SCOPE)
|
||||
endif(NOT return_code)
|
||||
endfunction(QUERY_QMAKE)
|
38
cmake/QtVersionOption.cmake
Normal file
38
cmake/QtVersionOption.cmake
Normal file
@ -0,0 +1,38 @@
|
||||
#.rst:
|
||||
# QtVersionOption
|
||||
# ---------------
|
||||
#
|
||||
# Adds a build option to select the major Qt version if necessary,
|
||||
# that is, if the major Qt version has not yet been determined otherwise
|
||||
# (e.g. by a corresponding find_package() call).
|
||||
#
|
||||
# This module is typically included by other modules requiring knowledge
|
||||
# about the major Qt version.
|
||||
#
|
||||
# ``QT_MAJOR_VERSION`` is defined to either be "5" or "6".
|
||||
#
|
||||
#
|
||||
# Since 5.82.0.
|
||||
|
||||
#=============================================================================
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if (DEFINED QT_MAJOR_VERSION)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (TARGET Qt5::Core)
|
||||
set(QT_MAJOR_VERSION 5)
|
||||
elseif (TARGET Qt6::Core)
|
||||
set(QT_MAJOR_VERSION 6)
|
||||
else()
|
||||
option(BUILD_WITH_QT6 "Build against Qt 6" OFF)
|
||||
|
||||
if (BUILD_WITH_QT6)
|
||||
set(QT_MAJOR_VERSION 6)
|
||||
else()
|
||||
set(QT_MAJOR_VERSION 5)
|
||||
endif()
|
||||
endif()
|
97
cmake/QtVersionlessBackport.cmake
Normal file
97
cmake/QtVersionlessBackport.cmake
Normal file
@ -0,0 +1,97 @@
|
||||
#=============================================================================
|
||||
# Copyright 2005-2011 Kitware, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# * Neither the name of Kitware, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#=============================================================================
|
||||
|
||||
# From Qt5CoreMacros.cmake
|
||||
|
||||
function(qt_generate_moc)
|
||||
if(QT_VERSION_MAJOR EQUAL 5)
|
||||
qt5_generate_moc(${ARGV})
|
||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt6_generate_moc(${ARGV})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(qt_wrap_cpp outfiles)
|
||||
if(QT_VERSION_MAJOR EQUAL 5)
|
||||
qt5_wrap_cpp("${outfiles}" ${ARGN})
|
||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt6_wrap_cpp("${outfiles}" ${ARGN})
|
||||
endif()
|
||||
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(qt_add_binary_resources)
|
||||
if(QT_VERSION_MAJOR EQUAL 5)
|
||||
qt5_add_binary_resources(${ARGV})
|
||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt6_add_binary_resources(${ARGV})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(qt_add_resources outfiles)
|
||||
if(QT_VERSION_MAJOR EQUAL 5)
|
||||
qt5_add_resources("${outfiles}" ${ARGN})
|
||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt6_add_resources("${outfiles}" ${ARGN})
|
||||
endif()
|
||||
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(qt_add_big_resources outfiles)
|
||||
if(QT_VERSION_MAJOR EQUAL 5)
|
||||
qt5_add_big_resources(${outfiles} ${ARGN})
|
||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt6_add_big_resources(${outfiles} ${ARGN})
|
||||
endif()
|
||||
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(qt_import_plugins)
|
||||
if(QT_VERSION_MAJOR EQUAL 5)
|
||||
qt5_import_plugins(${ARGV})
|
||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt6_import_plugins(${ARGV})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
# From Qt5WidgetsMacros.cmake
|
||||
|
||||
function(qt_wrap_ui outfiles)
|
||||
if(QT_VERSION_MAJOR EQUAL 5)
|
||||
qt5_wrap_ui("${outfiles}" ${ARGN})
|
||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt6_wrap_ui("${outfiles}" ${ARGN})
|
||||
endif()
|
||||
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
@ -1,50 +0,0 @@
|
||||
find_package(Qt5Test REQUIRED)
|
||||
|
||||
set(TEST_RESOURCE_PATH ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
message(${TEST_RESOURCE_PATH})
|
||||
|
||||
function(add_unit_test name)
|
||||
if(BUILD_TESTING)
|
||||
set(options "")
|
||||
set(oneValueArgs DATA)
|
||||
set(multiValueArgs SOURCES LIBS)
|
||||
|
||||
cmake_parse_arguments(OPT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||
|
||||
if(WIN32)
|
||||
add_executable(${name}_test ${OPT_SOURCES} ${TEST_RESOURCE_PATH}/UnitTest/test.rc)
|
||||
else()
|
||||
add_executable(${name}_test ${OPT_SOURCES})
|
||||
endif()
|
||||
|
||||
if(NOT "${OPT_DATA}" STREQUAL "")
|
||||
set(TEST_DATA_PATH "${CMAKE_CURRENT_BINARY_DIR}/data")
|
||||
set(TEST_DATA_PATH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${OPT_DATA}")
|
||||
message("From ${TEST_DATA_PATH_SRC} to ${TEST_DATA_PATH}")
|
||||
string(REGEX REPLACE "[/\\:]" "_" DATA_TARGET_NAME "${TEST_DATA_PATH_SRC}")
|
||||
if(UNIX)
|
||||
# on unix we get the third / from the filename
|
||||
set(TEST_DATA_URL "file://${TEST_DATA_PATH}")
|
||||
else()
|
||||
# we don't on windows, so we have to add it ourselves
|
||||
set(TEST_DATA_URL "file:///${TEST_DATA_PATH}")
|
||||
endif()
|
||||
if(NOT TARGET "${DATA_TARGET_NAME}")
|
||||
add_custom_target(${DATA_TARGET_NAME})
|
||||
add_dependencies(${name}_test ${DATA_TARGET_NAME})
|
||||
add_custom_command(
|
||||
TARGET ${DATA_TARGET_NAME}
|
||||
COMMAND ${CMAKE_COMMAND} "-DTEST_DATA_URL=${TEST_DATA_URL}" -DSOURCE=${TEST_DATA_PATH_SRC} -DDESTINATION=${TEST_DATA_PATH} -P ${TEST_RESOURCE_PATH}/UnitTest/generate_test_data.cmake
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(${name}_test Qt5::Test ${OPT_LIBS})
|
||||
|
||||
target_include_directories(${name}_test PRIVATE "${TEST_RESOURCE_PATH}/UnitTest/")
|
||||
|
||||
add_test(NAME ${name} COMMAND ${name}_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
endfunction()
|
@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QFile>
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QDir>
|
||||
|
||||
#define expandstr(s) expandstr2(s)
|
||||
#define expandstr2(s) #s
|
||||
|
||||
class TestsInternal
|
||||
{
|
||||
public:
|
||||
static QByteArray readFile(const QString &fileName)
|
||||
{
|
||||
QFile f(fileName);
|
||||
f.open(QFile::ReadOnly);
|
||||
return f.readAll();
|
||||
}
|
||||
static QString readFileUtf8(const QString &fileName)
|
||||
{
|
||||
return QString::fromUtf8(readFile(fileName));
|
||||
}
|
||||
};
|
||||
|
||||
#define GET_TEST_FILE(file) TestsInternal::readFile(QFINDTESTDATA(file))
|
||||
#define GET_TEST_FILE_UTF8(file) TestsInternal::readFileUtf8(QFINDTESTDATA(file))
|
||||
|
@ -1,23 +0,0 @@
|
||||
# Copy files from source directory to destination directory, substituting any
|
||||
# variables. Create destination directory if it does not exist.
|
||||
|
||||
function(configure_files srcDir destDir)
|
||||
make_directory(${destDir})
|
||||
|
||||
file(GLOB templateFiles RELATIVE ${srcDir} ${srcDir}/*)
|
||||
foreach(templateFile ${templateFiles})
|
||||
set(srcTemplatePath ${srcDir}/${templateFile})
|
||||
if(NOT IS_DIRECTORY ${srcTemplatePath})
|
||||
configure_file(
|
||||
${srcTemplatePath}
|
||||
${destDir}/${templateFile}
|
||||
@ONLY
|
||||
NEWLINE_STYLE LF
|
||||
)
|
||||
else()
|
||||
configure_files("${srcTemplatePath}" "${destDir}/${templateFile}")
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
configure_files(${SOURCE} ${DESTINATION})
|
@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<assemblyIdentity name="Launcher.Test.0" type="win32" version="5.0.0.0" />
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<description>Custom Minecraft launcher for managing multiple installs.</description>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!--The ID below indicates app support for Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
<!--The ID below indicates app support for Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<!--The ID below indicates app support for Windows Developer Preview / Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
@ -1,28 +0,0 @@
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
1 RT_MANIFEST "test.manifest"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,0
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "000004b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "MultiMC & PolyMC Contributors"
|
||||
VALUE "FileDescription", "Testcase"
|
||||
VALUE "FileVersion", "1.0.0.0"
|
||||
VALUE "ProductName", "Launcher Testcase"
|
||||
VALUE "ProductVersion", "5"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0000, 0x04b0 // Unicode
|
||||
END
|
||||
END
|
@ -1,881 +0,0 @@
|
||||
# - Use Module for Java
|
||||
# This file provides functions for Java. It is assumed that FindJava.cmake
|
||||
# has already been loaded. See FindJava.cmake for information on how to
|
||||
# load Java into your CMake project.
|
||||
#
|
||||
# add_jar(TARGET_NAME SRC1 SRC2 .. SRCN RCS1 RCS2 .. RCSN)
|
||||
#
|
||||
# This command creates a <TARGET_NAME>.jar. It compiles the given source
|
||||
# files (SRC) and adds the given resource files (RCS) to the jar file.
|
||||
# If only resource files are given then just a jar file is created.
|
||||
#
|
||||
# Additional instructions:
|
||||
# To add compile flags to the target you can set these flags with
|
||||
# the following variable:
|
||||
#
|
||||
# set(CMAKE_JAVA_COMPILE_FLAGS -nowarn)
|
||||
#
|
||||
# To add a path or a jar file to the class path you can do this
|
||||
# with the CMAKE_JAVA_INCLUDE_PATH variable.
|
||||
#
|
||||
# set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar)
|
||||
#
|
||||
# To use a different output name for the target you can set it with:
|
||||
#
|
||||
# set(CMAKE_JAVA_TARGET_OUTPUT_NAME shibboleet.jar)
|
||||
# add_jar(foobar foobar.java)
|
||||
#
|
||||
# To use a different output directory than CMAKE_CURRENT_BINARY_DIR
|
||||
# you can set it with:
|
||||
#
|
||||
# set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin)
|
||||
#
|
||||
# To define an entry point in your jar you can set it with:
|
||||
#
|
||||
# set(CMAKE_JAVA_JAR_ENTRY_POINT com/examples/MyProject/Main)
|
||||
#
|
||||
# To add a VERSION to the target output name you can set it using
|
||||
# CMAKE_JAVA_TARGET_VERSION. This will create a jar file with the name
|
||||
# shibboleet-1.0.0.jar and will create a symlink shibboleet.jar
|
||||
# pointing to the jar with the version information.
|
||||
#
|
||||
# set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
|
||||
# add_jar(shibboleet shibbotleet.java)
|
||||
#
|
||||
# If the target is a JNI library, utilize the following commands to
|
||||
# create a JNI symbolic link:
|
||||
#
|
||||
# set(CMAKE_JNI_TARGET TRUE)
|
||||
# set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
|
||||
# add_jar(shibboleet shibbotleet.java)
|
||||
# install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet)
|
||||
# install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR})
|
||||
#
|
||||
# If a single target needs to produce more than one jar from its
|
||||
# java source code, to prevent the accumulation of duplicate class
|
||||
# files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior
|
||||
# to calling the add_jar() function:
|
||||
#
|
||||
# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo)
|
||||
# add_jar(foo foo.java)
|
||||
#
|
||||
# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar)
|
||||
# add_jar(bar bar.java)
|
||||
#
|
||||
# Target Properties:
|
||||
# The add_jar() functions sets some target properties. You can get these
|
||||
# properties with the
|
||||
# get_property(TARGET <target_name> PROPERTY <propery_name>)
|
||||
# command.
|
||||
#
|
||||
# INSTALL_FILES The files which should be installed. This is used by
|
||||
# install_jar().
|
||||
# JNI_SYMLINK The JNI symlink which should be installed.
|
||||
# This is used by install_jni_symlink().
|
||||
# JAR_FILE The location of the jar file so that you can include
|
||||
# it.
|
||||
# CLASS_DIR The directory where the class files can be found. For
|
||||
# example to use them with javah.
|
||||
#
|
||||
# find_jar(<VAR>
|
||||
# name | NAMES name1 [name2 ...]
|
||||
# [PATHS path1 [path2 ... ENV var]]
|
||||
# [VERSIONS version1 [version2]]
|
||||
# [DOC "cache documentation string"]
|
||||
# )
|
||||
#
|
||||
# This command is used to find a full path to the named jar. A cache
|
||||
# entry named by <VAR> is created to stor the result of this command. If
|
||||
# the full path to a jar is found the result is stored in the variable
|
||||
# and the search will not repeated unless the variable is cleared. If
|
||||
# nothing is found, the result will be <VAR>-NOTFOUND, and the search
|
||||
# will be attempted again next time find_jar is invoked with the same
|
||||
# variable.
|
||||
# The name of the full path to a file that is searched for is specified
|
||||
# by the names listed after NAMES argument. Additional search locations
|
||||
# can be specified after the PATHS argument. If you require special a
|
||||
# version of a jar file you can specify it with the VERSIONS argument.
|
||||
# The argument after DOC will be used for the documentation string in
|
||||
# the cache.
|
||||
#
|
||||
# install_jar(TARGET_NAME DESTINATION)
|
||||
#
|
||||
# This command installs the TARGET_NAME files to the given DESTINATION.
|
||||
# It should be called in the same scope as add_jar() or it will fail.
|
||||
#
|
||||
# install_jni_symlink(TARGET_NAME DESTINATION)
|
||||
#
|
||||
# This command installs the TARGET_NAME JNI symlinks to the given
|
||||
# DESTINATION. It should be called in the same scope as add_jar()
|
||||
# or it will fail.
|
||||
#
|
||||
# create_javadoc(<VAR>
|
||||
# PACKAGES pkg1 [pkg2 ...]
|
||||
# [SOURCEPATH <sourcepath>]
|
||||
# [CLASSPATH <classpath>]
|
||||
# [INSTALLPATH <install path>]
|
||||
# [DOCTITLE "the documentation title"]
|
||||
# [WINDOWTITLE "the title of the document"]
|
||||
# [AUTHOR TRUE|FALSE]
|
||||
# [USE TRUE|FALSE]
|
||||
# [VERSION TRUE|FALSE]
|
||||
# )
|
||||
#
|
||||
# Create java documentation based on files or packages. For more
|
||||
# details please read the javadoc manpage.
|
||||
#
|
||||
# There are two main signatures for create_javadoc. The first
|
||||
# signature works with package names on a path with source files:
|
||||
#
|
||||
# Example:
|
||||
# create_javadoc(my_example_doc
|
||||
# PACKAGES com.exmaple.foo com.example.bar
|
||||
# SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
|
||||
# WINDOWTITLE "My example"
|
||||
# DOCTITLE "<h1>My example</h1>"
|
||||
# AUTHOR TRUE
|
||||
# USE TRUE
|
||||
# VERSION TRUE
|
||||
# )
|
||||
#
|
||||
# The second signature for create_javadoc works on a given list of
|
||||
# files.
|
||||
#
|
||||
# create_javadoc(<VAR>
|
||||
# FILES file1 [file2 ...]
|
||||
# [CLASSPATH <classpath>]
|
||||
# [INSTALLPATH <install path>]
|
||||
# [DOCTITLE "the documentation title"]
|
||||
# [WINDOWTITLE "the title of the document"]
|
||||
# [AUTHOR TRUE|FALSE]
|
||||
# [USE TRUE|FALSE]
|
||||
# [VERSION TRUE|FALSE]
|
||||
# )
|
||||
#
|
||||
# Example:
|
||||
# create_javadoc(my_example_doc
|
||||
# FILES ${example_SRCS}
|
||||
# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
|
||||
# WINDOWTITLE "My example"
|
||||
# DOCTITLE "<h1>My example</h1>"
|
||||
# AUTHOR TRUE
|
||||
# USE TRUE
|
||||
# VERSION TRUE
|
||||
# )
|
||||
#
|
||||
# Both signatures share most of the options. These options are the
|
||||
# same as what you can find in the javadoc manpage. Please look at
|
||||
# the manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and
|
||||
# VERSION.
|
||||
#
|
||||
# The documentation will be by default installed to
|
||||
#
|
||||
# ${CMAKE_INSTALL_PREFIX}/share/javadoc/<VAR>
|
||||
#
|
||||
# if you don't set the INSTALLPATH.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
|
||||
# Copyright 2010 Ben Boeckel <ben.boeckel@kitware.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
function (__java_copy_file src dest comment)
|
||||
add_custom_command(
|
||||
OUTPUT ${dest}
|
||||
COMMAND cmake -E copy_if_different
|
||||
ARGS ${src}
|
||||
${dest}
|
||||
DEPENDS ${src}
|
||||
COMMENT ${comment})
|
||||
endfunction (__java_copy_file src dest comment)
|
||||
|
||||
# define helper scripts
|
||||
set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake)
|
||||
set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake)
|
||||
|
||||
function(add_jar _TARGET_NAME)
|
||||
set(_JAVA_SOURCE_FILES ${ARGN})
|
||||
|
||||
if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
|
||||
set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif(NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
|
||||
|
||||
if (CMAKE_JAVA_JAR_ENTRY_POINT)
|
||||
set(_ENTRY_POINT_OPTION e)
|
||||
set(_ENTRY_POINT_VALUE ${CMAKE_JAVA_JAR_ENTRY_POINT})
|
||||
endif (CMAKE_JAVA_JAR_ENTRY_POINT)
|
||||
|
||||
if (LIBRARY_OUTPUT_PATH)
|
||||
set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH})
|
||||
else (LIBRARY_OUTPUT_PATH)
|
||||
set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR})
|
||||
endif (LIBRARY_OUTPUT_PATH)
|
||||
|
||||
set(CMAKE_JAVA_INCLUDE_PATH
|
||||
${CMAKE_JAVA_INCLUDE_PATH}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_JAVA_OBJECT_OUTPUT_PATH}
|
||||
${CMAKE_JAVA_LIBRARY_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
if (WIN32 AND NOT CYGWIN AND NOT CMAKE_CROSSCOMPILING)
|
||||
set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";")
|
||||
else ()
|
||||
set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":")
|
||||
endif()
|
||||
|
||||
foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH})
|
||||
set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}")
|
||||
endforeach(JAVA_INCLUDE_DIR)
|
||||
|
||||
set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir")
|
||||
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar")
|
||||
if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION)
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
|
||||
set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
|
||||
elseif (CMAKE_JAVA_TARGET_VERSION)
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
|
||||
set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar")
|
||||
elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME)
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
|
||||
endif (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION)
|
||||
# reset
|
||||
set(CMAKE_JAVA_TARGET_OUTPUT_NAME)
|
||||
|
||||
set(_JAVA_CLASS_FILES)
|
||||
set(_JAVA_COMPILE_FILES)
|
||||
set(_JAVA_DEPENDS)
|
||||
set(_JAVA_RESOURCE_FILES)
|
||||
foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES})
|
||||
get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT)
|
||||
get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE)
|
||||
get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH)
|
||||
get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE)
|
||||
|
||||
file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR} ${_JAVA_FULL})
|
||||
file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL})
|
||||
string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN)
|
||||
string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN)
|
||||
if (${_BIN_LEN} LESS ${_SRC_LEN})
|
||||
set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH})
|
||||
else (${_BIN_LEN} LESS ${_SRC_LEN})
|
||||
set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH})
|
||||
endif (${_BIN_LEN} LESS ${_SRC_LEN})
|
||||
get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH)
|
||||
|
||||
if (_JAVA_EXT MATCHES ".java")
|
||||
list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE})
|
||||
set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class")
|
||||
set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE})
|
||||
|
||||
elseif (_JAVA_EXT MATCHES ".jar"
|
||||
OR _JAVA_EXT MATCHES ".war"
|
||||
OR _JAVA_EXT MATCHES ".ear"
|
||||
OR _JAVA_EXT MATCHES ".sar")
|
||||
list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_SOURCE_FILE})
|
||||
|
||||
elseif (_JAVA_EXT STREQUAL "")
|
||||
list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH})
|
||||
list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}})
|
||||
|
||||
else (_JAVA_EXT MATCHES ".java")
|
||||
__java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE}
|
||||
${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE}
|
||||
"Copying ${_JAVA_SOURCE_FILE} to the build directory")
|
||||
list(APPEND _JAVA_RESOURCE_FILES ${_JAVA_SOURCE_FILE})
|
||||
endif (_JAVA_EXT MATCHES ".java")
|
||||
endforeach(_JAVA_SOURCE_FILE)
|
||||
|
||||
# create an empty java_class_filelist
|
||||
if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist)
|
||||
file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "")
|
||||
endif()
|
||||
|
||||
if (_JAVA_COMPILE_FILES)
|
||||
# Compile the java files and create a list of class files
|
||||
add_custom_command(
|
||||
# NOTE: this command generates an artificial dependency file
|
||||
OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
|
||||
COMMAND ${Java_JAVAC_EXECUTABLE}
|
||||
${CMAKE_JAVA_COMPILE_FLAGS}
|
||||
-classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}"
|
||||
-d ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
${_JAVA_COMPILE_FILES}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
|
||||
DEPENDS ${_JAVA_COMPILE_FILES}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Building Java objects for ${_TARGET_NAME}.jar"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
-DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}"
|
||||
-P ${_JAVA_CLASS_FILELIST_SCRIPT}
|
||||
DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif (_JAVA_COMPILE_FILES)
|
||||
|
||||
# create the jar file
|
||||
set(_JAVA_JAR_OUTPUT_PATH
|
||||
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME})
|
||||
if (CMAKE_JNI_TARGET)
|
||||
add_custom_command(
|
||||
OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
|
||||
COMMAND ${Java_JAR_EXECUTABLE}
|
||||
-cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
|
||||
${_JAVA_RESOURCE_FILES} @java_class_filelist
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
|
||||
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
|
||||
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
|
||||
-P ${_JAVA_SYMLINK_SCRIPT}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
|
||||
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH}
|
||||
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
|
||||
-P ${_JAVA_SYMLINK_SCRIPT}
|
||||
DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
|
||||
WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
|
||||
)
|
||||
else ()
|
||||
add_custom_command(
|
||||
OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
|
||||
COMMAND ${Java_JAR_EXECUTABLE}
|
||||
-cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
|
||||
${_JAVA_RESOURCE_FILES} @java_class_filelist
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
|
||||
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
|
||||
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
|
||||
-P ${_JAVA_SYMLINK_SCRIPT}
|
||||
WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
|
||||
COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
|
||||
)
|
||||
endif (CMAKE_JNI_TARGET)
|
||||
|
||||
# Add the target and make sure we have the latest resource files.
|
||||
add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH})
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
INSTALL_FILES
|
||||
${_JAVA_JAR_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
if (_JAVA_TARGET_OUTPUT_LINK)
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
INSTALL_FILES
|
||||
${_JAVA_JAR_OUTPUT_PATH}
|
||||
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
|
||||
)
|
||||
|
||||
if (CMAKE_JNI_TARGET)
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
JNI_SYMLINK
|
||||
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
|
||||
)
|
||||
endif (CMAKE_JNI_TARGET)
|
||||
endif (_JAVA_TARGET_OUTPUT_LINK)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
JAR_FILE
|
||||
${_JAVA_JAR_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
CLASSDIR
|
||||
${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
endfunction(add_jar)
|
||||
|
||||
function(INSTALL_JAR _TARGET_NAME _DESTINATION)
|
||||
get_property(__FILES
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
INSTALL_FILES
|
||||
)
|
||||
|
||||
if (__FILES)
|
||||
install(
|
||||
FILES
|
||||
${__FILES}
|
||||
DESTINATION
|
||||
${_DESTINATION}
|
||||
)
|
||||
else (__FILES)
|
||||
message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
|
||||
endif (__FILES)
|
||||
endfunction(INSTALL_JAR _TARGET_NAME _DESTINATION)
|
||||
|
||||
function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
|
||||
get_property(__SYMLINK
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
JNI_SYMLINK
|
||||
)
|
||||
|
||||
if (__SYMLINK)
|
||||
install(
|
||||
FILES
|
||||
${__SYMLINK}
|
||||
DESTINATION
|
||||
${_DESTINATION}
|
||||
)
|
||||
else (__SYMLINK)
|
||||
message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
|
||||
endif (__SYMLINK)
|
||||
endfunction(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
|
||||
|
||||
function (find_jar VARIABLE)
|
||||
set(_jar_names)
|
||||
set(_jar_files)
|
||||
set(_jar_versions)
|
||||
set(_jar_paths
|
||||
/usr/share/java/
|
||||
/usr/local/share/java/
|
||||
${Java_JAR_PATHS})
|
||||
set(_jar_doc "NOTSET")
|
||||
|
||||
set(_state "name")
|
||||
|
||||
foreach (arg ${ARGN})
|
||||
if (${_state} STREQUAL "name")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "NAMES")
|
||||
set(_jar_names ${arg})
|
||||
if (_jar_doc STREQUAL "NOTSET")
|
||||
set(_jar_doc "Finding ${arg} jar")
|
||||
endif (_jar_doc STREQUAL "NOTSET")
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
elseif (${_state} STREQUAL "versions")
|
||||
if (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "NAMES")
|
||||
set(_jar_versions ${_jar_versions} ${arg})
|
||||
endif (${arg} STREQUAL "NAMES")
|
||||
elseif (${_state} STREQUAL "names")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "VERSIONS")
|
||||
set(_jar_names ${_jar_names} ${arg})
|
||||
if (_jar_doc STREQUAL "NOTSET")
|
||||
set(_jar_doc "Finding ${arg} jar")
|
||||
endif (_jar_doc STREQUAL "NOTSET")
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
elseif (${_state} STREQUAL "paths")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "VERSIONS")
|
||||
set(_jar_paths ${_jar_paths} ${arg})
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
elseif (${_state} STREQUAL "doc")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
else (${arg} STREQUAL "VERSIONS")
|
||||
set(_jar_doc ${arg})
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
endif (${_state} STREQUAL "name")
|
||||
endforeach (arg ${ARGN})
|
||||
|
||||
if (NOT _jar_names)
|
||||
message(FATAL_ERROR "find_jar: No name to search for given")
|
||||
endif (NOT _jar_names)
|
||||
|
||||
foreach (jar_name ${_jar_names})
|
||||
foreach (version ${_jar_versions})
|
||||
set(_jar_files ${_jar_files} ${jar_name}-${version}.jar)
|
||||
endforeach (version ${_jar_versions})
|
||||
set(_jar_files ${_jar_files} ${jar_name}.jar)
|
||||
endforeach (jar_name ${_jar_names})
|
||||
|
||||
find_file(${VARIABLE}
|
||||
NAMES ${_jar_files}
|
||||
PATHS ${_jar_paths}
|
||||
DOC ${_jar_doc}
|
||||
NO_DEFAULT_PATH)
|
||||
endfunction (find_jar VARIABLE)
|
||||
|
||||
function(create_javadoc _target)
|
||||
set(_javadoc_packages)
|
||||
set(_javadoc_files)
|
||||
set(_javadoc_sourcepath)
|
||||
set(_javadoc_classpath)
|
||||
set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc")
|
||||
set(_javadoc_doctitle)
|
||||
set(_javadoc_windowtitle)
|
||||
set(_javadoc_author FALSE)
|
||||
set(_javadoc_version FALSE)
|
||||
set(_javadoc_use FALSE)
|
||||
|
||||
set(_state "package")
|
||||
|
||||
foreach (arg ${ARGN})
|
||||
if (${_state} STREQUAL "package")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_packages ${arg})
|
||||
set(_state "packages")
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "packages")
|
||||
if (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_packages ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "files")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_files ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "sourcepath")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_sourcepath ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "classpath")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_classpath ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "installpath")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_installpath ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "doctitle")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_doctitle ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "windowtitle")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_windowtitle ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "author")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_author ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "use")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_use ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "version")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_version ${arg})
|
||||
endif ()
|
||||
endif (${_state} STREQUAL "package")
|
||||
endforeach (arg ${ARGN})
|
||||
|
||||
set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target})
|
||||
set(_javadoc_options -d ${_javadoc_builddir})
|
||||
|
||||
if (_javadoc_sourcepath)
|
||||
set(_start TRUE)
|
||||
foreach(_path ${_javadoc_sourcepath})
|
||||
if (_start)
|
||||
set(_sourcepath ${_path})
|
||||
set(_start FALSE)
|
||||
else (_start)
|
||||
set(_sourcepath ${_sourcepath}:${_path})
|
||||
endif (_start)
|
||||
endforeach(_path ${_javadoc_sourcepath})
|
||||
set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath})
|
||||
endif (_javadoc_sourcepath)
|
||||
|
||||
if (_javadoc_classpath)
|
||||
set(_start TRUE)
|
||||
foreach(_path ${_javadoc_classpath})
|
||||
if (_start)
|
||||
set(_classpath ${_path})
|
||||
set(_start FALSE)
|
||||
else (_start)
|
||||
set(_classpath ${_classpath}:${_path})
|
||||
endif (_start)
|
||||
endforeach(_path ${_javadoc_classpath})
|
||||
set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}")
|
||||
endif (_javadoc_classpath)
|
||||
|
||||
if (_javadoc_doctitle)
|
||||
set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}')
|
||||
endif (_javadoc_doctitle)
|
||||
|
||||
if (_javadoc_windowtitle)
|
||||
set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}')
|
||||
endif (_javadoc_windowtitle)
|
||||
|
||||
if (_javadoc_author)
|
||||
set(_javadoc_options ${_javadoc_options} -author)
|
||||
endif (_javadoc_author)
|
||||
|
||||
if (_javadoc_use)
|
||||
set(_javadoc_options ${_javadoc_options} -use)
|
||||
endif (_javadoc_use)
|
||||
|
||||
if (_javadoc_version)
|
||||
set(_javadoc_options ${_javadoc_options} -version)
|
||||
endif (_javadoc_version)
|
||||
|
||||
add_custom_target(${_target}_javadoc ALL
|
||||
COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options}
|
||||
${_javadoc_files}
|
||||
${_javadoc_packages}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY ${_javadoc_builddir}
|
||||
DESTINATION ${_javadoc_installpath}
|
||||
)
|
||||
endfunction(create_javadoc)
|
@ -1,52 +0,0 @@
|
||||
#
|
||||
# This script create a list of compiled Java class files to be added to a
|
||||
# jar file. This avoids including cmake files which get created in the
|
||||
# binary directory.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
if (CMAKE_JAVA_CLASS_OUTPUT_PATH)
|
||||
if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
|
||||
|
||||
set(_JAVA_GLOBBED_FILES)
|
||||
if (CMAKE_JAR_CLASSES_PREFIX)
|
||||
foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
|
||||
message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}")
|
||||
|
||||
file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class")
|
||||
if (_JAVA_GLOBBED_TMP_FILES)
|
||||
list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES})
|
||||
endif (_JAVA_GLOBBED_TMP_FILES)
|
||||
endforeach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
|
||||
else()
|
||||
file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class")
|
||||
endif (CMAKE_JAR_CLASSES_PREFIX)
|
||||
|
||||
set(_JAVA_CLASS_FILES)
|
||||
# file(GLOB_RECURSE foo RELATIVE) is broken so we need this.
|
||||
foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
|
||||
file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE})
|
||||
set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n)
|
||||
endforeach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
|
||||
|
||||
# write to file
|
||||
file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES})
|
||||
|
||||
else (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
|
||||
message(SEND_ERROR "FATAL: Java class output path doesn't exist")
|
||||
endif (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
|
||||
else (CMAKE_JAVA_CLASS_OUTPUT_PATH)
|
||||
message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH")
|
||||
endif (CMAKE_JAVA_CLASS_OUTPUT_PATH)
|
@ -1,32 +0,0 @@
|
||||
#
|
||||
# Helper script for UseJava.cmake
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
if (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
|
||||
if (_JAVA_TARGET_OUTPUT_NAME)
|
||||
find_program(LN_EXECUTABLE
|
||||
NAMES
|
||||
ln
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}"
|
||||
WORKING_DIRECTORY ${_JAVA_TARGET_DIR}
|
||||
)
|
||||
else (_JAVA_TARGET_OUTPUT_NAME)
|
||||
message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME")
|
||||
endif (_JAVA_TARGET_OUTPUT_NAME)
|
||||
endif (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
|
@ -1 +1 @@
|
||||
(import packages/nix/flake-compat.nix).defaultNix
|
||||
(import nix/flake-compat.nix).defaultNix
|
||||
|
56
flake.lock
generated
56
flake.lock
generated
@ -3,11 +3,11 @@
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1648199409,
|
||||
"narHash": "sha256-JwPKdC2PoVBkG6E+eWw3j6BMR6sL3COpYWfif7RVb8Y=",
|
||||
"lastModified": 1650374568,
|
||||
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "64a525ee38886ab9028e6f61790de0832aa3ef03",
|
||||
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -19,26 +19,26 @@
|
||||
"libnbtplusplus": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1591558203,
|
||||
"narHash": "sha256-QgvNvaoFflCXEPCCFBCeZvYTpuiwScBG7EosUgFwFNQ=",
|
||||
"owner": "multimc",
|
||||
"lastModified": 1650031308,
|
||||
"narHash": "sha256-TvVOjkUobYJD9itQYueELJX3wmecvEdCbJ0FinW2mL4=",
|
||||
"owner": "PrismLauncher",
|
||||
"repo": "libnbtplusplus",
|
||||
"rev": "dc72a20b7efd304d12af2025223fad07b4b78464",
|
||||
"rev": "2203af7eeb48c45398139b583615134efd8d407f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "multimc",
|
||||
"owner": "PrismLauncher",
|
||||
"repo": "libnbtplusplus",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1648219316,
|
||||
"narHash": "sha256-Ctij+dOi0ZZIfX5eMhgwugfvB+WZSrvVNAyAuANOsnQ=",
|
||||
"lastModified": 1666057921,
|
||||
"narHash": "sha256-VpQqtXdj6G7cH//SvoprjR7XT3KS7p+tCVebGK1N6tE=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "30d3d79b7d3607d56546dd2a6b49e156ba0ec634",
|
||||
"rev": "88eab1e431cabd0ed621428d8b40d425a07af39f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -48,28 +48,28 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"quazip": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1643049383,
|
||||
"narHash": "sha256-LcJY6yd6GyeL7X5MP4L94diceM1TYespWByliBsjK98=",
|
||||
"owner": "stachenov",
|
||||
"repo": "quazip",
|
||||
"rev": "09ec1d10c6d627f895109b21728dda000cbfa7d1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "stachenov",
|
||||
"repo": "quazip",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"libnbtplusplus": "libnbtplusplus",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"quazip": "quazip"
|
||||
"tomlplusplus": "tomlplusplus"
|
||||
}
|
||||
},
|
||||
"tomlplusplus": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1666091090,
|
||||
"narHash": "sha256-djpMCFPvkJcfynV8WnsYdtwLq+J7jpV1iM4C6TojiyM=",
|
||||
"owner": "marzer",
|
||||
"repo": "tomlplusplus",
|
||||
"rev": "1e4a3833d013aee08f58c5b31c69f709afc69f73",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "marzer",
|
||||
"repo": "tomlplusplus",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
28
flake.nix
28
flake.nix
@ -4,31 +4,35 @@
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||
flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
||||
libnbtplusplus = { url = "github:multimc/libnbtplusplus"; flake = false; };
|
||||
quazip = { url = "github:stachenov/quazip"; flake = false; };
|
||||
libnbtplusplus = { url = "github:PrismLauncher/libnbtplusplus"; flake = false; };
|
||||
tomlplusplus = { url = "github:marzer/tomlplusplus"; flake = false; };
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, libnbtplusplus, quazip, ... }:
|
||||
outputs = { self, nixpkgs, libnbtplusplus, tomlplusplus, ... }:
|
||||
let
|
||||
# Generate a user-friendly version number.
|
||||
# User-friendly version number.
|
||||
version = builtins.substring 0 8 self.lastModifiedDate;
|
||||
|
||||
# System types to support (qtbase is currently broken for "aarch64-darwin")
|
||||
# Supported systems (qtbase is currently broken for "aarch64-darwin")
|
||||
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" ];
|
||||
|
||||
# Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'.
|
||||
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||
|
||||
# Nixpkgs instantiated for supported system types.
|
||||
# Nixpkgs instantiated for supported systems.
|
||||
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
||||
|
||||
packagesFn = pkgs: rec {
|
||||
prismlauncher = pkgs.libsForQt5.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
|
||||
prismlauncher-qt6 = pkgs.qt6Packages.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
|
||||
};
|
||||
in
|
||||
{
|
||||
packages = forAllSystems (system: { polymc = pkgs.${system}.libsForQt5.callPackage ./packages/nix/polymc { inherit version self quazip libnbtplusplus; }; });
|
||||
defaultPackage = forAllSystems (system: self.packages.${system}.polymc);
|
||||
packages = forAllSystems (system:
|
||||
let packages = packagesFn pkgs.${system}; in
|
||||
packages // { default = packages.prismlauncher; }
|
||||
);
|
||||
|
||||
apps = forAllSystems (system: { polymc = { type = "app"; program = "${self.defaultPackage.${system}}/bin/polymc"; }; });
|
||||
defaultApp = forAllSystems (system: self.apps.${system}.polymc);
|
||||
|
||||
overlay = final: prev: { polymc = self.defaultPackage.${final.system}; };
|
||||
overlay = final: packagesFn;
|
||||
};
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -36,6 +37,7 @@
|
||||
#include "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
|
||||
#include "net/PasteUpload.h"
|
||||
#include "ui/MainWindow.h"
|
||||
#include "ui/InstanceWindow.h"
|
||||
|
||||
@ -58,9 +60,15 @@
|
||||
#include "ui/themes/BrightTheme.h"
|
||||
#include "ui/themes/CustomTheme.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "ui/WinDarkmode.h"
|
||||
#include <versionhelpers.h>
|
||||
#endif
|
||||
|
||||
#include "ui/setupwizard/SetupWizard.h"
|
||||
#include "ui/setupwizard/LanguageWizardPage.h"
|
||||
#include "ui/setupwizard/JavaWizardPage.h"
|
||||
#include "ui/setupwizard/PasteWizardPage.h"
|
||||
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
|
||||
@ -71,6 +79,7 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <QAccessible>
|
||||
#include <QCommandLineParser>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QNetworkAccessManager>
|
||||
@ -81,6 +90,7 @@
|
||||
#include <QDebug>
|
||||
#include <QStyleFactory>
|
||||
#include <QWindow>
|
||||
#include <QIcon>
|
||||
|
||||
#include "InstanceList.h"
|
||||
|
||||
@ -96,20 +106,23 @@
|
||||
#include "tools/JVisualVM.h"
|
||||
#include "tools/MCEditTool.h"
|
||||
|
||||
#include <xdgicon.h>
|
||||
#include "settings/INISettingsObject.h"
|
||||
#include "settings/Setting.h"
|
||||
|
||||
#include "translations/TranslationsModel.h"
|
||||
#include "meta/Index.h"
|
||||
|
||||
#include <Commandline.h>
|
||||
#include <FileSystem.h>
|
||||
#include <DesktopServices.h>
|
||||
#include <LocalPeer.h>
|
||||
|
||||
#include <sys.h>
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#include <dlfcn.h>
|
||||
#include "gamemode_client.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
@ -124,12 +137,6 @@
|
||||
|
||||
static const QLatin1String liveCheckFile("live.check");
|
||||
|
||||
using namespace Commandline;
|
||||
|
||||
#define MACOS_HINT "If you are on macOS Sierra, you might have to move the app to your /Applications or ~/Applications folder. "\
|
||||
"This usually fixes the problem and you can move the application elsewhere afterwards.\n"\
|
||||
"\n"
|
||||
|
||||
namespace {
|
||||
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||
{
|
||||
@ -221,91 +228,36 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
setOrganizationName(BuildConfig.LAUNCHER_NAME);
|
||||
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
|
||||
setApplicationName(BuildConfig.LAUNCHER_NAME);
|
||||
setApplicationDisplayName(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||
setApplicationDisplayName(QString("%1 %2").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString()));
|
||||
setApplicationVersion(BuildConfig.printableVersionString());
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,7,0))
|
||||
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
|
||||
#endif
|
||||
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
|
||||
startTime = QDateTime::currentDateTime();
|
||||
|
||||
// Don't quit on hiding the last window
|
||||
this->setQuitOnLastWindowClosed(false);
|
||||
|
||||
// Commandline parsing
|
||||
QHash<QString, QVariant> args;
|
||||
{
|
||||
Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||
|
||||
// --help
|
||||
parser.addSwitch("help");
|
||||
parser.addShortOpt("help", 'h');
|
||||
parser.addDocumentation("help", "Display this help and exit.");
|
||||
// --version
|
||||
parser.addSwitch("version");
|
||||
parser.addShortOpt("version", 'V');
|
||||
parser.addDocumentation("version", "Display program version and exit.");
|
||||
// --dir
|
||||
parser.addOption("dir");
|
||||
parser.addShortOpt("dir", 'd');
|
||||
parser.addDocumentation("dir", "Use the supplied folder as application root instead of the binary location (use '.' for current)");
|
||||
// --launch
|
||||
parser.addOption("launch");
|
||||
parser.addShortOpt("launch", 'l');
|
||||
parser.addDocumentation("launch", "Launch the specified instance (by instance ID)");
|
||||
// --server
|
||||
parser.addOption("server");
|
||||
parser.addShortOpt("server", 's');
|
||||
parser.addDocumentation("server", "Join the specified server on launch (only valid in combination with --launch)");
|
||||
// --profile
|
||||
parser.addOption("profile");
|
||||
parser.addShortOpt("profile", 'a');
|
||||
parser.addDocumentation("profile", "Use the account specified by its profile name (only valid in combination with --launch)");
|
||||
// --alive
|
||||
parser.addSwitch("alive");
|
||||
parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after the launcher starts");
|
||||
// --import
|
||||
parser.addOption("import");
|
||||
parser.addShortOpt("import", 'I');
|
||||
parser.addDocumentation("import", "Import instance from specified zip (local path or URL)");
|
||||
parser.addOptions({
|
||||
{{"d", "dir"}, "Use a custom path as application root (use '.' for current directory)", "directory"},
|
||||
{{"l", "launch"}, "Launch the specified instance (by instance ID)", "instance"},
|
||||
{{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
|
||||
{{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
|
||||
{"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
|
||||
{{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"}
|
||||
});
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
||||
// parse the arguments
|
||||
try
|
||||
{
|
||||
args = parser.parse(arguments());
|
||||
}
|
||||
catch (const ParsingError &e)
|
||||
{
|
||||
std::cerr << "CommandLineError: " << e.what() << std::endl;
|
||||
if(argc > 0)
|
||||
std::cerr << "Try '" << argv[0] << " -h' to get help on command line parameters."
|
||||
<< std::endl;
|
||||
m_status = Application::Failed;
|
||||
return;
|
||||
}
|
||||
parser.process(arguments());
|
||||
|
||||
// display help and exit
|
||||
if (args["help"].toBool())
|
||||
{
|
||||
std::cout << qPrintable(parser.compileHelp(arguments()[0]));
|
||||
m_status = Application::Succeeded;
|
||||
return;
|
||||
}
|
||||
|
||||
// display version and exit
|
||||
if (args["version"].toBool())
|
||||
{
|
||||
std::cout << "Version " << BuildConfig.printableVersionString().toStdString() << std::endl;
|
||||
std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
|
||||
m_status = Application::Succeeded;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_instanceIdToLaunch = args["launch"].toString();
|
||||
m_serverToJoin = args["server"].toString();
|
||||
m_profileToUse = args["profile"].toString();
|
||||
m_liveCheck = args["alive"].toBool();
|
||||
m_zipToImport = args["import"].toUrl();
|
||||
m_instanceIdToLaunch = parser.value("launch");
|
||||
m_serverToJoin = parser.value("server");
|
||||
m_profileToUse = parser.value("profile");
|
||||
m_liveCheck = parser.isSet("alive");
|
||||
m_zipToImport = parser.value("import");
|
||||
|
||||
// error if --launch is missing with --server or --profile
|
||||
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
|
||||
@ -320,7 +272,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
|
||||
{
|
||||
// Root path is used for updates and portable data
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||
QDir foo(FS::PathCombine(binPath, "..")); // typically portable-root or /usr
|
||||
m_rootPath = foo.absolutePath();
|
||||
#elif defined(Q_OS_WIN32)
|
||||
@ -331,16 +283,12 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
// on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
|
||||
FS::updateTimestamp(m_rootPath);
|
||||
#endif
|
||||
|
||||
#ifdef LAUNCHER_JARS_LOCATION
|
||||
m_jarsPath = TOSTRING(LAUNCHER_JARS_LOCATION);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString adjustedBy;
|
||||
QString dataPath;
|
||||
// change folder
|
||||
QString dirParam = args["dir"].toString();
|
||||
QString dirParam = parser.value("dir");
|
||||
if (!dirParam.isEmpty())
|
||||
{
|
||||
// the dir param. it makes multimc data path point to whatever the user specified
|
||||
@ -354,6 +302,12 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
dataPath = foo.absolutePath();
|
||||
adjustedBy = "Persistent data path";
|
||||
|
||||
QDir polymcData(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "PolyMC"));
|
||||
if (polymcData.exists()) {
|
||||
dataPath = polymcData.absolutePath();
|
||||
adjustedBy = "PolyMC data path";
|
||||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
// TODO: this should be removed in a future version
|
||||
// TODO: provide a migration path similar to macOS migration
|
||||
@ -379,9 +333,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
QString(
|
||||
"The launcher data folder could not be created.\n"
|
||||
"\n"
|
||||
#if defined(Q_OS_MAC)
|
||||
MACOS_HINT
|
||||
#endif
|
||||
"Make sure you have the right permissions to the launcher data folder and any folder needed to access it.\n"
|
||||
"(%1)\n"
|
||||
"\n"
|
||||
@ -397,9 +348,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
QString(
|
||||
"The launcher data folder could not be opened.\n"
|
||||
"\n"
|
||||
#if defined(Q_OS_MAC)
|
||||
MACOS_HINT
|
||||
#endif
|
||||
"Make sure you have the right permissions to the launcher data folder.\n"
|
||||
"(%1)\n"
|
||||
"\n"
|
||||
@ -409,69 +357,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
// move user data to new location if on macOS and it still exists in Contents/MacOS
|
||||
QDir fi(applicationDirPath());
|
||||
QString originalData = fi.absolutePath();
|
||||
// if the config file exists in Contents/MacOS, then user data is still there and needs to moved
|
||||
if (QFileInfo::exists(FS::PathCombine(originalData, BuildConfig.LAUNCHER_CONFIGFILE)))
|
||||
{
|
||||
if (!QFileInfo::exists(FS::PathCombine(originalData, "dontmovemacdata")))
|
||||
{
|
||||
QMessageBox::StandardButton askMoveDialogue;
|
||||
askMoveDialogue = QMessageBox::question(
|
||||
nullptr,
|
||||
BuildConfig.LAUNCHER_DISPLAYNAME,
|
||||
"Would you like to move application data to a new data location? It will improve the launcher's performance, but if you switch to older versions it will look like instances have disappeared. If you select no, you can migrate later in settings. You should select yes unless you're commonly switching between different versions (eg. develop and stable).",
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::Yes
|
||||
);
|
||||
if (askMoveDialogue == QMessageBox::Yes)
|
||||
{
|
||||
qDebug() << "On macOS and found config file in old location, moving user data...";
|
||||
QDir dir;
|
||||
QStringList dataFiles {
|
||||
"*.log", // Launcher log files: ${Launcher_Name}-@.log
|
||||
"accounts.json",
|
||||
"accounts",
|
||||
"assets",
|
||||
"cache",
|
||||
"icons",
|
||||
"instances",
|
||||
"libraries",
|
||||
"meta",
|
||||
"metacache",
|
||||
"mods",
|
||||
BuildConfig.LAUNCHER_CONFIGFILE,
|
||||
"themes",
|
||||
"translations"
|
||||
};
|
||||
QDirIterator files(originalData, dataFiles);
|
||||
while (files.hasNext()) {
|
||||
QString filePath(files.next());
|
||||
QString fileName(files.fileName());
|
||||
if (!dir.rename(filePath, FS::PathCombine(dataPath, fileName)))
|
||||
{
|
||||
qWarning() << "Failed to move " << fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataPath = originalData;
|
||||
QDir::setCurrent(dataPath);
|
||||
QFile file(originalData + "/dontmovemacdata");
|
||||
file.open(QIODevice::WriteOnly);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataPath = originalData;
|
||||
QDir::setCurrent(dataPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Establish the mechanism for communication with an already running PolyMC that uses the same data path.
|
||||
* If there is one, tell it what the user actually wanted to do and exit.
|
||||
@ -543,9 +428,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
QString(
|
||||
"The launcher couldn't create a log file - the data folder is not writable.\n"
|
||||
"\n"
|
||||
#if defined(Q_OS_MAC)
|
||||
MACOS_HINT
|
||||
#endif
|
||||
"Make sure you have write permissions to the data folder.\n"
|
||||
"(%1)\n"
|
||||
"\n"
|
||||
@ -607,8 +489,10 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
|
||||
// Initialize application settings
|
||||
{
|
||||
m_settings.reset(new INISettingsObject(BuildConfig.LAUNCHER_CONFIGFILE, this));
|
||||
// Provide a fallback for migration from PolyMC
|
||||
m_settings.reset(new INISettingsObject({ BuildConfig.LAUNCHER_CONFIGFILE, "polymc.cfg", "multimc.cfg" }, this));
|
||||
// Updates
|
||||
// Multiple channels are separated by spaces
|
||||
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
|
||||
m_settings->registerSetting("AutoUpdate", true);
|
||||
|
||||
@ -686,16 +570,23 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
m_settings->registerSetting("JavaPath", "");
|
||||
m_settings->registerSetting("JavaTimestamp", 0);
|
||||
m_settings->registerSetting("JavaArchitecture", "");
|
||||
m_settings->registerSetting("JavaRealArchitecture", "");
|
||||
m_settings->registerSetting("JavaVersion", "");
|
||||
m_settings->registerSetting("JavaVendor", "");
|
||||
m_settings->registerSetting("LastHostname", "");
|
||||
m_settings->registerSetting("JvmArgs", "");
|
||||
m_settings->registerSetting("IgnoreJavaCompatibility", false);
|
||||
m_settings->registerSetting("IgnoreJavaWizard", false);
|
||||
|
||||
// Native library workarounds
|
||||
m_settings->registerSetting("UseNativeOpenAL", false);
|
||||
m_settings->registerSetting("UseNativeGLFW", false);
|
||||
|
||||
// Peformance related options
|
||||
m_settings->registerSetting("EnableFeralGamemode", false);
|
||||
m_settings->registerSetting("EnableMangoHud", false);
|
||||
m_settings->registerSetting("UseDiscreteGpu", false);
|
||||
|
||||
// Game time
|
||||
m_settings->registerSetting("ShowGameTime", true);
|
||||
m_settings->registerSetting("ShowGlobalGameTime", true);
|
||||
@ -704,6 +595,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
// Minecraft launch method
|
||||
m_settings->registerSetting("MCLaunchMethod", "LauncherPart");
|
||||
|
||||
// Minecraft mods
|
||||
m_settings->registerSetting("ModMetadataDisabled", false);
|
||||
|
||||
// Minecraft offline player name
|
||||
m_settings->registerSetting("LastOfflinePlayerName", "");
|
||||
|
||||
@ -735,15 +629,55 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
|
||||
m_settings->registerSetting("UpdateDialogGeometry", "");
|
||||
|
||||
// pastebin URL
|
||||
m_settings->registerSetting("PastebinURL", "https://0x0.st");
|
||||
m_settings->registerSetting("ModDownloadGeometry", "");
|
||||
|
||||
// HACK: This code feels so stupid is there a less stupid way of doing this?
|
||||
{
|
||||
m_settings->registerSetting("PastebinURL", "");
|
||||
m_settings->registerSetting("PastebinType", PasteUpload::PasteType::Mclogs);
|
||||
m_settings->registerSetting("PastebinCustomAPIBase", "");
|
||||
|
||||
QString pastebinURL = m_settings->get("PastebinURL").toString();
|
||||
|
||||
bool userHadDefaultPastebin = pastebinURL == "https://0x0.st";
|
||||
if (!pastebinURL.isEmpty() && !userHadDefaultPastebin)
|
||||
{
|
||||
m_settings->set("PastebinType", PasteUpload::PasteType::NullPointer);
|
||||
m_settings->set("PastebinCustomAPIBase", pastebinURL);
|
||||
m_settings->reset("PastebinURL");
|
||||
}
|
||||
|
||||
bool ok;
|
||||
int pasteType = m_settings->get("PastebinType").toInt(&ok);
|
||||
// If PastebinType is invalid then reset the related settings.
|
||||
if (!ok || !(PasteUpload::PasteType::First <= pasteType && pasteType <= PasteUpload::PasteType::Last))
|
||||
{
|
||||
m_settings->reset("PastebinType");
|
||||
m_settings->reset("PastebinCustomAPIBase");
|
||||
}
|
||||
}
|
||||
// meta URL
|
||||
m_settings->registerSetting("MetaURLOverride", "");
|
||||
|
||||
m_settings->registerSetting("CloseAfterLaunch", false);
|
||||
m_settings->registerSetting("QuitAfterGameStop", false);
|
||||
|
||||
// Custom MSA credentials
|
||||
// Custom Microsoft Authentication Client ID
|
||||
m_settings->registerSetting("MSAClientIDOverride", "");
|
||||
|
||||
// Custom Flame API Key
|
||||
{
|
||||
m_settings->registerSetting("CFKeyOverride", "");
|
||||
m_settings->registerSetting("FlameKeyOverride", "");
|
||||
|
||||
QString flameKey = m_settings->get("CFKeyOverride").toString();
|
||||
|
||||
if (!flameKey.isEmpty())
|
||||
m_settings->set("FlameKeyOverride", flameKey);
|
||||
m_settings->reset("CFKeyOverride");
|
||||
}
|
||||
m_settings->registerSetting("UserAgentOverride", "");
|
||||
|
||||
// Init page provider
|
||||
{
|
||||
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
|
||||
@ -791,7 +725,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
auto platform = getIdealPlatform(BuildConfig.BUILD_PLATFORM);
|
||||
auto channelUrl = BuildConfig.UPDATER_BASE + platform + "/channels.json";
|
||||
qDebug() << "Initializing updater with platform: " << platform << " -- " << channelUrl;
|
||||
m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
|
||||
m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL));
|
||||
qDebug() << "<> Updater started.";
|
||||
}
|
||||
|
||||
@ -881,6 +815,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath());
|
||||
m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath());
|
||||
m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
|
||||
m_metacache->addBase("FlameMods", QDir("cache/FlameMods").absolutePath());
|
||||
m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath());
|
||||
m_metacache->addBase("ModrinthModpacks", QDir("cache/ModrinthModpacks").absolutePath());
|
||||
m_metacache->addBase("root", QDir::currentPath());
|
||||
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
||||
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
|
||||
@ -905,6 +842,12 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
m_mcedit.reset(new MCEditTool(m_settings));
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
connect(this, &Application::clickedOnDock, [this]() {
|
||||
this->showMainWindow();
|
||||
});
|
||||
#endif
|
||||
|
||||
connect(this, &Application::aboutToQuit, [this](){
|
||||
if(m_instances)
|
||||
{
|
||||
@ -925,10 +868,13 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
qDebug() << "<> Application theme set.";
|
||||
}
|
||||
|
||||
updateCapabilities();
|
||||
|
||||
if(createSetupWizard())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
performMainStartupAction();
|
||||
}
|
||||
|
||||
@ -936,6 +882,10 @@ bool Application::createSetupWizard()
|
||||
{
|
||||
bool javaRequired = [&]()
|
||||
{
|
||||
bool ignoreJavaWizard = m_settings->get("IgnoreJavaWizard").toBool();
|
||||
if(ignoreJavaWizard) {
|
||||
return false;
|
||||
}
|
||||
QString currentHostName = QHostInfo::localHostName();
|
||||
QString oldHostName = settings()->get("LastHostname").toString();
|
||||
if (currentHostName != oldHostName)
|
||||
@ -957,7 +907,8 @@ bool Application::createSetupWizard()
|
||||
return true;
|
||||
return false;
|
||||
}();
|
||||
bool wizardRequired = javaRequired || languageRequired;
|
||||
bool pasteInterventionRequired = settings()->get("PastebinURL") != "";
|
||||
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired;
|
||||
|
||||
if(wizardRequired)
|
||||
{
|
||||
@ -966,10 +917,16 @@ bool Application::createSetupWizard()
|
||||
{
|
||||
m_setupWizard->addPage(new LanguageWizardPage(m_setupWizard));
|
||||
}
|
||||
|
||||
if (javaRequired)
|
||||
{
|
||||
m_setupWizard->addPage(new JavaWizardPage(m_setupWizard));
|
||||
}
|
||||
|
||||
if (pasteInterventionRequired)
|
||||
{
|
||||
m_setupWizard->addPage(new PasteWizardPage(m_setupWizard));
|
||||
}
|
||||
connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished);
|
||||
m_setupWizard->show();
|
||||
return true;
|
||||
@ -977,6 +934,21 @@ bool Application::createSetupWizard()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Application::event(QEvent* event) {
|
||||
#ifdef Q_OS_MACOS
|
||||
if (event->type() == QEvent::ApplicationStateChange) {
|
||||
auto ev = static_cast<QApplicationStateChangeEvent*>(event);
|
||||
|
||||
if (m_prevAppState == Qt::ApplicationActive
|
||||
&& ev->applicationState() == Qt::ApplicationActive) {
|
||||
emit clickedOnDock();
|
||||
}
|
||||
m_prevAppState = ev->applicationState();
|
||||
}
|
||||
#endif
|
||||
return QApplication::event(event);
|
||||
}
|
||||
|
||||
void Application::setupWizardFinished(int status)
|
||||
{
|
||||
qDebug() << "Wizard result =" << status;
|
||||
@ -1011,7 +983,7 @@ void Application::performMainStartupAction()
|
||||
qDebug() << " Launching with account" << m_profileToUse;
|
||||
}
|
||||
|
||||
launch(inst, true, nullptr, serverToJoin, accountToUse);
|
||||
launch(inst, true, false, nullptr, serverToJoin, accountToUse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1115,6 +1087,7 @@ void Application::messageReceived(const QByteArray& message)
|
||||
launch(
|
||||
instance,
|
||||
true,
|
||||
false,
|
||||
nullptr,
|
||||
serverObject,
|
||||
accountObject
|
||||
@ -1152,15 +1125,6 @@ std::vector<ITheme *> Application::getValidApplicationThemes()
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Application::isFlatpak()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
return QFile::exists("/.flatpak-info");
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::setApplicationTheme(const QString& name, bool initial)
|
||||
{
|
||||
auto systemPalette = qApp->palette();
|
||||
@ -1169,6 +1133,15 @@ void Application::setApplicationTheme(const QString& name, bool initial)
|
||||
{
|
||||
auto & theme = (*themeIter).second;
|
||||
theme->apply(initial);
|
||||
#ifdef Q_OS_WIN
|
||||
if (m_mainWindow && IsWindows10OrGreater()) {
|
||||
if (QString::compare(theme->id(), "dark") == 0) {
|
||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
||||
} else {
|
||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1178,15 +1151,15 @@ void Application::setApplicationTheme(const QString& name, bool initial)
|
||||
|
||||
void Application::setIconTheme(const QString& name)
|
||||
{
|
||||
XdgIcon::setThemeName(name);
|
||||
QIcon::setThemeName(name);
|
||||
}
|
||||
|
||||
QIcon Application::getThemedIcon(const QString& name)
|
||||
{
|
||||
if(name == "logo") {
|
||||
return QIcon(":/org.polymc.PolyMC.svg");
|
||||
return QIcon(":/" + BuildConfig.LAUNCHER_SVGFILENAME);
|
||||
}
|
||||
return XdgIcon::fromTheme(name);
|
||||
return QIcon::fromTheme(name);
|
||||
}
|
||||
|
||||
bool Application::openJsonEditor(const QString &filename)
|
||||
@ -1206,6 +1179,7 @@ bool Application::openJsonEditor(const QString &filename)
|
||||
bool Application::launch(
|
||||
InstancePtr instance,
|
||||
bool online,
|
||||
bool demo,
|
||||
BaseProfilerFactory *profiler,
|
||||
MinecraftServerTargetPtr serverToJoin,
|
||||
MinecraftAccountPtr accountToUse
|
||||
@ -1229,6 +1203,7 @@ bool Application::launch(
|
||||
controller.reset(new LaunchController());
|
||||
controller->setInstance(instance);
|
||||
controller->setOnline(online);
|
||||
controller->setDemo(demo);
|
||||
controller->setProfiler(profiler);
|
||||
controller->setServerToJoin(serverToJoin);
|
||||
controller->setAccountToUse(accountToUse);
|
||||
@ -1242,6 +1217,9 @@ bool Application::launch(
|
||||
}
|
||||
connect(controller.get(), &LaunchController::succeeded, this, &Application::controllerSucceeded);
|
||||
connect(controller.get(), &LaunchController::failed, this, &Application::controllerFailed);
|
||||
connect(controller.get(), &LaunchController::aborted, this, [this] {
|
||||
controllerFailed(tr("Aborted"));
|
||||
});
|
||||
addRunningInstance();
|
||||
controller->start();
|
||||
return true;
|
||||
@ -1396,6 +1374,16 @@ MainWindow* Application::showMainWindow(bool minimized)
|
||||
m_mainWindow = new MainWindow();
|
||||
m_mainWindow->restoreState(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowState").toByteArray()));
|
||||
m_mainWindow->restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowGeometry").toByteArray()));
|
||||
#ifdef Q_OS_WIN
|
||||
if (IsWindows10OrGreater())
|
||||
{
|
||||
if (QString::compare(settings()->get("ApplicationTheme").toString(), "dark") == 0) {
|
||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
||||
} else {
|
||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(minimized)
|
||||
{
|
||||
m_mainWindow->showMinimized();
|
||||
@ -1548,13 +1536,48 @@ shared_qobject_ptr<Meta::Index> Application::metadataIndex()
|
||||
return m_metadataIndex;
|
||||
}
|
||||
|
||||
QString Application::getJarsPath()
|
||||
void Application::updateCapabilities()
|
||||
{
|
||||
if(m_jarsPath.isEmpty())
|
||||
m_capabilities = None;
|
||||
if (!getMSAClientID().isEmpty())
|
||||
m_capabilities |= SupportsMSA;
|
||||
if (!getFlameAPIKey().isEmpty())
|
||||
m_capabilities |= SupportsFlame;
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
if (gamemode_query_status() >= 0)
|
||||
m_capabilities |= SupportsGameMode;
|
||||
|
||||
{
|
||||
return FS::PathCombine(QCoreApplication::applicationDirPath(), "jars");
|
||||
void *dummy = dlopen("libMangoHud_dlsym.so", RTLD_LAZY);
|
||||
// try normal variant as well
|
||||
if (dummy == NULL)
|
||||
dummy = dlopen("libMangoHud.so", RTLD_LAZY);
|
||||
|
||||
if (dummy != NULL) {
|
||||
dlclose(dummy);
|
||||
m_capabilities |= SupportsMangoHud;
|
||||
}
|
||||
}
|
||||
return FS::PathCombine(m_rootPath, m_jarsPath);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString Application::getJarPath(QString jarFile)
|
||||
{
|
||||
QStringList potentialPaths = {
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||
FS::PathCombine(m_rootPath, "share/" + BuildConfig.LAUNCHER_APP_BINARY_NAME),
|
||||
#endif
|
||||
FS::PathCombine(m_rootPath, "jars"),
|
||||
FS::PathCombine(applicationDirPath(), "jars")
|
||||
};
|
||||
for(QString p : potentialPaths)
|
||||
{
|
||||
QString jarPath = FS::PathCombine(p, jarFile);
|
||||
if (QFileInfo(jarPath).isFile())
|
||||
return jarPath;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString Application::getMSAClientID()
|
||||
@ -1566,3 +1589,34 @@ QString Application::getMSAClientID()
|
||||
|
||||
return BuildConfig.MSA_CLIENT_ID;
|
||||
}
|
||||
|
||||
QString Application::getFlameAPIKey()
|
||||
{
|
||||
QString keyOverride = m_settings->get("FlameKeyOverride").toString();
|
||||
if (!keyOverride.isEmpty()) {
|
||||
return keyOverride;
|
||||
}
|
||||
|
||||
return BuildConfig.FLAME_API_KEY;
|
||||
}
|
||||
|
||||
QString Application::getUserAgent()
|
||||
{
|
||||
QString uaOverride = m_settings->get("UserAgentOverride").toString();
|
||||
if (!uaOverride.isEmpty()) {
|
||||
return uaOverride.replace("$LAUNCHER_VER", BuildConfig.printableVersionString());
|
||||
}
|
||||
|
||||
return BuildConfig.USER_AGENT;
|
||||
}
|
||||
|
||||
QString Application::getUserAgentUncached()
|
||||
{
|
||||
QString uaOverride = m_settings->get("UserAgentOverride").toString();
|
||||
if (!uaOverride.isEmpty()) {
|
||||
uaOverride += " (Uncached)";
|
||||
return uaOverride.replace("$LAUNCHER_VER", BuildConfig.printableVersionString());
|
||||
}
|
||||
|
||||
return BuildConfig.USER_AGENT_UNCACHED;
|
||||
}
|
||||
|
@ -90,10 +90,22 @@ public:
|
||||
Initialized
|
||||
};
|
||||
|
||||
enum Capability {
|
||||
None = 0,
|
||||
|
||||
SupportsMSA = 1 << 0,
|
||||
SupportsFlame = 1 << 1,
|
||||
SupportsGameMode = 1 << 2,
|
||||
SupportsMangoHud = 1 << 3,
|
||||
};
|
||||
Q_DECLARE_FLAGS(Capabilities, Capability)
|
||||
|
||||
public:
|
||||
Application(int &argc, char **argv);
|
||||
virtual ~Application();
|
||||
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
std::shared_ptr<SettingsObject> settings() const {
|
||||
return m_settings;
|
||||
}
|
||||
@ -104,8 +116,6 @@ public:
|
||||
|
||||
QIcon getThemedIcon(const QString& name);
|
||||
|
||||
bool isFlatpak();
|
||||
|
||||
void setIconTheme(const QString& name);
|
||||
|
||||
std::vector<ITheme *> getValidApplicationThemes();
|
||||
@ -152,15 +162,28 @@ public:
|
||||
|
||||
shared_qobject_ptr<Meta::Index> metadataIndex();
|
||||
|
||||
QString getJarsPath();
|
||||
void updateCapabilities();
|
||||
|
||||
/*!
|
||||
* Finds and returns the full path to a jar file.
|
||||
* Returns a null-string if it could not be found.
|
||||
*/
|
||||
QString getJarPath(QString jarFile);
|
||||
|
||||
QString getMSAClientID();
|
||||
QString getFlameAPIKey();
|
||||
QString getUserAgent();
|
||||
QString getUserAgentUncached();
|
||||
|
||||
/// this is the root of the 'installation'. Used for automatic updates
|
||||
const QString &root() {
|
||||
return m_rootPath;
|
||||
}
|
||||
|
||||
const Capabilities capabilities() {
|
||||
return m_capabilities;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Opens a json file using either a system default editor, or, if not empty, the editor
|
||||
* specified in the settings
|
||||
@ -180,10 +203,15 @@ signals:
|
||||
void globalSettingsAboutToOpen();
|
||||
void globalSettingsClosed();
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
void clickedOnDock();
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
bool launch(
|
||||
InstancePtr instance,
|
||||
bool online = true,
|
||||
bool demo = false,
|
||||
BaseProfilerFactory *profiler = nullptr,
|
||||
MinecraftServerTargetPtr serverToJoin = nullptr,
|
||||
MinecraftAccountPtr accountToUse = nullptr
|
||||
@ -229,13 +257,17 @@ private:
|
||||
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
|
||||
std::map<QString, std::unique_ptr<ITheme>> m_themes;
|
||||
std::unique_ptr<MCEditTool> m_mcedit;
|
||||
QString m_jarsPath;
|
||||
QSet<QString> m_features;
|
||||
|
||||
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
|
||||
|
||||
QString m_rootPath;
|
||||
Status m_status = Application::StartingUp;
|
||||
Capabilities m_capabilities;
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
// used on Windows to attach the standard IO streams
|
||||
|
@ -1,11 +1,47 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ApplicationMessage.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include "Json.h"
|
||||
|
||||
void ApplicationMessage::parse(const QByteArray & input) {
|
||||
auto doc = QJsonDocument::fromBinaryData(input);
|
||||
auto root = doc.object();
|
||||
auto doc = Json::requireDocument(input, "ApplicationMessage");
|
||||
auto root = Json::requireObject(doc, "ApplicationMessage");
|
||||
|
||||
command = root.value("command").toString();
|
||||
args.clear();
|
||||
@ -25,7 +61,5 @@ QByteArray ApplicationMessage::serialize() {
|
||||
}
|
||||
root.insert("args", outArgs);
|
||||
|
||||
QJsonDocument out;
|
||||
out.setObject(root);
|
||||
return out.toBinaryData();
|
||||
return Json::toText(root);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -38,6 +39,7 @@
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "settings/INISettingsObject.h"
|
||||
#include "settings/Setting.h"
|
||||
@ -51,15 +53,26 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
||||
: QObject()
|
||||
{
|
||||
m_settings = settings;
|
||||
m_global_settings = globalSettings;
|
||||
m_rootDir = rootDir;
|
||||
|
||||
m_settings->registerSetting("name", "Unnamed Instance");
|
||||
m_settings->registerSetting("iconKey", "default");
|
||||
m_settings->registerSetting("notes", "");
|
||||
|
||||
m_settings->registerSetting("lastLaunchTime", 0);
|
||||
m_settings->registerSetting("totalTimePlayed", 0);
|
||||
m_settings->registerSetting("lastTimePlayed", 0);
|
||||
m_settings->registerSetting("InstanceType", "OneSix");
|
||||
|
||||
// Game time override
|
||||
auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
|
||||
m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride);
|
||||
m_settings->registerOverride(globalSettings->getSetting("RecordGameTime"), gameTimeOverride);
|
||||
|
||||
// NOTE: Sometimees InstanceType is already registered, as it was used to identify the type of
|
||||
// a locally stored instance
|
||||
if (!m_settings->getSetting("InstanceType"))
|
||||
m_settings->registerSetting("InstanceType", "");
|
||||
|
||||
// Custom Commands
|
||||
auto commandSetting = m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false);
|
||||
@ -76,6 +89,14 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
||||
|
||||
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleMaxLines"), nullptr);
|
||||
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleOverflowStop"), nullptr);
|
||||
|
||||
// Managed Packs
|
||||
m_settings->registerSetting("ManagedPack", false);
|
||||
m_settings->registerSetting("ManagedPackType", "");
|
||||
m_settings->registerSetting("ManagedPackID", "");
|
||||
m_settings->registerSetting("ManagedPackName", "");
|
||||
m_settings->registerSetting("ManagedPackVersionID", "");
|
||||
m_settings->registerSetting("ManagedPackVersionName", "");
|
||||
}
|
||||
|
||||
QString BaseInstance::getPreLaunchCommand()
|
||||
@ -93,9 +114,59 @@ QString BaseInstance::getPostExitCommand()
|
||||
return settings()->get("PostExitCommand").toString();
|
||||
}
|
||||
|
||||
bool BaseInstance::isManagedPack() const
|
||||
{
|
||||
return m_settings->get("ManagedPack").toBool();
|
||||
}
|
||||
|
||||
QString BaseInstance::getManagedPackType() const
|
||||
{
|
||||
return m_settings->get("ManagedPackType").toString();
|
||||
}
|
||||
|
||||
QString BaseInstance::getManagedPackID() const
|
||||
{
|
||||
return m_settings->get("ManagedPackID").toString();
|
||||
}
|
||||
|
||||
QString BaseInstance::getManagedPackName() const
|
||||
{
|
||||
return m_settings->get("ManagedPackName").toString();
|
||||
}
|
||||
|
||||
QString BaseInstance::getManagedPackVersionID() const
|
||||
{
|
||||
return m_settings->get("ManagedPackVersionID").toString();
|
||||
}
|
||||
|
||||
QString BaseInstance::getManagedPackVersionName() const
|
||||
{
|
||||
return m_settings->get("ManagedPackVersionName").toString();
|
||||
}
|
||||
|
||||
void BaseInstance::setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version)
|
||||
{
|
||||
m_settings->set("ManagedPack", true);
|
||||
m_settings->set("ManagedPackType", type);
|
||||
m_settings->set("ManagedPackID", id);
|
||||
m_settings->set("ManagedPackName", name);
|
||||
m_settings->set("ManagedPackVersionID", versionId);
|
||||
m_settings->set("ManagedPackVersionName", version);
|
||||
}
|
||||
|
||||
void BaseInstance::copyManagedPack(BaseInstance& other)
|
||||
{
|
||||
m_settings->set("ManagedPack", other.isManagedPack());
|
||||
m_settings->set("ManagedPackType", other.getManagedPackType());
|
||||
m_settings->set("ManagedPackID", other.getManagedPackID());
|
||||
m_settings->set("ManagedPackName", other.getManagedPackName());
|
||||
m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID());
|
||||
m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName());
|
||||
}
|
||||
|
||||
int BaseInstance::getConsoleMaxLines() const
|
||||
{
|
||||
auto lineSetting = settings()->getSetting("ConsoleMaxLines");
|
||||
auto lineSetting = m_settings->getSetting("ConsoleMaxLines");
|
||||
bool conversionOk = false;
|
||||
int maxLines = lineSetting->get().toInt(&conversionOk);
|
||||
if(!conversionOk)
|
||||
@ -108,7 +179,7 @@ int BaseInstance::getConsoleMaxLines() const
|
||||
|
||||
bool BaseInstance::shouldStopOnConsoleOverflow() const
|
||||
{
|
||||
return settings()->get("ConsoleOverflowStop").toBool();
|
||||
return m_settings->get("ConsoleOverflowStop").toBool();
|
||||
}
|
||||
|
||||
void BaseInstance::iconUpdated(QString key)
|
||||
@ -183,7 +254,7 @@ void BaseInstance::setRunning(bool running)
|
||||
|
||||
int64_t BaseInstance::totalTimePlayed() const
|
||||
{
|
||||
qint64 current = settings()->get("totalTimePlayed").toLongLong();
|
||||
qint64 current = m_settings->get("totalTimePlayed").toLongLong();
|
||||
if(m_isRunning)
|
||||
{
|
||||
QDateTime timeNow = QDateTime::currentDateTime();
|
||||
@ -199,7 +270,7 @@ int64_t BaseInstance::lastTimePlayed() const
|
||||
QDateTime timeNow = QDateTime::currentDateTime();
|
||||
return m_timeStarted.secsTo(timeNow);
|
||||
}
|
||||
return settings()->get("lastTimePlayed").toLongLong();
|
||||
return m_settings->get("lastTimePlayed").toLongLong();
|
||||
}
|
||||
|
||||
void BaseInstance::resetTimePlayed()
|
||||
@ -218,8 +289,10 @@ QString BaseInstance::instanceRoot() const
|
||||
return m_rootDir;
|
||||
}
|
||||
|
||||
SettingsObjectPtr BaseInstance::settings() const
|
||||
SettingsObjectPtr BaseInstance::settings()
|
||||
{
|
||||
loadSpecificSettings();
|
||||
|
||||
return m_settings;
|
||||
}
|
||||
|
||||
@ -282,11 +355,11 @@ QString BaseInstance::name() const
|
||||
|
||||
QString BaseInstance::windowTitle() const
|
||||
{
|
||||
return BuildConfig.LAUNCHER_NAME + ": " + name().replace(QRegExp("[ \n\r\t]+"), " ");
|
||||
return BuildConfig.LAUNCHER_DISPLAYNAME + ": " + name().replace(QRegularExpression("\\s+"), " ");
|
||||
}
|
||||
|
||||
// FIXME: why is this here? move it to MinecraftInstance!!!
|
||||
QStringList BaseInstance::extraArguments() const
|
||||
QStringList BaseInstance::extraArguments()
|
||||
{
|
||||
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
|
||||
}
|
||||
@ -295,3 +368,8 @@ shared_qobject_ptr<LaunchTask> BaseInstance::getLaunchTask()
|
||||
{
|
||||
return m_launchProcess;
|
||||
}
|
||||
|
||||
void BaseInstance::updateRuntimeContext()
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -53,6 +54,7 @@
|
||||
#include "net/Mode.h"
|
||||
|
||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
||||
#include "RuntimeContext.h"
|
||||
|
||||
class QDir;
|
||||
class Task;
|
||||
@ -139,13 +141,22 @@ public:
|
||||
QString getPostExitCommand();
|
||||
QString getWrapperCommand();
|
||||
|
||||
bool isManagedPack() const;
|
||||
QString getManagedPackType() const;
|
||||
QString getManagedPackID() const;
|
||||
QString getManagedPackName() const;
|
||||
QString getManagedPackVersionID() const;
|
||||
QString getManagedPackVersionName() const;
|
||||
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
|
||||
void copyManagedPack(BaseInstance& other);
|
||||
|
||||
/// guess log level from a line of game log
|
||||
virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level)
|
||||
{
|
||||
return level;
|
||||
};
|
||||
|
||||
virtual QStringList extraArguments() const;
|
||||
virtual QStringList extraArguments();
|
||||
|
||||
/// Traits. Normally inside the version, depends on instance implementation.
|
||||
virtual QSet <QString> traits() const = 0;
|
||||
@ -161,9 +172,18 @@ public:
|
||||
/*!
|
||||
* \brief Gets this instance's settings object.
|
||||
* This settings object stores instance-specific settings.
|
||||
*
|
||||
* Note that this method is not const.
|
||||
* It may call loadSpecificSettings() to ensure those are loaded.
|
||||
*
|
||||
* \return A pointer to this instance's settings object.
|
||||
*/
|
||||
virtual SettingsObjectPtr settings() const;
|
||||
virtual SettingsObjectPtr settings();
|
||||
|
||||
/*!
|
||||
* \brief Loads settings specific to an instance type if they're not already loaded.
|
||||
*/
|
||||
virtual void loadSpecificSettings() = 0;
|
||||
|
||||
/// returns a valid update task
|
||||
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
|
||||
@ -179,6 +199,7 @@ public:
|
||||
* Create envrironment variables for running the instance
|
||||
*/
|
||||
virtual QProcessEnvironment createEnvironment() = 0;
|
||||
virtual QProcessEnvironment createLaunchEnvironment() = 0;
|
||||
|
||||
/*!
|
||||
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'
|
||||
@ -196,10 +217,16 @@ public:
|
||||
virtual QString instanceConfigFolder() const = 0;
|
||||
|
||||
/// get variables this instance exports
|
||||
virtual QMap<QString, QString> getVariables() const = 0;
|
||||
virtual QMap<QString, QString> getVariables() = 0;
|
||||
|
||||
virtual QString typeName() const = 0;
|
||||
|
||||
void updateRuntimeContext();
|
||||
RuntimeContext runtimeContext() const
|
||||
{
|
||||
return m_runtimeContext;
|
||||
}
|
||||
|
||||
bool hasVersionBroken() const
|
||||
{
|
||||
return m_hasBrokenVersion;
|
||||
@ -258,6 +285,11 @@ public:
|
||||
protected:
|
||||
void changeStatus(Status newStatus);
|
||||
|
||||
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); };
|
||||
|
||||
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
||||
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
||||
|
||||
signals:
|
||||
/*!
|
||||
* \brief Signal emitted when properties relevant to the instance view change
|
||||
@ -280,12 +312,17 @@ protected: /* data */
|
||||
bool m_isRunning = false;
|
||||
shared_qobject_ptr<LaunchTask> m_launchProcess;
|
||||
QDateTime m_timeStarted;
|
||||
RuntimeContext m_runtimeContext;
|
||||
|
||||
private: /* data */
|
||||
Status m_status = Status::Present;
|
||||
bool m_crashed = false;
|
||||
bool m_hasUpdate = false;
|
||||
bool m_hasBrokenVersion = false;
|
||||
|
||||
SettingsObjectWeakPtr m_global_settings;
|
||||
bool m_specific_settings_loaded = false;
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>)
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "BaseVersionList.h"
|
||||
@ -51,7 +71,7 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const
|
||||
switch (role)
|
||||
{
|
||||
case VersionPointerRole:
|
||||
return qVariantFromValue(version);
|
||||
return QVariant::fromValue(version);
|
||||
|
||||
case VersionRole:
|
||||
return version->name();
|
||||
|
@ -4,8 +4,6 @@ project(application)
|
||||
|
||||
######## Sources and headers ########
|
||||
|
||||
include (UnitTest)
|
||||
|
||||
set(CORE_SOURCES
|
||||
# LOGIC - Base classes and infrastructure
|
||||
BaseInstaller.h
|
||||
@ -28,6 +26,7 @@ set(CORE_SOURCES
|
||||
MMCZip.cpp
|
||||
MMCStrings.h
|
||||
MMCStrings.cpp
|
||||
RuntimeContext.h
|
||||
|
||||
# Basic instance manipulation tasks (derived from InstanceTask)
|
||||
InstanceCreationTask.h
|
||||
@ -90,17 +89,6 @@ set(CORE_SOURCES
|
||||
MMCTime.cpp
|
||||
)
|
||||
|
||||
add_unit_test(FileSystem
|
||||
SOURCES FileSystem_test.cpp
|
||||
LIBS Launcher_logic
|
||||
DATA testdata
|
||||
)
|
||||
|
||||
add_unit_test(GZip
|
||||
SOURCES GZip_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
set(PATHMATCHER_SOURCES
|
||||
# Path matchers
|
||||
pathmatcher/FSTreeMatcher.h
|
||||
@ -124,10 +112,13 @@ set(NET_SOURCES
|
||||
net/NetAction.h
|
||||
net/NetJob.cpp
|
||||
net/NetJob.h
|
||||
net/NetUtils.h
|
||||
net/PasteUpload.cpp
|
||||
net/PasteUpload.h
|
||||
net/Sink.h
|
||||
net/Validator.h
|
||||
net/Upload.cpp
|
||||
net/Upload.h
|
||||
)
|
||||
|
||||
# Game launch logic
|
||||
@ -162,19 +153,13 @@ set(UPDATE_SOURCES
|
||||
updater/UpdateChecker.cpp
|
||||
updater/DownloadTask.h
|
||||
updater/DownloadTask.cpp
|
||||
updater/ExternalUpdater.h
|
||||
)
|
||||
|
||||
add_unit_test(UpdateChecker
|
||||
SOURCES updater/UpdateChecker_test.cpp
|
||||
LIBS Launcher_logic
|
||||
DATA updater/testdata
|
||||
)
|
||||
|
||||
add_unit_test(DownloadTask
|
||||
SOURCES updater/DownloadTask_test.cpp
|
||||
LIBS Launcher_logic
|
||||
DATA updater/testdata
|
||||
)
|
||||
set(MAC_UPDATE_SOURCES
|
||||
updater/MacSparkleUpdater.h
|
||||
updater/MacSparkleUpdater.mm
|
||||
)
|
||||
|
||||
# Backend for the news bar... there's usually no news.
|
||||
set(NEWS_SOURCES
|
||||
@ -235,6 +220,8 @@ set(MINECRAFT_SOURCES
|
||||
minecraft/auth/steps/MigrationEligibilityStep.h
|
||||
minecraft/auth/steps/MinecraftProfileStep.cpp
|
||||
minecraft/auth/steps/MinecraftProfileStep.h
|
||||
minecraft/auth/steps/MinecraftProfileStepMojang.cpp
|
||||
minecraft/auth/steps/MinecraftProfileStepMojang.h
|
||||
minecraft/auth/steps/MSAStep.cpp
|
||||
minecraft/auth/steps/MSAStep.h
|
||||
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
||||
@ -302,8 +289,6 @@ set(MINECRAFT_SOURCES
|
||||
minecraft/Rule.h
|
||||
minecraft/OneSixVersionFormat.cpp
|
||||
minecraft/OneSixVersionFormat.h
|
||||
minecraft/OpSys.cpp
|
||||
minecraft/OpSys.h
|
||||
minecraft/ParseUtils.cpp
|
||||
minecraft/ParseUtils.h
|
||||
minecraft/ProfileUtils.cpp
|
||||
@ -311,6 +296,8 @@ set(MINECRAFT_SOURCES
|
||||
minecraft/Library.cpp
|
||||
minecraft/Library.h
|
||||
minecraft/MojangDownloadInfo.h
|
||||
minecraft/VanillaInstanceCreationTask.cpp
|
||||
minecraft/VanillaInstanceCreationTask.h
|
||||
minecraft/VersionFile.cpp
|
||||
minecraft/VersionFile.h
|
||||
minecraft/VersionFilterData.h
|
||||
@ -320,19 +307,36 @@ set(MINECRAFT_SOURCES
|
||||
minecraft/WorldList.h
|
||||
minecraft/WorldList.cpp
|
||||
|
||||
minecraft/mod/MetadataHandler.h
|
||||
minecraft/mod/Mod.h
|
||||
minecraft/mod/Mod.cpp
|
||||
minecraft/mod/ModDetails.h
|
||||
minecraft/mod/ModFolderModel.h
|
||||
minecraft/mod/ModFolderModel.cpp
|
||||
minecraft/mod/ModFolderLoadTask.h
|
||||
minecraft/mod/ModFolderLoadTask.cpp
|
||||
minecraft/mod/LocalModParseTask.h
|
||||
minecraft/mod/LocalModParseTask.cpp
|
||||
minecraft/mod/Resource.h
|
||||
minecraft/mod/Resource.cpp
|
||||
minecraft/mod/ResourceFolderModel.h
|
||||
minecraft/mod/ResourceFolderModel.cpp
|
||||
minecraft/mod/ResourcePack.h
|
||||
minecraft/mod/ResourcePack.cpp
|
||||
minecraft/mod/ResourcePackFolderModel.h
|
||||
minecraft/mod/ResourcePackFolderModel.cpp
|
||||
minecraft/mod/TexturePack.h
|
||||
minecraft/mod/TexturePack.cpp
|
||||
minecraft/mod/TexturePackFolderModel.h
|
||||
minecraft/mod/TexturePackFolderModel.cpp
|
||||
minecraft/mod/ShaderPackFolderModel.h
|
||||
minecraft/mod/tasks/BasicFolderLoadTask.h
|
||||
minecraft/mod/tasks/ModFolderLoadTask.h
|
||||
minecraft/mod/tasks/ModFolderLoadTask.cpp
|
||||
minecraft/mod/tasks/LocalModParseTask.h
|
||||
minecraft/mod/tasks/LocalModParseTask.cpp
|
||||
minecraft/mod/tasks/LocalModUpdateTask.h
|
||||
minecraft/mod/tasks/LocalModUpdateTask.cpp
|
||||
minecraft/mod/tasks/LocalResourcePackParseTask.h
|
||||
minecraft/mod/tasks/LocalResourcePackParseTask.cpp
|
||||
minecraft/mod/tasks/LocalTexturePackParseTask.h
|
||||
minecraft/mod/tasks/LocalTexturePackParseTask.cpp
|
||||
|
||||
# Assets
|
||||
minecraft/AssetsUtils.h
|
||||
@ -350,52 +354,6 @@ set(MINECRAFT_SOURCES
|
||||
mojang/PackageManifest.cpp
|
||||
minecraft/Agent.h)
|
||||
|
||||
add_unit_test(GradleSpecifier
|
||||
SOURCES minecraft/GradleSpecifier_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_executable(PackageManifest
|
||||
mojang/PackageManifest_test.cpp
|
||||
)
|
||||
target_link_libraries(PackageManifest
|
||||
Launcher_logic
|
||||
Qt5::Test
|
||||
)
|
||||
target_include_directories(PackageManifest
|
||||
PRIVATE ../cmake/UnitTest/
|
||||
)
|
||||
add_test(
|
||||
NAME PackageManifest
|
||||
COMMAND PackageManifest
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_unit_test(MojangVersionFormat
|
||||
SOURCES minecraft/MojangVersionFormat_test.cpp
|
||||
LIBS Launcher_logic
|
||||
DATA minecraft/testdata
|
||||
)
|
||||
|
||||
add_unit_test(Library
|
||||
SOURCES minecraft/Library_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
# FIXME: shares data with FileSystem test
|
||||
add_unit_test(ModFolderModel
|
||||
SOURCES minecraft/mod/ModFolderModel_test.cpp
|
||||
DATA testdata
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
add_unit_test(ParseUtils
|
||||
SOURCES minecraft/ParseUtils_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
# the screenshots feature
|
||||
set(SCREENSHOTS_SOURCES
|
||||
screenshots/Screenshot.h
|
||||
@ -409,15 +367,14 @@ set(TASKS_SOURCES
|
||||
# Tasks
|
||||
tasks/Task.h
|
||||
tasks/Task.cpp
|
||||
tasks/ConcurrentTask.h
|
||||
tasks/ConcurrentTask.cpp
|
||||
tasks/SequentialTask.h
|
||||
tasks/SequentialTask.cpp
|
||||
tasks/MultipleOptionsTask.h
|
||||
tasks/MultipleOptionsTask.cpp
|
||||
)
|
||||
|
||||
add_unit_test(Task
|
||||
SOURCES tasks/Task_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
set(SETTINGS_SOURCES
|
||||
# Settings
|
||||
settings/INIFile.cpp
|
||||
@ -434,11 +391,6 @@ set(SETTINGS_SOURCES
|
||||
settings/SettingsObject.h
|
||||
)
|
||||
|
||||
add_unit_test(INIFile
|
||||
SOURCES settings/INIFile_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
set(JAVA_SOURCES
|
||||
java/JavaChecker.h
|
||||
java/JavaChecker.cpp
|
||||
@ -454,11 +406,6 @@ set(JAVA_SOURCES
|
||||
java/JavaVersion.cpp
|
||||
)
|
||||
|
||||
add_unit_test(JavaVersion
|
||||
SOURCES java/JavaVersion_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
set(TRANSLATIONS_SOURCES
|
||||
translations/TranslationsModel.h
|
||||
translations/TranslationsModel.cpp
|
||||
@ -495,13 +442,26 @@ set(META_SOURCES
|
||||
)
|
||||
|
||||
set(API_SOURCES
|
||||
modplatform/ModIndex.h
|
||||
modplatform/ModIndex.cpp
|
||||
|
||||
modplatform/ModAPI.h
|
||||
|
||||
modplatform/EnsureMetadataTask.h
|
||||
modplatform/EnsureMetadataTask.cpp
|
||||
|
||||
modplatform/CheckUpdateTask.h
|
||||
|
||||
modplatform/flame/FlameAPI.h
|
||||
modplatform/flame/FlameAPI.cpp
|
||||
modplatform/modrinth/ModrinthAPI.h
|
||||
|
||||
modplatform/modrinth/ModrinthAPI.cpp
|
||||
modplatform/helpers/NetworkModAPI.h
|
||||
modplatform/helpers/NetworkModAPI.cpp
|
||||
modplatform/helpers/HashUtils.h
|
||||
modplatform/helpers/HashUtils.cpp
|
||||
modplatform/helpers/OverrideUtils.h
|
||||
modplatform/helpers/OverrideUtils.cpp
|
||||
)
|
||||
|
||||
set(FTB_SOURCES
|
||||
@ -525,11 +485,21 @@ set(FLAME_SOURCES
|
||||
modplatform/flame/PackManifest.cpp
|
||||
modplatform/flame/FileResolvingTask.h
|
||||
modplatform/flame/FileResolvingTask.cpp
|
||||
modplatform/flame/FlameCheckUpdate.cpp
|
||||
modplatform/flame/FlameCheckUpdate.h
|
||||
modplatform/flame/FlameInstanceCreationTask.h
|
||||
modplatform/flame/FlameInstanceCreationTask.cpp
|
||||
)
|
||||
|
||||
set(MODRINTH_SOURCES
|
||||
modplatform/modrinth/ModrinthPackIndex.cpp
|
||||
modplatform/modrinth/ModrinthPackIndex.h
|
||||
modplatform/modrinth/ModrinthPackManifest.cpp
|
||||
modplatform/modrinth/ModrinthPackManifest.h
|
||||
modplatform/modrinth/ModrinthCheckUpdate.cpp
|
||||
modplatform/modrinth/ModrinthCheckUpdate.h
|
||||
modplatform/modrinth/ModrinthInstanceCreationTask.cpp
|
||||
modplatform/modrinth/ModrinthInstanceCreationTask.h
|
||||
)
|
||||
|
||||
set(MODPACKSCH_SOURCES
|
||||
@ -539,6 +509,12 @@ set(MODPACKSCH_SOURCES
|
||||
modplatform/modpacksch/FTBPackManifest.cpp
|
||||
)
|
||||
|
||||
set(PACKWIZ_SOURCES
|
||||
modplatform/packwiz/Packwiz.h
|
||||
modplatform/packwiz/Packwiz.cpp
|
||||
)
|
||||
|
||||
|
||||
set(TECHNIC_SOURCES
|
||||
modplatform/technic/SingleZipPackInstallTask.h
|
||||
modplatform/technic/SingleZipPackInstallTask.cpp
|
||||
@ -557,13 +533,10 @@ set(ATLAUNCHER_SOURCES
|
||||
modplatform/atlauncher/ATLPackInstallTask.h
|
||||
modplatform/atlauncher/ATLPackManifest.cpp
|
||||
modplatform/atlauncher/ATLPackManifest.h
|
||||
modplatform/atlauncher/ATLShareCode.cpp
|
||||
modplatform/atlauncher/ATLShareCode.h
|
||||
)
|
||||
|
||||
add_unit_test(Index
|
||||
SOURCES meta/Index_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
################################ COMPILE ################################
|
||||
|
||||
# we need zlib
|
||||
@ -590,10 +563,15 @@ set(LOGIC_SOURCES
|
||||
${FLAME_SOURCES}
|
||||
${MODRINTH_SOURCES}
|
||||
${MODPACKSCH_SOURCES}
|
||||
${PACKWIZ_SOURCES}
|
||||
${TECHNIC_SOURCES}
|
||||
${ATLAUNCHER_SOURCES}
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
set (LOGIC_SOURCES ${LOGIC_SOURCES} ${MAC_UPDATE_SOURCES})
|
||||
endif()
|
||||
|
||||
SET(LAUNCHER_SOURCES
|
||||
# Application base
|
||||
Application.h
|
||||
@ -655,6 +633,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/setupwizard/JavaWizardPage.h
|
||||
ui/setupwizard/LanguageWizardPage.cpp
|
||||
ui/setupwizard/LanguageWizardPage.h
|
||||
ui/setupwizard/PasteWizardPage.cpp
|
||||
ui/setupwizard/PasteWizardPage.h
|
||||
|
||||
# GUI - themes
|
||||
ui/themes/FusionTheme.cpp
|
||||
@ -687,6 +667,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/pages/BasePageProvider.h
|
||||
|
||||
# GUI - instance pages
|
||||
ui/pages/instance/ExternalResourcesPage.cpp
|
||||
ui/pages/instance/ExternalResourcesPage.h
|
||||
ui/pages/instance/GameOptionsPage.cpp
|
||||
ui/pages/instance/GameOptionsPage.h
|
||||
ui/pages/instance/VersionPage.cpp
|
||||
@ -748,6 +730,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h
|
||||
ui/pages/modplatform/atlauncher/AtlPage.cpp
|
||||
ui/pages/modplatform/atlauncher/AtlPage.h
|
||||
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.cpp
|
||||
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.h
|
||||
|
||||
ui/pages/modplatform/ftb/FtbFilterModel.cpp
|
||||
ui/pages/modplatform/ftb/FtbFilterModel.h
|
||||
@ -770,6 +754,11 @@ SET(LAUNCHER_SOURCES
|
||||
ui/pages/modplatform/flame/FlameModPage.cpp
|
||||
ui/pages/modplatform/flame/FlameModPage.h
|
||||
|
||||
ui/pages/modplatform/modrinth/ModrinthPage.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthPage.h
|
||||
ui/pages/modplatform/modrinth/ModrinthModel.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthModel.h
|
||||
|
||||
ui/pages/modplatform/technic/TechnicModel.cpp
|
||||
ui/pages/modplatform/technic/TechnicModel.h
|
||||
ui/pages/modplatform/technic/TechnicPage.cpp
|
||||
@ -778,10 +767,10 @@ SET(LAUNCHER_SOURCES
|
||||
ui/pages/modplatform/ImportPage.cpp
|
||||
ui/pages/modplatform/ImportPage.h
|
||||
|
||||
ui/pages/modplatform/modrinth/ModrinthModel.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthModel.h
|
||||
ui/pages/modplatform/modrinth/ModrinthPage.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthPage.h
|
||||
ui/pages/modplatform/modrinth/ModrinthModModel.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthModModel.h
|
||||
ui/pages/modplatform/modrinth/ModrinthModPage.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthModPage.h
|
||||
|
||||
# GUI - dialogs
|
||||
ui/dialogs/AboutDialog.cpp
|
||||
@ -810,6 +799,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/dialogs/NewComponentDialog.h
|
||||
ui/dialogs/NewInstanceDialog.cpp
|
||||
ui/dialogs/NewInstanceDialog.h
|
||||
ui/dialogs/NewsDialog.cpp
|
||||
ui/dialogs/NewsDialog.h
|
||||
ui/pagedialog/PageDialog.cpp
|
||||
ui/pagedialog/PageDialog.h
|
||||
ui/dialogs/ProgressDialog.cpp
|
||||
@ -824,6 +815,14 @@ SET(LAUNCHER_SOURCES
|
||||
ui/dialogs/SkinUploadDialog.h
|
||||
ui/dialogs/ModDownloadDialog.cpp
|
||||
ui/dialogs/ModDownloadDialog.h
|
||||
ui/dialogs/ScrollMessageBox.cpp
|
||||
ui/dialogs/ScrollMessageBox.h
|
||||
ui/dialogs/BlockedModsDialog.cpp
|
||||
ui/dialogs/BlockedModsDialog.h
|
||||
ui/dialogs/ChooseProviderDialog.h
|
||||
ui/dialogs/ChooseProviderDialog.cpp
|
||||
ui/dialogs/ModUpdateDialog.cpp
|
||||
ui/dialogs/ModUpdateDialog.h
|
||||
|
||||
# GUI - widgets
|
||||
ui/widgets/Common.cpp
|
||||
@ -846,8 +845,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/widgets/LineSeparator.h
|
||||
ui/widgets/LogView.cpp
|
||||
ui/widgets/LogView.h
|
||||
ui/widgets/MCModInfoFrame.cpp
|
||||
ui/widgets/MCModInfoFrame.h
|
||||
ui/widgets/InfoFrame.cpp
|
||||
ui/widgets/InfoFrame.h
|
||||
ui/widgets/ModFilterWidget.cpp
|
||||
ui/widgets/ModFilterWidget.h
|
||||
ui/widgets/ModListView.cpp
|
||||
@ -855,6 +854,12 @@ SET(LAUNCHER_SOURCES
|
||||
ui/widgets/PageContainer.cpp
|
||||
ui/widgets/PageContainer.h
|
||||
ui/widgets/PageContainer_p.h
|
||||
ui/widgets/ProjectDescriptionPage.h
|
||||
ui/widgets/ProjectDescriptionPage.cpp
|
||||
ui/widgets/VariableSizedImageObject.h
|
||||
ui/widgets/VariableSizedImageObject.cpp
|
||||
ui/widgets/ProjectItem.h
|
||||
ui/widgets/ProjectItem.cpp
|
||||
ui/widgets/VersionListView.cpp
|
||||
ui/widgets/VersionListView.h
|
||||
ui/widgets/VersionSelectWidget.cpp
|
||||
@ -878,7 +883,18 @@ SET(LAUNCHER_SOURCES
|
||||
ui/instanceview/VisualGroup.h
|
||||
)
|
||||
|
||||
qt5_wrap_ui(LAUNCHER_UI
|
||||
if(WIN32)
|
||||
set(LAUNCHER_SOURCES
|
||||
${LAUNCHER_SOURCES}
|
||||
|
||||
# GUI - dark titlebar for Windows 10/11
|
||||
ui/WinDarkmode.h
|
||||
ui/WinDarkmode.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
qt_wrap_ui(LAUNCHER_UI
|
||||
ui/setupwizard/PasteWizardPage.ui
|
||||
ui/pages/global/AccountListPage.ui
|
||||
ui/pages/global/JavaPage.ui
|
||||
ui/pages/global/LauncherPage.ui
|
||||
@ -886,7 +902,7 @@ qt5_wrap_ui(LAUNCHER_UI
|
||||
ui/pages/global/ProxyPage.ui
|
||||
ui/pages/global/MinecraftPage.ui
|
||||
ui/pages/global/ExternalToolsPage.ui
|
||||
ui/pages/instance/ModFolderPage.ui
|
||||
ui/pages/instance/ExternalResourcesPage.ui
|
||||
ui/pages/instance/NotesPage.ui
|
||||
ui/pages/instance/LogPage.ui
|
||||
ui/pages/instance/ServersPage.ui
|
||||
@ -904,10 +920,11 @@ qt5_wrap_ui(LAUNCHER_UI
|
||||
ui/pages/modplatform/legacy_ftb/Page.ui
|
||||
ui/pages/modplatform/ImportPage.ui
|
||||
ui/pages/modplatform/ftb/FtbPage.ui
|
||||
ui/pages/modplatform/modrinth/ModrinthPage.ui
|
||||
ui/pages/modplatform/technic/TechnicPage.ui
|
||||
ui/widgets/InstanceCardWidget.ui
|
||||
ui/widgets/CustomCommands.ui
|
||||
ui/widgets/MCModInfoFrame.ui
|
||||
ui/widgets/InfoFrame.ui
|
||||
ui/widgets/ModFilterWidget.ui
|
||||
ui/dialogs/CopyInstanceDialog.ui
|
||||
ui/dialogs/ProfileSetupDialog.ui
|
||||
@ -915,6 +932,7 @@ qt5_wrap_ui(LAUNCHER_UI
|
||||
ui/dialogs/NewInstanceDialog.ui
|
||||
ui/dialogs/UpdateDialog.ui
|
||||
ui/dialogs/NewComponentDialog.ui
|
||||
ui/dialogs/NewsDialog.ui
|
||||
ui/dialogs/ProfileSelectDialog.ui
|
||||
ui/dialogs/SkinUploadDialog.ui
|
||||
ui/dialogs/ExportInstanceDialog.ui
|
||||
@ -925,9 +943,12 @@ qt5_wrap_ui(LAUNCHER_UI
|
||||
ui/dialogs/LoginDialog.ui
|
||||
ui/dialogs/EditAccountDialog.ui
|
||||
ui/dialogs/ReviewMessageBox.ui
|
||||
ui/dialogs/ScrollMessageBox.ui
|
||||
ui/dialogs/BlockedModsDialog.ui
|
||||
ui/dialogs/ChooseProviderDialog.ui
|
||||
)
|
||||
|
||||
qt5_add_resources(LAUNCHER_RESOURCES
|
||||
qt_add_resources(LAUNCHER_RESOURCES
|
||||
resources/backgrounds/backgrounds.qrc
|
||||
resources/multimc/multimc.qrc
|
||||
resources/pe_dark/pe_dark.qrc
|
||||
@ -943,35 +964,61 @@ qt5_add_resources(LAUNCHER_RESOURCES
|
||||
|
||||
######## Windows resource files ########
|
||||
if(WIN32)
|
||||
set(LAUNCHER_RCS ../${Launcher_Branding_WindowsRC})
|
||||
set(LAUNCHER_RCS ${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_WindowsRC})
|
||||
endif()
|
||||
|
||||
# Add executable
|
||||
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
|
||||
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(Launcher_logic
|
||||
systeminfo
|
||||
Launcher_classparser
|
||||
Launcher_murmur2
|
||||
nbt++
|
||||
${ZLIB_LIBRARIES}
|
||||
optional-bare
|
||||
tomlc99
|
||||
tomlplusplus::tomlplusplus
|
||||
BuildConfig
|
||||
Katabasis
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
ghcFilesystem::ghc_filesystem
|
||||
)
|
||||
|
||||
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
||||
target_link_libraries(Launcher_logic
|
||||
gamemode
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(Launcher_logic
|
||||
Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::Xml
|
||||
Qt${QT_VERSION_MAJOR}::Network
|
||||
Qt${QT_VERSION_MAJOR}::Concurrent
|
||||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
${Launcher_QT_LIBS}
|
||||
)
|
||||
target_link_libraries(Launcher_logic
|
||||
Qt5::Core
|
||||
Qt5::Xml
|
||||
Qt5::Network
|
||||
Qt5::Concurrent
|
||||
Qt5::Gui
|
||||
)
|
||||
target_link_libraries(Launcher_logic
|
||||
Launcher_iconfix
|
||||
QuaZip::QuaZip
|
||||
hoedown
|
||||
LocalPeer
|
||||
Launcher_rainbow
|
||||
)
|
||||
if(APPLE)
|
||||
set(CMAKE_MACOSX_RPATH 1)
|
||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
|
||||
|
||||
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
|
||||
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
|
||||
|
||||
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
||||
target_link_libraries(Launcher_logic
|
||||
"-framework AppKit"
|
||||
"-framework Carbon"
|
||||
"-framework Foundation"
|
||||
"-framework ApplicationServices"
|
||||
)
|
||||
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
|
||||
endif()
|
||||
|
||||
target_link_libraries(Launcher_logic)
|
||||
|
||||
@ -994,8 +1041,16 @@ install(TARGETS ${Launcher_Name}
|
||||
BUNDLE DESTINATION "." COMPONENT Runtime
|
||||
LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
|
||||
RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
|
||||
FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime
|
||||
)
|
||||
|
||||
if (UNIX AND APPLE)
|
||||
# Add Sparkle updater
|
||||
# It has to be copied here instead of just allowing fixup_bundle to install it, otherwise essential parts of
|
||||
# the framework aren't installed
|
||||
install(DIRECTORY ${MACOSX_SPARKLE_DIR}/Sparkle.framework DESTINATION ${FRAMEWORK_DEST_DIR} USE_SOURCE_PERMISSIONS)
|
||||
endif()
|
||||
|
||||
#### The bundle mess! ####
|
||||
# Bundle utilities are used to complete the portable packages - they add all the libraries that would otherwise be missing on the target system.
|
||||
# NOTE: it seems that this absolutely has to be here, and nowhere else.
|
||||
@ -1036,6 +1091,14 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
||||
COMPONENT Runtime
|
||||
)
|
||||
endif()
|
||||
# TLS plugins (Qt 6 only)
|
||||
if(EXISTS "${QT_PLUGINS_DIR}/tls")
|
||||
install(
|
||||
DIRECTORY "${QT_PLUGINS_DIR}/tls"
|
||||
DESTINATION ${PLUGIN_DEST_DIR}
|
||||
COMPONENT Runtime
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
# Image formats
|
||||
install(
|
||||
@ -1078,6 +1141,16 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
||||
REGEX "\\.dSYM" EXCLUDE
|
||||
)
|
||||
endif()
|
||||
# TLS plugins (Qt 6 only)
|
||||
if(EXISTS "${QT_PLUGINS_DIR}/tls")
|
||||
install(
|
||||
DIRECTORY "${QT_PLUGINS_DIR}/tls"
|
||||
DESTINATION ${PLUGIN_DEST_DIR}
|
||||
COMPONENT Runtime
|
||||
REGEX "_debug\\." EXCLUDE
|
||||
REGEX "\\.dSYM" EXCLUDE
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
|
||||
|
@ -1,18 +1,38 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Commandline.h"
|
||||
@ -47,7 +67,7 @@ QStringList splitArgs(QString args)
|
||||
if (cchar == '\\')
|
||||
escape = true;
|
||||
else if (cchar == inquotes)
|
||||
inquotes = 0;
|
||||
inquotes = QChar::Null;
|
||||
else
|
||||
current += cchar;
|
||||
// otherwise
|
||||
@ -72,412 +92,4 @@ QStringList splitArgs(QString args)
|
||||
argv << current;
|
||||
return argv;
|
||||
}
|
||||
|
||||
Parser::Parser(FlagStyle::Enum flagStyle, ArgumentStyle::Enum argStyle)
|
||||
{
|
||||
m_flagStyle = flagStyle;
|
||||
m_argStyle = argStyle;
|
||||
}
|
||||
|
||||
// styles setter/getter
|
||||
void Parser::setArgumentStyle(ArgumentStyle::Enum style)
|
||||
{
|
||||
m_argStyle = style;
|
||||
}
|
||||
ArgumentStyle::Enum Parser::argumentStyle()
|
||||
{
|
||||
return m_argStyle;
|
||||
}
|
||||
|
||||
void Parser::setFlagStyle(FlagStyle::Enum style)
|
||||
{
|
||||
m_flagStyle = style;
|
||||
}
|
||||
FlagStyle::Enum Parser::flagStyle()
|
||||
{
|
||||
return m_flagStyle;
|
||||
}
|
||||
|
||||
// setup methods
|
||||
void Parser::addSwitch(QString name, bool def)
|
||||
{
|
||||
if (m_params.contains(name))
|
||||
throw "Name not unique";
|
||||
|
||||
OptionDef *param = new OptionDef;
|
||||
param->type = otSwitch;
|
||||
param->name = name;
|
||||
param->metavar = QString("<%1>").arg(name);
|
||||
param->def = def;
|
||||
|
||||
m_options[name] = param;
|
||||
m_params[name] = (CommonDef *)param;
|
||||
m_optionList.append(param);
|
||||
}
|
||||
|
||||
void Parser::addOption(QString name, QVariant def)
|
||||
{
|
||||
if (m_params.contains(name))
|
||||
throw "Name not unique";
|
||||
|
||||
OptionDef *param = new OptionDef;
|
||||
param->type = otOption;
|
||||
param->name = name;
|
||||
param->metavar = QString("<%1>").arg(name);
|
||||
param->def = def;
|
||||
|
||||
m_options[name] = param;
|
||||
m_params[name] = (CommonDef *)param;
|
||||
m_optionList.append(param);
|
||||
}
|
||||
|
||||
void Parser::addArgument(QString name, bool required, QVariant def)
|
||||
{
|
||||
if (m_params.contains(name))
|
||||
throw "Name not unique";
|
||||
|
||||
PositionalDef *param = new PositionalDef;
|
||||
param->name = name;
|
||||
param->def = def;
|
||||
param->required = required;
|
||||
param->metavar = name;
|
||||
|
||||
m_positionals.append(param);
|
||||
m_params[name] = (CommonDef *)param;
|
||||
}
|
||||
|
||||
void Parser::addDocumentation(QString name, QString doc, QString metavar)
|
||||
{
|
||||
if (!m_params.contains(name))
|
||||
throw "Name does not exist";
|
||||
|
||||
CommonDef *param = m_params[name];
|
||||
param->doc = doc;
|
||||
if (!metavar.isNull())
|
||||
param->metavar = metavar;
|
||||
}
|
||||
|
||||
void Parser::addShortOpt(QString name, QChar flag)
|
||||
{
|
||||
if (!m_params.contains(name))
|
||||
throw "Name does not exist";
|
||||
if (!m_options.contains(name))
|
||||
throw "Name is not an Option or Swtich";
|
||||
|
||||
OptionDef *param = m_options[name];
|
||||
m_flags[flag] = param;
|
||||
param->flag = flag;
|
||||
}
|
||||
|
||||
// help methods
|
||||
QString Parser::compileHelp(QString progName, int helpIndent, bool useFlags)
|
||||
{
|
||||
QStringList help;
|
||||
help << compileUsage(progName, useFlags) << "\r\n";
|
||||
|
||||
// positionals
|
||||
if (!m_positionals.isEmpty())
|
||||
{
|
||||
help << "\r\n";
|
||||
help << "Positional arguments:\r\n";
|
||||
QListIterator<PositionalDef *> it2(m_positionals);
|
||||
while (it2.hasNext())
|
||||
{
|
||||
PositionalDef *param = it2.next();
|
||||
help << " " << param->metavar;
|
||||
help << " " << QString(helpIndent - param->metavar.length() - 1, ' ');
|
||||
help << param->doc << "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Options
|
||||
if (!m_optionList.isEmpty())
|
||||
{
|
||||
help << "\r\n";
|
||||
QString optPrefix, flagPrefix;
|
||||
getPrefix(optPrefix, flagPrefix);
|
||||
|
||||
help << "Options & Switches:\r\n";
|
||||
QListIterator<OptionDef *> it(m_optionList);
|
||||
while (it.hasNext())
|
||||
{
|
||||
OptionDef *option = it.next();
|
||||
help << " ";
|
||||
int nameLength = optPrefix.length() + option->name.length();
|
||||
if (!option->flag.isNull())
|
||||
{
|
||||
nameLength += 3 + flagPrefix.length();
|
||||
help << flagPrefix << option->flag << ", ";
|
||||
}
|
||||
help << optPrefix << option->name;
|
||||
if (option->type == otOption)
|
||||
{
|
||||
QString arg = QString("%1%2").arg(
|
||||
((m_argStyle == ArgumentStyle::Equals) ? "=" : " "), option->metavar);
|
||||
nameLength += arg.length();
|
||||
help << arg;
|
||||
}
|
||||
help << " " << QString(helpIndent - nameLength - 1, ' ');
|
||||
help << option->doc << "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
return help.join("");
|
||||
}
|
||||
|
||||
QString Parser::compileUsage(QString progName, bool useFlags)
|
||||
{
|
||||
QStringList usage;
|
||||
usage << "Usage: " << progName;
|
||||
|
||||
QString optPrefix, flagPrefix;
|
||||
getPrefix(optPrefix, flagPrefix);
|
||||
|
||||
// options
|
||||
QListIterator<OptionDef *> it(m_optionList);
|
||||
while (it.hasNext())
|
||||
{
|
||||
OptionDef *option = it.next();
|
||||
usage << " [";
|
||||
if (!option->flag.isNull() && useFlags)
|
||||
usage << flagPrefix << option->flag;
|
||||
else
|
||||
usage << optPrefix << option->name;
|
||||
if (option->type == otOption)
|
||||
usage << ((m_argStyle == ArgumentStyle::Equals) ? "=" : " ") << option->metavar;
|
||||
usage << "]";
|
||||
}
|
||||
|
||||
// arguments
|
||||
QListIterator<PositionalDef *> it2(m_positionals);
|
||||
while (it2.hasNext())
|
||||
{
|
||||
PositionalDef *param = it2.next();
|
||||
usage << " " << (param->required ? "<" : "[");
|
||||
usage << param->metavar;
|
||||
usage << (param->required ? ">" : "]");
|
||||
}
|
||||
|
||||
return usage.join("");
|
||||
}
|
||||
|
||||
// parsing
|
||||
QHash<QString, QVariant> Parser::parse(QStringList argv)
|
||||
{
|
||||
QHash<QString, QVariant> map;
|
||||
|
||||
QStringListIterator it(argv);
|
||||
QString programName = it.next();
|
||||
|
||||
QString optionPrefix;
|
||||
QString flagPrefix;
|
||||
QListIterator<PositionalDef *> positionals(m_positionals);
|
||||
QStringList expecting;
|
||||
|
||||
getPrefix(optionPrefix, flagPrefix);
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
QString arg = it.next();
|
||||
|
||||
if (!expecting.isEmpty())
|
||||
// we were expecting an argument
|
||||
{
|
||||
QString name = expecting.first();
|
||||
/*
|
||||
if (map.contains(name))
|
||||
throw ParsingError(
|
||||
QString("Option %2%1 was given multiple times").arg(name, optionPrefix));
|
||||
*/
|
||||
map[name] = QVariant(arg);
|
||||
|
||||
expecting.removeFirst();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.startsWith(optionPrefix))
|
||||
// we have an option
|
||||
{
|
||||
// qDebug("Found option %s", qPrintable(arg));
|
||||
|
||||
QString name = arg.mid(optionPrefix.length());
|
||||
QString equals;
|
||||
|
||||
if ((m_argStyle == ArgumentStyle::Equals ||
|
||||
m_argStyle == ArgumentStyle::SpaceAndEquals) &&
|
||||
name.contains("="))
|
||||
{
|
||||
int i = name.indexOf("=");
|
||||
equals = name.mid(i + 1);
|
||||
name = name.left(i);
|
||||
}
|
||||
|
||||
if (m_options.contains(name))
|
||||
{
|
||||
/*
|
||||
if (map.contains(name))
|
||||
throw ParsingError(QString("Option %2%1 was given multiple times")
|
||||
.arg(name, optionPrefix));
|
||||
*/
|
||||
OptionDef *option = m_options[name];
|
||||
if (option->type == otSwitch)
|
||||
map[name] = true;
|
||||
else // if (option->type == otOption)
|
||||
{
|
||||
if (m_argStyle == ArgumentStyle::Space)
|
||||
expecting.append(name);
|
||||
else if (!equals.isNull())
|
||||
map[name] = equals;
|
||||
else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
|
||||
expecting.append(name);
|
||||
else
|
||||
throw ParsingError(QString("Option %2%1 reqires an argument.")
|
||||
.arg(name, optionPrefix));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
throw ParsingError(QString("Unknown Option %2%1").arg(name, optionPrefix));
|
||||
}
|
||||
|
||||
if (arg.startsWith(flagPrefix))
|
||||
// we have (a) flag(s)
|
||||
{
|
||||
// qDebug("Found flags %s", qPrintable(arg));
|
||||
|
||||
QString flags = arg.mid(flagPrefix.length());
|
||||
QString equals;
|
||||
|
||||
if ((m_argStyle == ArgumentStyle::Equals ||
|
||||
m_argStyle == ArgumentStyle::SpaceAndEquals) &&
|
||||
flags.contains("="))
|
||||
{
|
||||
int i = flags.indexOf("=");
|
||||
equals = flags.mid(i + 1);
|
||||
flags = flags.left(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < flags.length(); i++)
|
||||
{
|
||||
QChar flag = flags.at(i);
|
||||
|
||||
if (!m_flags.contains(flag))
|
||||
throw ParsingError(QString("Unknown flag %2%1").arg(flag, flagPrefix));
|
||||
|
||||
OptionDef *option = m_flags[flag];
|
||||
/*
|
||||
if (map.contains(option->name))
|
||||
throw ParsingError(QString("Option %2%1 was given multiple times")
|
||||
.arg(option->name, optionPrefix));
|
||||
*/
|
||||
if (option->type == otSwitch)
|
||||
map[option->name] = true;
|
||||
else // if (option->type == otOption)
|
||||
{
|
||||
if (m_argStyle == ArgumentStyle::Space)
|
||||
expecting.append(option->name);
|
||||
else if (!equals.isNull())
|
||||
if (i == flags.length() - 1)
|
||||
map[option->name] = equals;
|
||||
else
|
||||
throw ParsingError(QString("Flag %4%2 of Argument-requiring Option "
|
||||
"%1 not last flag in %4%3")
|
||||
.arg(option->name, flag, flags, flagPrefix));
|
||||
else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
|
||||
expecting.append(option->name);
|
||||
else
|
||||
throw ParsingError(QString("Option %1 reqires an argument. (flag %3%2)")
|
||||
.arg(option->name, flag, flagPrefix));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// must be a positional argument
|
||||
if (!positionals.hasNext())
|
||||
throw ParsingError(QString("Don't know what to do with '%1'").arg(arg));
|
||||
|
||||
PositionalDef *param = positionals.next();
|
||||
|
||||
map[param->name] = arg;
|
||||
}
|
||||
|
||||
// check if we're missing something
|
||||
if (!expecting.isEmpty())
|
||||
throw ParsingError(QString("Was still expecting arguments for %2%1").arg(
|
||||
expecting.join(QString(", ") + optionPrefix), optionPrefix));
|
||||
|
||||
while (positionals.hasNext())
|
||||
{
|
||||
PositionalDef *param = positionals.next();
|
||||
if (param->required)
|
||||
throw ParsingError(
|
||||
QString("Missing required positional argument '%1'").arg(param->name));
|
||||
else
|
||||
map[param->name] = param->def;
|
||||
}
|
||||
|
||||
// fill out gaps
|
||||
QListIterator<OptionDef *> iter(m_optionList);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
OptionDef *option = iter.next();
|
||||
if (!map.contains(option->name))
|
||||
map[option->name] = option->def;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
// clear defs
|
||||
void Parser::clear()
|
||||
{
|
||||
m_flags.clear();
|
||||
m_params.clear();
|
||||
m_options.clear();
|
||||
|
||||
QMutableListIterator<OptionDef *> it(m_optionList);
|
||||
while (it.hasNext())
|
||||
{
|
||||
OptionDef *option = it.next();
|
||||
it.remove();
|
||||
delete option;
|
||||
}
|
||||
|
||||
QMutableListIterator<PositionalDef *> it2(m_positionals);
|
||||
while (it2.hasNext())
|
||||
{
|
||||
PositionalDef *arg = it2.next();
|
||||
it2.remove();
|
||||
delete arg;
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor
|
||||
Parser::~Parser()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
// getPrefix
|
||||
void Parser::getPrefix(QString &opt, QString &flag)
|
||||
{
|
||||
if (m_flagStyle == FlagStyle::Windows)
|
||||
opt = flag = "/";
|
||||
else if (m_flagStyle == FlagStyle::Unix)
|
||||
opt = flag = "-";
|
||||
// else if (m_flagStyle == FlagStyle::GNU)
|
||||
else
|
||||
{
|
||||
opt = "--";
|
||||
flag = "-";
|
||||
}
|
||||
}
|
||||
|
||||
// ParsingError
|
||||
ParsingError::ParsingError(const QString &what) : std::runtime_error(what.toStdString())
|
||||
{
|
||||
}
|
||||
}
|
@ -17,12 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QHash>
|
||||
#include <QStringList>
|
||||
|
||||
/**
|
||||
@ -39,212 +34,4 @@ namespace Commandline
|
||||
* @return a QStringList containing all arguments
|
||||
*/
|
||||
QStringList splitArgs(QString args);
|
||||
|
||||
/**
|
||||
* @brief The FlagStyle enum
|
||||
* Specifies how flags are decorated
|
||||
*/
|
||||
|
||||
namespace FlagStyle
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
GNU, /**< --option and -o (GNU Style) */
|
||||
Unix, /**< -option and -o (Unix Style) */
|
||||
Windows, /**< /option and /o (Windows Style) */
|
||||
#ifdef Q_OS_WIN32
|
||||
Default = Windows
|
||||
#else
|
||||
Default = GNU
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The ArgumentStyle enum
|
||||
*/
|
||||
namespace ArgumentStyle
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
Space, /**< --option value */
|
||||
Equals, /**< --option=value */
|
||||
SpaceAndEquals, /**< --option[= ]value */
|
||||
#ifdef Q_OS_WIN32
|
||||
Default = Equals
|
||||
#else
|
||||
Default = SpaceAndEquals
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The ParsingError class
|
||||
*/
|
||||
class ParsingError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
ParsingError(const QString &what);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The Parser class
|
||||
*/
|
||||
class Parser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Parser constructor
|
||||
* @param flagStyle the FlagStyle to use in this Parser
|
||||
* @param argStyle the ArgumentStyle to use in this Parser
|
||||
*/
|
||||
Parser(FlagStyle::Enum flagStyle = FlagStyle::Default,
|
||||
ArgumentStyle::Enum argStyle = ArgumentStyle::Default);
|
||||
|
||||
/**
|
||||
* @brief set the flag style
|
||||
* @param style
|
||||
*/
|
||||
void setFlagStyle(FlagStyle::Enum style);
|
||||
|
||||
/**
|
||||
* @brief get the flag style
|
||||
* @return
|
||||
*/
|
||||
FlagStyle::Enum flagStyle();
|
||||
|
||||
/**
|
||||
* @brief set the argument style
|
||||
* @param style
|
||||
*/
|
||||
void setArgumentStyle(ArgumentStyle::Enum style);
|
||||
|
||||
/**
|
||||
* @brief get the argument style
|
||||
* @return
|
||||
*/
|
||||
ArgumentStyle::Enum argumentStyle();
|
||||
|
||||
/**
|
||||
* @brief define a boolean switch
|
||||
* @param name the parameter name
|
||||
* @param def the default value
|
||||
*/
|
||||
void addSwitch(QString name, bool def = false);
|
||||
|
||||
/**
|
||||
* @brief define an option that takes an additional argument
|
||||
* @param name the parameter name
|
||||
* @param def the default value
|
||||
*/
|
||||
void addOption(QString name, QVariant def = QVariant());
|
||||
|
||||
/**
|
||||
* @brief define a positional argument
|
||||
* @param name the parameter name
|
||||
* @param required wether this argument is required
|
||||
* @param def the default value
|
||||
*/
|
||||
void addArgument(QString name, bool required = true, QVariant def = QVariant());
|
||||
|
||||
/**
|
||||
* @brief adds a flag to an existing parameter
|
||||
* @param name the (existing) parameter name
|
||||
* @param flag the flag character
|
||||
* @see addSwitch addArgument addOption
|
||||
* Note: any one parameter can only have one flag
|
||||
*/
|
||||
void addShortOpt(QString name, QChar flag);
|
||||
|
||||
/**
|
||||
* @brief adds documentation to a Parameter
|
||||
* @param name the parameter name
|
||||
* @param metavar a string to be displayed as placeholder for the value
|
||||
* @param doc a QString containing the documentation
|
||||
* Note: on positional arguments, metavar replaces the name as displayed.
|
||||
* on options , metavar replaces the value placeholder
|
||||
*/
|
||||
void addDocumentation(QString name, QString doc, QString metavar = QString());
|
||||
|
||||
/**
|
||||
* @brief generate a help message
|
||||
* @param progName the program name to use in the help message
|
||||
* @param helpIndent how much the parameter documentation should be indented
|
||||
* @param flagsInUsage whether we should use flags instead of options in the usage
|
||||
* @return a help message
|
||||
*/
|
||||
QString compileHelp(QString progName, int helpIndent = 22, bool flagsInUsage = true);
|
||||
|
||||
/**
|
||||
* @brief generate a short usage message
|
||||
* @param progName the program name to use in the usage message
|
||||
* @param useFlags whether we should use flags instead of options
|
||||
* @return a usage message
|
||||
*/
|
||||
QString compileUsage(QString progName, bool useFlags = true);
|
||||
|
||||
/**
|
||||
* @brief parse
|
||||
* @param argv a QStringList containing the program ARGV
|
||||
* @return a QHash mapping argument names to their values
|
||||
*/
|
||||
QHash<QString, QVariant> parse(QStringList argv);
|
||||
|
||||
/**
|
||||
* @brief clear all definitions
|
||||
*/
|
||||
void clear();
|
||||
|
||||
~Parser();
|
||||
|
||||
private:
|
||||
FlagStyle::Enum m_flagStyle;
|
||||
ArgumentStyle::Enum m_argStyle;
|
||||
|
||||
enum OptionType
|
||||
{
|
||||
otSwitch,
|
||||
otOption
|
||||
};
|
||||
|
||||
// Important: the common part MUST BE COMMON ON ALL THREE structs
|
||||
struct CommonDef
|
||||
{
|
||||
QString name;
|
||||
QString doc;
|
||||
QString metavar;
|
||||
QVariant def;
|
||||
};
|
||||
|
||||
struct OptionDef
|
||||
{
|
||||
// common
|
||||
QString name;
|
||||
QString doc;
|
||||
QString metavar;
|
||||
QVariant def;
|
||||
// option
|
||||
OptionType type;
|
||||
QChar flag;
|
||||
};
|
||||
|
||||
struct PositionalDef
|
||||
{
|
||||
// common
|
||||
QString name;
|
||||
QString doc;
|
||||
QString metavar;
|
||||
QVariant def;
|
||||
// positional
|
||||
bool required;
|
||||
};
|
||||
|
||||
QHash<QString, OptionDef *> m_options;
|
||||
QHash<QChar, OptionDef *> m_flags;
|
||||
QHash<QString, CommonDef *> m_params;
|
||||
QList<PositionalDef *> m_positionals;
|
||||
QList<OptionDef *> m_optionList;
|
||||
|
||||
void getPrefix(QString &opt, QString &flag);
|
||||
};
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ bool openDirectory(const QString &path, bool ensureExists)
|
||||
return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
|
||||
};
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
if(!APPLICATION->isFlatpak())
|
||||
if(!isFlatpak())
|
||||
{
|
||||
return IndirectOpen(f);
|
||||
}
|
||||
@ -140,7 +140,7 @@ bool openFile(const QString &path)
|
||||
return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||
};
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
if(!APPLICATION->isFlatpak())
|
||||
if(!isFlatpak())
|
||||
{
|
||||
return IndirectOpen(f);
|
||||
}
|
||||
@ -158,7 +158,7 @@ bool openFile(const QString &application, const QString &path, const QString &wo
|
||||
qDebug() << "Opening file" << path << "using" << application;
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
||||
if(!APPLICATION->isFlatpak())
|
||||
if(!isFlatpak())
|
||||
{
|
||||
return IndirectOpen([&]()
|
||||
{
|
||||
@ -178,7 +178,7 @@ bool run(const QString &application, const QStringList &args, const QString &wor
|
||||
{
|
||||
qDebug() << "Running" << application << "with args" << args.join(' ');
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
if(!APPLICATION->isFlatpak())
|
||||
if(!isFlatpak())
|
||||
{
|
||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
||||
return IndirectOpen([&]()
|
||||
@ -203,7 +203,7 @@ bool openUrl(const QUrl &url)
|
||||
return QDesktopServices::openUrl(url);
|
||||
};
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
if(!APPLICATION->isFlatpak())
|
||||
if(!isFlatpak())
|
||||
{
|
||||
return IndirectOpen(f);
|
||||
}
|
||||
@ -216,4 +216,13 @@ bool openUrl(const QUrl &url)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isFlatpak()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
return QFile::exists("/.flatpak-info");
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,4 +33,6 @@ namespace DesktopServices
|
||||
* Open the URL, most likely in a browser. Maybe.
|
||||
*/
|
||||
bool openUrl(const QUrl &url);
|
||||
|
||||
bool isFlatpak();
|
||||
}
|
||||
|
@ -1,77 +1,135 @@
|
||||
// Licensed under the Apache-2.0 license. See README.md for details.
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "FileSystem.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QSaveFile>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QUrl>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QSaveFile>
|
||||
#include <QStandardPaths>
|
||||
#include <QTextStream>
|
||||
#include <QUrl>
|
||||
#include "DesktopServices.h"
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <sys/utime.h>
|
||||
#include <winnls.h>
|
||||
#include <shobjidl.h>
|
||||
#include <objbase.h>
|
||||
#include <objidl.h>
|
||||
#include <shlguid.h>
|
||||
#include <shlobj.h>
|
||||
#include <objbase.h>
|
||||
#include <objidl.h>
|
||||
#include <shlguid.h>
|
||||
#include <shlobj.h>
|
||||
#include <shobjidl.h>
|
||||
#include <sys/utime.h>
|
||||
#include <windows.h>
|
||||
#include <winnls.h>
|
||||
#include <string>
|
||||
#else
|
||||
#include <utime.h>
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
|
||||
#endif // __APPLE__
|
||||
|
||||
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
|
||||
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
|
||||
#define GHC_USE_STD_FS
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#endif // MacOS min version check
|
||||
#endif // Other OSes version check
|
||||
|
||||
#ifndef GHC_USE_STD_FS
|
||||
#include <ghc/filesystem.hpp>
|
||||
namespace fs = ghc::filesystem;
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
|
||||
std::wstring toStdString(QString s)
|
||||
{
|
||||
return s.toStdWString();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
std::string toStdString(QString s)
|
||||
{
|
||||
return s.toStdString();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace FS {
|
||||
|
||||
void ensureExists(const QDir &dir)
|
||||
void ensureExists(const QDir& dir)
|
||||
{
|
||||
if (!QDir().mkpath(dir.absolutePath()))
|
||||
{
|
||||
throw FileSystemException("Unable to create folder " + dir.dirName() + " (" +
|
||||
dir.absolutePath() + ")");
|
||||
if (!QDir().mkpath(dir.absolutePath())) {
|
||||
throw FileSystemException("Unable to create folder " + dir.dirName() + " (" + dir.absolutePath() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
void write(const QString &filename, const QByteArray &data)
|
||||
void write(const QString& filename, const QByteArray& data)
|
||||
{
|
||||
ensureExists(QFileInfo(filename).dir());
|
||||
QSaveFile file(filename);
|
||||
if (!file.open(QSaveFile::WriteOnly))
|
||||
{
|
||||
throw FileSystemException("Couldn't open " + filename + " for writing: " +
|
||||
file.errorString());
|
||||
if (!file.open(QSaveFile::WriteOnly)) {
|
||||
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
||||
}
|
||||
if (data.size() != file.write(data))
|
||||
{
|
||||
throw FileSystemException("Error writing data to " + filename + ": " +
|
||||
file.errorString());
|
||||
if (data.size() != file.write(data)) {
|
||||
throw FileSystemException("Error writing data to " + filename + ": " + file.errorString());
|
||||
}
|
||||
if (!file.commit())
|
||||
{
|
||||
throw FileSystemException("Error while committing data to " + filename + ": " +
|
||||
file.errorString());
|
||||
if (!file.commit()) {
|
||||
throw FileSystemException("Error while committing data to " + filename + ": " + file.errorString());
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray read(const QString &filename)
|
||||
QByteArray read(const QString& filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
{
|
||||
throw FileSystemException("Unable to open " + filename + " for reading: " +
|
||||
file.errorString());
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
throw FileSystemException("Unable to open " + filename + " for reading: " + file.errorString());
|
||||
}
|
||||
const qint64 size = file.size();
|
||||
QByteArray data(int(size), 0);
|
||||
const qint64 ret = file.read(data.data(), size);
|
||||
if (ret == -1 || ret != size)
|
||||
{
|
||||
throw FileSystemException("Error reading data from " + filename + ": " +
|
||||
file.errorString());
|
||||
if (ret == -1 || ret != size) {
|
||||
throw FileSystemException("Error reading data from " + filename + ": " + file.errorString());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@ -105,149 +163,102 @@ bool ensureFolderPathExists(QString foldernamepath)
|
||||
return success;
|
||||
}
|
||||
|
||||
bool copy::operator()(const QString &offset)
|
||||
bool copy::operator()(const QString& offset)
|
||||
{
|
||||
//NOTE always deep copy on windows. the alternatives are too messy.
|
||||
#if defined Q_OS_WIN32
|
||||
using copy_opts = fs::copy_options;
|
||||
|
||||
// NOTE always deep copy on windows. the alternatives are too messy.
|
||||
#if defined Q_OS_WIN32
|
||||
m_followSymlinks = true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
auto src = PathCombine(m_src.absolutePath(), offset);
|
||||
auto dst = PathCombine(m_dst.absolutePath(), offset);
|
||||
|
||||
QFileInfo currentSrc(src);
|
||||
if (!currentSrc.exists())
|
||||
return false;
|
||||
std::error_code err;
|
||||
|
||||
if(!m_followSymlinks && currentSrc.isSymLink())
|
||||
{
|
||||
qDebug() << "creating symlink" << src << " - " << dst;
|
||||
if (!ensureFilePathExists(dst))
|
||||
{
|
||||
qWarning() << "Cannot create path!";
|
||||
return false;
|
||||
fs::copy_options opt = copy_opts::none;
|
||||
|
||||
// The default behavior is to follow symlinks
|
||||
if (!m_followSymlinks)
|
||||
opt |= copy_opts::copy_symlinks;
|
||||
|
||||
// Function that'll do the actual copying
|
||||
auto copy_file = [&](QString src_path, QString relative_dst_path) {
|
||||
if (m_blacklist && m_blacklist->matches(relative_dst_path))
|
||||
return;
|
||||
|
||||
auto dst_path = PathCombine(dst, relative_dst_path);
|
||||
ensureFilePathExists(dst_path);
|
||||
|
||||
fs::copy(toStdString(src_path), toStdString(dst_path), opt, err);
|
||||
if (err) {
|
||||
qWarning() << "Failed to copy files:" << QString::fromStdString(err.message());
|
||||
qDebug() << "Source file:" << src_path;
|
||||
qDebug() << "Destination file:" << dst_path;
|
||||
}
|
||||
return QFile::link(currentSrc.symLinkTarget(), dst);
|
||||
};
|
||||
|
||||
// We can't use copy_opts::recursive because we need to take into account the
|
||||
// blacklisted paths, so we iterate over the source directory, and if there's no blacklist
|
||||
// match, we copy the file.
|
||||
QDir src_dir(src);
|
||||
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
|
||||
|
||||
while (source_it.hasNext()) {
|
||||
auto src_path = source_it.next();
|
||||
auto relative_path = src_dir.relativeFilePath(src_path);
|
||||
|
||||
copy_file(src_path, relative_path);
|
||||
}
|
||||
else if(currentSrc.isFile())
|
||||
{
|
||||
qDebug() << "copying file" << src << " - " << dst;
|
||||
if (!ensureFilePathExists(dst))
|
||||
{
|
||||
qWarning() << "Cannot create path!";
|
||||
return false;
|
||||
}
|
||||
return QFile::copy(src, dst);
|
||||
}
|
||||
else if(currentSrc.isDir())
|
||||
{
|
||||
qDebug() << "recursing" << offset;
|
||||
if (!ensureFolderPathExists(dst))
|
||||
{
|
||||
qWarning() << "Cannot create path!";
|
||||
return false;
|
||||
}
|
||||
QDir currentDir(src);
|
||||
for(auto & f : currentDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System))
|
||||
{
|
||||
auto inner_offset = PathCombine(offset, f);
|
||||
// ignore and skip stuff that matches the blacklist.
|
||||
if(m_blacklist && m_blacklist->matches(inner_offset))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(!operator()(inner_offset))
|
||||
{
|
||||
qWarning() << "Failed to copy" << inner_offset;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical() << "Copy ERROR: Unknown filesystem object:" << src;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
// If the root src is not a directory, the previous iterator won't run.
|
||||
if (!fs::is_directory(toStdString(src)))
|
||||
copy_file(src, "");
|
||||
|
||||
return err.value() == 0;
|
||||
}
|
||||
|
||||
bool deletePath(QString path)
|
||||
{
|
||||
bool OK = true;
|
||||
QFileInfo finfo(path);
|
||||
if(finfo.isFile()) {
|
||||
return QFile::remove(path);
|
||||
std::error_code err;
|
||||
|
||||
fs::remove_all(toStdString(path), err);
|
||||
|
||||
if (err) {
|
||||
qWarning() << "Failed to remove files:" << QString::fromStdString(err.message());
|
||||
}
|
||||
|
||||
QDir dir(path);
|
||||
|
||||
if (!dir.exists())
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
auto allEntries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden |
|
||||
QDir::AllDirs | QDir::Files,
|
||||
QDir::DirsFirst);
|
||||
|
||||
for(auto & info: allEntries)
|
||||
{
|
||||
#if defined Q_OS_WIN32
|
||||
QString nativePath = QDir::toNativeSeparators(info.absoluteFilePath());
|
||||
auto wString = nativePath.toStdWString();
|
||||
DWORD dwAttrs = GetFileAttributesW(wString.c_str());
|
||||
// Windows: check for junctions, reparse points and other nasty things of that sort
|
||||
if(dwAttrs & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
{
|
||||
if (info.isFile())
|
||||
{
|
||||
OK &= QFile::remove(info.absoluteFilePath());
|
||||
}
|
||||
else if (info.isDir())
|
||||
{
|
||||
OK &= dir.rmdir(info.absoluteFilePath());
|
||||
}
|
||||
}
|
||||
#else
|
||||
// We do not trust Qt with reparse points, but do trust it with unix symlinks.
|
||||
if(info.isSymLink())
|
||||
{
|
||||
OK &= QFile::remove(info.absoluteFilePath());
|
||||
}
|
||||
#endif
|
||||
else if (info.isDir())
|
||||
{
|
||||
OK &= deletePath(info.absoluteFilePath());
|
||||
}
|
||||
else if (info.isFile())
|
||||
{
|
||||
OK &= QFile::remove(info.absoluteFilePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
OK = false;
|
||||
qCritical() << "Delete ERROR: Unknown filesystem object:" << info.absoluteFilePath();
|
||||
}
|
||||
}
|
||||
OK &= dir.rmdir(dir.absolutePath());
|
||||
return OK;
|
||||
return err.value() == 0;
|
||||
}
|
||||
|
||||
|
||||
QString PathCombine(const QString & path1, const QString & path2)
|
||||
bool trash(QString path, QString *pathInTrash = nullptr)
|
||||
{
|
||||
if(!path1.size())
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
return false;
|
||||
#else
|
||||
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
|
||||
if (DesktopServices::isFlatpak())
|
||||
return false;
|
||||
return QFile::moveToTrash(path, pathInTrash);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString PathCombine(const QString& path1, const QString& path2)
|
||||
{
|
||||
if (!path1.size())
|
||||
return path2;
|
||||
if(!path2.size())
|
||||
if (!path2.size())
|
||||
return path1;
|
||||
return QDir::cleanPath(path1 + QDir::separator() + path2);
|
||||
}
|
||||
|
||||
QString PathCombine(const QString & path1, const QString & path2, const QString & path3)
|
||||
QString PathCombine(const QString& path1, const QString& path2, const QString& path3)
|
||||
{
|
||||
return PathCombine(PathCombine(path1, path2), path3);
|
||||
}
|
||||
|
||||
QString PathCombine(const QString & path1, const QString & path2, const QString & path3, const QString & path4)
|
||||
QString PathCombine(const QString& path1, const QString& path2, const QString& path3, const QString& path4)
|
||||
{
|
||||
return PathCombine(PathCombine(path1, path2, path3), path4);
|
||||
}
|
||||
@ -259,17 +270,14 @@ QString AbsolutePath(QString path)
|
||||
|
||||
QString ResolveExecutable(QString path)
|
||||
{
|
||||
if (path.isEmpty())
|
||||
{
|
||||
if (path.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
if(!path.contains('/'))
|
||||
{
|
||||
if (!path.contains('/')) {
|
||||
path = QStandardPaths::findExecutable(path);
|
||||
}
|
||||
QFileInfo pathInfo(path);
|
||||
if(!pathInfo.exists() || !pathInfo.isExecutable())
|
||||
{
|
||||
if (!pathInfo.exists() || !pathInfo.isExecutable()) {
|
||||
return QString();
|
||||
}
|
||||
return pathInfo.absoluteFilePath();
|
||||
@ -289,12 +297,9 @@ QString NormalizePath(QString path)
|
||||
QDir b(path);
|
||||
QString newAbsolute = b.absolutePath();
|
||||
|
||||
if (newAbsolute.startsWith(currentAbsolute))
|
||||
{
|
||||
if (newAbsolute.startsWith(currentAbsolute)) {
|
||||
return a.relativeFilePath(newAbsolute);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return newAbsolute;
|
||||
}
|
||||
}
|
||||
@ -303,10 +308,8 @@ QString badFilenameChars = "\"\\/?<>:;*|!+\r\n";
|
||||
|
||||
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
||||
{
|
||||
for (int i = 0; i < string.length(); i++)
|
||||
{
|
||||
if (badFilenameChars.contains(string[i]))
|
||||
{
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
if (badFilenameChars.contains(string[i])) {
|
||||
string[i] = replaceWith;
|
||||
}
|
||||
}
|
||||
@ -318,15 +321,11 @@ QString DirNameFromString(QString string, QString inDir)
|
||||
int num = 0;
|
||||
QString baseName = RemoveInvalidFilenameChars(string, '-');
|
||||
QString dirName;
|
||||
do
|
||||
{
|
||||
if(num == 0)
|
||||
{
|
||||
do {
|
||||
if (num == 0) {
|
||||
dirName = baseName;
|
||||
}
|
||||
else
|
||||
{
|
||||
dirName = baseName + QString::number(num);;
|
||||
} else {
|
||||
dirName = baseName + "(" + QString::number(num) + ")";
|
||||
}
|
||||
|
||||
// If it's over 9000
|
||||
@ -345,63 +344,13 @@ bool checkProblemticPathJava(QDir folder)
|
||||
return pathfoldername.contains("!", Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
// Win32 crap
|
||||
#if defined Q_OS_WIN
|
||||
|
||||
bool called_coinit = false;
|
||||
|
||||
HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args)
|
||||
{
|
||||
HRESULT hres;
|
||||
|
||||
if (!called_coinit)
|
||||
{
|
||||
hres = CoInitialize(NULL);
|
||||
called_coinit = true;
|
||||
|
||||
if (!SUCCEEDED(hres))
|
||||
{
|
||||
qWarning("Failed to initialize COM. Error 0x%08lX", hres);
|
||||
return hres;
|
||||
}
|
||||
}
|
||||
|
||||
IShellLink *link;
|
||||
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
|
||||
(LPVOID *)&link);
|
||||
|
||||
if (SUCCEEDED(hres))
|
||||
{
|
||||
IPersistFile *persistFile;
|
||||
|
||||
link->SetPath(targetPath);
|
||||
link->SetArguments(args);
|
||||
|
||||
hres = link->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile);
|
||||
if (SUCCEEDED(hres))
|
||||
{
|
||||
WCHAR wstr[MAX_PATH];
|
||||
|
||||
MultiByteToWideChar(CP_ACP, 0, linkPath, -1, wstr, MAX_PATH);
|
||||
|
||||
hres = persistFile->Save(wstr, TRUE);
|
||||
persistFile->Release();
|
||||
}
|
||||
link->Release();
|
||||
}
|
||||
return hres;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
QString getDesktopDir()
|
||||
{
|
||||
return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
}
|
||||
|
||||
// Cross-platform Shortcut creation
|
||||
bool createShortCut(QString location, QString dest, QStringList args, QString name,
|
||||
QString icon)
|
||||
bool createShortCut(QString location, QString dest, QStringList args, QString name, QString icon)
|
||||
{
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
location = PathCombine(location, name + ".desktop");
|
||||
@ -426,8 +375,7 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na
|
||||
stream.flush();
|
||||
f.close();
|
||||
|
||||
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup |
|
||||
QFileDevice::ExeOther);
|
||||
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
|
||||
|
||||
return true;
|
||||
#elif defined Q_OS_WIN
|
||||
@ -454,4 +402,26 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool overrideFolder(QString overwritten_path, QString override_path)
|
||||
{
|
||||
using copy_opts = fs::copy_options;
|
||||
|
||||
if (!FS::ensureFolderPathExists(overwritten_path))
|
||||
return false;
|
||||
|
||||
std::error_code err;
|
||||
fs::copy_options opt = copy_opts::recursive | copy_opts::overwrite_existing;
|
||||
|
||||
// FIXME: hello traveller! Apparently std::copy does NOT overwrite existing files on GNU libstdc++ on Windows?
|
||||
fs::copy(toStdString(override_path), toStdString(overwritten_path), opt, err);
|
||||
|
||||
if (err) {
|
||||
qCritical() << QString("Failed to apply override from %1 to %2").arg(override_path, overwritten_path);
|
||||
qCritical() << "Reason:" << QString::fromStdString(err.message());
|
||||
}
|
||||
|
||||
return err.value() == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,37 @@
|
||||
// Licensed under the Apache-2.0 license. See README.md for details.
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -8,29 +41,27 @@
|
||||
#include <QDir>
|
||||
#include <QFlags>
|
||||
|
||||
namespace FS
|
||||
{
|
||||
namespace FS {
|
||||
|
||||
class FileSystemException : public ::Exception
|
||||
{
|
||||
public:
|
||||
FileSystemException(const QString &message) : Exception(message) {}
|
||||
class FileSystemException : public ::Exception {
|
||||
public:
|
||||
FileSystemException(const QString& message) : Exception(message) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* write data to a file safely
|
||||
*/
|
||||
void write(const QString &filename, const QByteArray &data);
|
||||
void write(const QString& filename, const QByteArray& data);
|
||||
|
||||
/**
|
||||
* read data from a file safely\
|
||||
*/
|
||||
QByteArray read(const QString &filename);
|
||||
QByteArray read(const QString& filename);
|
||||
|
||||
/**
|
||||
* Update the last changed timestamp of an existing file
|
||||
*/
|
||||
bool updateTimestamp(const QString & filename);
|
||||
bool updateTimestamp(const QString& filename);
|
||||
|
||||
/**
|
||||
* Creates all the folders in a path for the specified path
|
||||
@ -44,35 +75,31 @@ bool ensureFilePathExists(QString filenamepath);
|
||||
*/
|
||||
bool ensureFolderPathExists(QString filenamepath);
|
||||
|
||||
class copy
|
||||
{
|
||||
public:
|
||||
copy(const QString & src, const QString & dst)
|
||||
class copy {
|
||||
public:
|
||||
copy(const QString& src, const QString& dst)
|
||||
{
|
||||
m_src = src;
|
||||
m_dst = dst;
|
||||
m_src.setPath(src);
|
||||
m_dst.setPath(dst);
|
||||
}
|
||||
copy & followSymlinks(const bool follow)
|
||||
copy& followSymlinks(const bool follow)
|
||||
{
|
||||
m_followSymlinks = follow;
|
||||
return *this;
|
||||
}
|
||||
copy & blacklist(const IPathMatcher * filter)
|
||||
copy& blacklist(const IPathMatcher* filter)
|
||||
{
|
||||
m_blacklist = filter;
|
||||
return *this;
|
||||
}
|
||||
bool operator()()
|
||||
{
|
||||
return operator()(QString());
|
||||
}
|
||||
bool operator()() { return operator()(QString()); }
|
||||
|
||||
private:
|
||||
bool operator()(const QString &offset);
|
||||
private:
|
||||
bool operator()(const QString& offset);
|
||||
|
||||
private:
|
||||
private:
|
||||
bool m_followSymlinks = true;
|
||||
const IPathMatcher * m_blacklist = nullptr;
|
||||
const IPathMatcher* m_blacklist = nullptr;
|
||||
QDir m_src;
|
||||
QDir m_dst;
|
||||
};
|
||||
@ -82,9 +109,14 @@ private:
|
||||
*/
|
||||
bool deletePath(QString path);
|
||||
|
||||
QString PathCombine(const QString &path1, const QString &path2);
|
||||
QString PathCombine(const QString &path1, const QString &path2, const QString &path3);
|
||||
QString PathCombine(const QString &path1, const QString &path2, const QString &path3, const QString &path4);
|
||||
/**
|
||||
* Trash a folder / file
|
||||
*/
|
||||
bool trash(QString path, QString *pathInTrash);
|
||||
|
||||
QString PathCombine(const QString& path1, const QString& path2);
|
||||
QString PathCombine(const QString& path1, const QString& path2, const QString& path3);
|
||||
QString PathCombine(const QString& path1, const QString& path2, const QString& path3, const QString& path4);
|
||||
|
||||
QString AbsolutePath(QString path);
|
||||
|
||||
@ -120,8 +152,7 @@ bool checkProblemticPathJava(QDir folder);
|
||||
// Get the Directory representing the User's Desktop
|
||||
QString getDesktopDir();
|
||||
|
||||
// Create a shortcut at *location*, pointing to *dest* called with the arguments *args*
|
||||
// call it *name* and assign it the icon *icon*
|
||||
// return true if operation succeeded
|
||||
bool createShortCut(QString location, QString dest, QStringList args, QString name, QString iconLocation);
|
||||
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
|
||||
// Equivalent to doing QDir::rename, but allowing for overrides
|
||||
bool overrideFolder(QString overwritten_path, QString override_path);
|
||||
}
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "GZip.h"
|
||||
#include <zlib.h>
|
||||
#include <QByteArray>
|
||||
@ -37,7 +72,7 @@ bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedByte
|
||||
uncompLength *= 2;
|
||||
}
|
||||
|
||||
strm.next_out = (Bytef *)(uncompressedBytes.data() + strm.total_out);
|
||||
strm.next_out = reinterpret_cast<Bytef *>((uncompressedBytes.data() + strm.total_out));
|
||||
strm.avail_out = uncompLength - strm.total_out;
|
||||
|
||||
// Inflate another chunk.
|
||||
@ -67,7 +102,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned compLength = std::min(uncompressedBytes.size(), 16);
|
||||
unsigned compLength = qMin(uncompressedBytes.size(), 16);
|
||||
compressedBytes.clear();
|
||||
compressedBytes.resize(compLength);
|
||||
|
||||
@ -94,7 +129,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
|
||||
{
|
||||
compressedBytes.resize(compressedBytes.size() * 2);
|
||||
}
|
||||
zs.next_out = (Bytef *) (compressedBytes.data() + offset);
|
||||
zs.next_out = reinterpret_cast<Bytef*>((compressedBytes.data() + offset));
|
||||
temp = zs.avail_out = compressedBytes.size() - offset;
|
||||
ret = deflate(&zs, Z_FINISH);
|
||||
offset += temp - zs.avail_out;
|
||||
@ -112,4 +147,4 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
}
|
||||
void put(QByteArray input)
|
||||
{
|
||||
hoedown_buffer_put(buf, (uint8_t *) input.data(), input.size());
|
||||
hoedown_buffer_put(buf, reinterpret_cast<uint8_t *>(input.data()), input.size());
|
||||
}
|
||||
const uint8_t * data() const
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ void InstanceCopyTask::copyFinished()
|
||||
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
||||
|
||||
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
|
||||
inst->setName(m_instName);
|
||||
inst->setName(name());
|
||||
inst->setIconKey(m_instIcon);
|
||||
if(!m_keepPlaytime) {
|
||||
inst->resetTimePlayed();
|
||||
|
@ -1,40 +1,56 @@
|
||||
#include "InstanceCreationTask.h"
|
||||
#include "settings/INISettingsObject.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
//FIXME: remove this
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
||||
InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version)
|
||||
{
|
||||
m_version = version;
|
||||
m_usingLoader = false;
|
||||
}
|
||||
|
||||
InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion)
|
||||
{
|
||||
m_version = version;
|
||||
m_usingLoader = true;
|
||||
m_loader = loader;
|
||||
m_loaderVersion = loaderVersion;
|
||||
}
|
||||
InstanceCreationTask::InstanceCreationTask() = default;
|
||||
|
||||
void InstanceCreationTask::executeTask()
|
||||
{
|
||||
setStatus(tr("Creating instance from version %1").arg(m_version->name()));
|
||||
{
|
||||
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
||||
instanceSettings->suspendSave();
|
||||
MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath);
|
||||
auto components = inst.getPackProfile();
|
||||
components->buildingFromScratch();
|
||||
components->setComponentVersion("net.minecraft", m_version->descriptor(), true);
|
||||
if(m_usingLoader)
|
||||
components->setComponentVersion(m_loader, m_loaderVersion->descriptor());
|
||||
inst.setName(m_instName);
|
||||
inst.setIconKey(m_instIcon);
|
||||
instanceSettings->resumeSave();
|
||||
setAbortable(true);
|
||||
|
||||
if (updateInstance()) {
|
||||
emitSucceeded();
|
||||
return;
|
||||
}
|
||||
|
||||
// When the user aborted in the update stage.
|
||||
if (m_abort) {
|
||||
emitAborted();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!createInstance()) {
|
||||
if (m_abort)
|
||||
return;
|
||||
|
||||
qWarning() << "Instance creation failed!";
|
||||
if (!m_error_message.isEmpty())
|
||||
qWarning() << "Reason: " << m_error_message;
|
||||
emitFailed(tr("Error while creating new instance."));
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is set, it means we're updating an instance. So, we now need to remove the
|
||||
// files scheduled to, and we'd better not let the user abort in the middle of it, since it'd
|
||||
// put the instance in an invalid state.
|
||||
if (shouldOverride()) {
|
||||
setAbortable(false);
|
||||
setStatus(tr("Removing old conflicting files..."));
|
||||
qDebug() << "Removing old files";
|
||||
|
||||
for (auto path : m_files_to_remove) {
|
||||
if (!QFile::exists(path))
|
||||
continue;
|
||||
qDebug() << "Removing" << path;
|
||||
if (!QFile::remove(path)) {
|
||||
qCritical() << "Couldn't remove the old conflicting files.";
|
||||
emitFailed(tr("Failed to remove old conflicting files."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emitSucceeded();
|
||||
return;
|
||||
}
|
||||
|
@ -1,26 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "tasks/Task.h"
|
||||
#include "net/NetJob.h"
|
||||
#include <QUrl>
|
||||
#include "settings/SettingsObject.h"
|
||||
#include "BaseVersion.h"
|
||||
#include "InstanceTask.h"
|
||||
|
||||
class InstanceCreationTask : public InstanceTask
|
||||
{
|
||||
class InstanceCreationTask : public InstanceTask {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InstanceCreationTask(BaseVersionPtr version);
|
||||
explicit InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion);
|
||||
public:
|
||||
InstanceCreationTask();
|
||||
virtual ~InstanceCreationTask() = default;
|
||||
|
||||
protected:
|
||||
//! Entry point for tasks.
|
||||
virtual void executeTask() override;
|
||||
protected:
|
||||
void executeTask() final override;
|
||||
|
||||
private: /* data */
|
||||
BaseVersionPtr m_version;
|
||||
bool m_usingLoader;
|
||||
QString m_loader;
|
||||
BaseVersionPtr m_loaderVersion;
|
||||
/**
|
||||
* Tries to update an already existing instance.
|
||||
*
|
||||
* This can be implemented by subclasses to provide a way of updating an already existing
|
||||
* instance, according to that implementation's concept of 'identity' (i.e. instances that
|
||||
* are updates / downgrades of one another).
|
||||
*
|
||||
* If this returns true, createInstance() will not run, so you should do all update steps in here.
|
||||
* Otherwise, createInstance() is run as normal.
|
||||
*/
|
||||
virtual bool updateInstance() { return false; };
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* Returns whether the instance creation was successful (true) or not (false).
|
||||
*/
|
||||
virtual bool createInstance() { return false; };
|
||||
|
||||
QString getError() const { return m_error_message; }
|
||||
|
||||
protected:
|
||||
void setError(QString message) { m_error_message = message; };
|
||||
|
||||
protected:
|
||||
bool m_abort = false;
|
||||
|
||||
QStringList m_files_to_remove;
|
||||
|
||||
private:
|
||||
QString m_error_message;
|
||||
};
|
||||
|
@ -1,75 +1,103 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "InstanceImportTask.h"
|
||||
#include "BaseInstance.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "FileSystem.h"
|
||||
#include "MMCZip.h"
|
||||
#include "NullInstance.h"
|
||||
#include "settings/INISettingsObject.h"
|
||||
#include "icons/IconUtils.h"
|
||||
#include <QtConcurrentRun>
|
||||
|
||||
// FIXME: this does not belong here, it's Minecraft/Flame specific
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "modplatform/flame/FileResolvingTask.h"
|
||||
#include "modplatform/flame/PackManifest.h"
|
||||
#include "Json.h"
|
||||
#include <quazip/quazipdir.h>
|
||||
#include "modplatform/technic/TechnicPackProcessor.h"
|
||||
|
||||
#include "icons/IconList.h"
|
||||
#include "Application.h"
|
||||
#include "icons/IconUtils.h"
|
||||
|
||||
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl)
|
||||
#include "modplatform/technic/TechnicPackProcessor.h"
|
||||
#include "modplatform/modrinth/ModrinthInstanceCreationTask.h"
|
||||
#include "modplatform/flame/FlameInstanceCreationTask.h"
|
||||
|
||||
#include "settings/INISettingsObject.h"
|
||||
|
||||
#include <QtConcurrentRun>
|
||||
#include <algorithm>
|
||||
|
||||
#include <quazip/quazipdir.h>
|
||||
|
||||
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent)
|
||||
{
|
||||
m_sourceUrl = sourceUrl;
|
||||
m_parent = parent;
|
||||
}
|
||||
|
||||
bool InstanceImportTask::abort()
|
||||
{
|
||||
m_filesNetJob->abort();
|
||||
if (!canAbort())
|
||||
return false;
|
||||
|
||||
if (m_filesNetJob)
|
||||
m_filesNetJob->abort();
|
||||
m_extractFuture.cancel();
|
||||
|
||||
return false;
|
||||
return Task::abort();
|
||||
}
|
||||
|
||||
void InstanceImportTask::executeTask()
|
||||
{
|
||||
if (m_sourceUrl.isLocalFile())
|
||||
{
|
||||
setAbortable(true);
|
||||
|
||||
if (m_sourceUrl.isLocalFile()) {
|
||||
m_archivePath = m_sourceUrl.toLocalFile();
|
||||
processZipPack();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
|
||||
m_downloadRequired = true;
|
||||
|
||||
const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path();
|
||||
const QString path(m_sourceUrl.host() + '/' + m_sourceUrl.path());
|
||||
|
||||
auto entry = APPLICATION->metacache()->resolveEntry("general", path);
|
||||
entry->setStale(true);
|
||||
m_archivePath = entry->getFullPath();
|
||||
|
||||
m_filesNetJob = new NetJob(tr("Modpack download"), APPLICATION->network());
|
||||
m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry));
|
||||
m_archivePath = entry->getFullPath();
|
||||
auto job = m_filesNetJob.get();
|
||||
connect(job, &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
|
||||
connect(job, &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
|
||||
connect(job, &NetJob::failed, this, &InstanceImportTask::downloadFailed);
|
||||
|
||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
|
||||
connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
|
||||
connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
|
||||
connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
|
||||
|
||||
m_filesNetJob->start();
|
||||
}
|
||||
}
|
||||
@ -88,7 +116,13 @@ void InstanceImportTask::downloadFailed(QString reason)
|
||||
|
||||
void InstanceImportTask::downloadProgressChanged(qint64 current, qint64 total)
|
||||
{
|
||||
setProgress(current / 2, total);
|
||||
setProgress(current, total);
|
||||
}
|
||||
|
||||
void InstanceImportTask::downloadAborted()
|
||||
{
|
||||
emitAborted();
|
||||
m_filesNetJob.reset();
|
||||
}
|
||||
|
||||
void InstanceImportTask::processZipPack()
|
||||
@ -105,17 +139,20 @@ void InstanceImportTask::processZipPack()
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList blacklist = {"instance.cfg", "manifest.json"};
|
||||
QString mmcFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg");
|
||||
bool technicFound = QuaZipDir(m_packZip.get()).exists("/bin/modpack.jar") || QuaZipDir(m_packZip.get()).exists("/bin/version.json");
|
||||
QString flameFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json");
|
||||
QuaZipDir packZipDir(m_packZip.get());
|
||||
|
||||
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
|
||||
bool modrinthFound = packZipDir.exists("/modrinth.index.json");
|
||||
bool technicFound = packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json");
|
||||
QString root;
|
||||
if(!mmcFound.isNull())
|
||||
|
||||
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
|
||||
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
|
||||
if(modrinthFound)
|
||||
{
|
||||
// process as MultiMC instance/pack
|
||||
qDebug() << "MultiMC:" << mmcFound;
|
||||
root = mmcFound;
|
||||
m_modpackType = ModpackType::MultiMC;
|
||||
// process as Modrinth pack
|
||||
qDebug() << "Modrinth:" << modrinthFound;
|
||||
m_modpackType = ModpackType::Modrinth;
|
||||
}
|
||||
else if (technicFound)
|
||||
{
|
||||
@ -125,12 +162,25 @@ void InstanceImportTask::processZipPack()
|
||||
extractDir.cd(".minecraft");
|
||||
m_modpackType = ModpackType::Technic;
|
||||
}
|
||||
else if(!flameFound.isNull())
|
||||
else
|
||||
{
|
||||
// process as Flame pack
|
||||
qDebug() << "Flame:" << flameFound;
|
||||
root = flameFound;
|
||||
m_modpackType = ModpackType::Flame;
|
||||
QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg");
|
||||
QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json");
|
||||
|
||||
if (!mmcRoot.isNull())
|
||||
{
|
||||
// process as MultiMC instance/pack
|
||||
qDebug() << "MultiMC:" << mmcRoot;
|
||||
root = mmcRoot;
|
||||
m_modpackType = ModpackType::MultiMC;
|
||||
}
|
||||
else if(!flameRoot.isNull())
|
||||
{
|
||||
// process as Flame pack
|
||||
qDebug() << "Flame:" << flameRoot;
|
||||
root = flameRoot;
|
||||
m_modpackType = ModpackType::Flame;
|
||||
}
|
||||
}
|
||||
if(m_modpackType == ModpackType::Unknown)
|
||||
{
|
||||
@ -188,15 +238,18 @@ void InstanceImportTask::extractFinished()
|
||||
|
||||
switch(m_modpackType)
|
||||
{
|
||||
case ModpackType::Flame:
|
||||
processFlame();
|
||||
return;
|
||||
case ModpackType::MultiMC:
|
||||
processMultiMC();
|
||||
return;
|
||||
case ModpackType::Technic:
|
||||
processTechnic();
|
||||
return;
|
||||
case ModpackType::Flame:
|
||||
processFlame();
|
||||
return;
|
||||
case ModpackType::Modrinth:
|
||||
processModrinth();
|
||||
return;
|
||||
case ModpackType::Unknown:
|
||||
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
||||
return;
|
||||
@ -205,216 +258,31 @@ void InstanceImportTask::extractFinished()
|
||||
|
||||
void InstanceImportTask::extractAborted()
|
||||
{
|
||||
emitFailed(tr("Instance import has been aborted."));
|
||||
return;
|
||||
emitAborted();
|
||||
}
|
||||
|
||||
void InstanceImportTask::processFlame()
|
||||
{
|
||||
const static QMap<QString,QString> forgemap = {
|
||||
{"1.2.5", "3.4.9.171"},
|
||||
{"1.4.2", "6.0.1.355"},
|
||||
{"1.4.7", "6.6.2.534"},
|
||||
{"1.5.2", "7.8.1.737"}
|
||||
};
|
||||
Flame::Manifest pack;
|
||||
try
|
||||
{
|
||||
QString configPath = FS::PathCombine(m_stagingPath, "manifest.json");
|
||||
Flame::loadManifest(pack, configPath);
|
||||
QFile::remove(configPath);
|
||||
}
|
||||
catch (const JSONValidationError &e)
|
||||
{
|
||||
emitFailed(tr("Could not understand pack manifest:\n") + e.cause());
|
||||
return;
|
||||
}
|
||||
if(!pack.overrides.isEmpty())
|
||||
{
|
||||
QString overridePath = FS::PathCombine(m_stagingPath, pack.overrides);
|
||||
if (QFile::exists(overridePath))
|
||||
{
|
||||
QString mcPath = FS::PathCombine(m_stagingPath, "minecraft");
|
||||
if (!QFile::rename(overridePath, mcPath))
|
||||
{
|
||||
emitFailed(tr("Could not rename the overrides folder:\n") + pack.overrides);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logWarning(tr("The specified overrides folder (%1) is missing. Maybe the modpack was already used before?").arg(pack.overrides));
|
||||
}
|
||||
}
|
||||
auto* inst_creation_task = new FlameCreationTask(m_stagingPath, m_globalSettings, m_parent);
|
||||
|
||||
QString forgeVersion;
|
||||
QString fabricVersion;
|
||||
// TODO: is Quilt relevant here?
|
||||
for(auto &loader: pack.minecraft.modLoaders)
|
||||
{
|
||||
auto id = loader.id;
|
||||
if(id.startsWith("forge-"))
|
||||
{
|
||||
id.remove("forge-");
|
||||
forgeVersion = id;
|
||||
continue;
|
||||
}
|
||||
if(id.startsWith("fabric-"))
|
||||
{
|
||||
id.remove("fabric-");
|
||||
fabricVersion = id;
|
||||
continue;
|
||||
}
|
||||
logWarning(tr("Unknown mod loader in manifest: %1").arg(id));
|
||||
}
|
||||
|
||||
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
||||
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
||||
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
||||
auto mcVersion = pack.minecraft.version;
|
||||
// Hack to correct some 'special sauce'...
|
||||
if(mcVersion.endsWith('.'))
|
||||
{
|
||||
mcVersion.remove(QRegExp("[.]+$"));
|
||||
logWarning(tr("Mysterious trailing dots removed from Minecraft version while importing pack."));
|
||||
}
|
||||
auto components = instance.getPackProfile();
|
||||
components->buildingFromScratch();
|
||||
components->setComponentVersion("net.minecraft", mcVersion, true);
|
||||
if(!forgeVersion.isEmpty())
|
||||
{
|
||||
// FIXME: dirty, nasty, hack. Proper solution requires dependency resolution and knowledge of the metadata.
|
||||
if(forgeVersion == "recommended")
|
||||
{
|
||||
if(forgemap.contains(mcVersion))
|
||||
{
|
||||
forgeVersion = forgemap[mcVersion];
|
||||
}
|
||||
else
|
||||
{
|
||||
logWarning(tr("Could not map recommended Forge version for Minecraft %1").arg(mcVersion));
|
||||
}
|
||||
}
|
||||
components->setComponentVersion("net.minecraftforge", forgeVersion);
|
||||
}
|
||||
if(!fabricVersion.isEmpty())
|
||||
{
|
||||
components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion);
|
||||
}
|
||||
if (m_instIcon != "default")
|
||||
{
|
||||
instance.setIconKey(m_instIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(pack.name.contains("Direwolf20"))
|
||||
{
|
||||
instance.setIconKey("steve");
|
||||
}
|
||||
else if(pack.name.contains("FTB") || pack.name.contains("Feed The Beast"))
|
||||
{
|
||||
instance.setIconKey("ftb_logo");
|
||||
}
|
||||
else
|
||||
{
|
||||
// default to something other than the MultiMC default to distinguish these
|
||||
instance.setIconKey("flame");
|
||||
}
|
||||
}
|
||||
QString jarmodsPath = FS::PathCombine(m_stagingPath, "minecraft", "jarmods");
|
||||
QFileInfo jarmodsInfo(jarmodsPath);
|
||||
if(jarmodsInfo.isDir())
|
||||
{
|
||||
// install all the jar mods
|
||||
qDebug() << "Found jarmods:";
|
||||
QDir jarmodsDir(jarmodsPath);
|
||||
QStringList jarMods;
|
||||
for (auto info: jarmodsDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files))
|
||||
{
|
||||
qDebug() << info.fileName();
|
||||
jarMods.push_back(info.absoluteFilePath());
|
||||
}
|
||||
auto profile = instance.getPackProfile();
|
||||
profile->installJarMods(jarMods);
|
||||
// nuke the original files
|
||||
FS::deletePath(jarmodsPath);
|
||||
}
|
||||
instance.setName(m_instName);
|
||||
m_modIdResolver = new Flame::FileResolvingTask(APPLICATION->network(), pack);
|
||||
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::succeeded, [&]()
|
||||
{
|
||||
auto results = m_modIdResolver->getResults();
|
||||
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
|
||||
for(auto result: results.files)
|
||||
{
|
||||
QString filename = result.fileName;
|
||||
if(!result.required)
|
||||
{
|
||||
filename += ".disabled";
|
||||
}
|
||||
|
||||
auto relpath = FS::PathCombine("minecraft", result.targetFolder, filename);
|
||||
auto path = FS::PathCombine(m_stagingPath , relpath);
|
||||
|
||||
switch(result.type)
|
||||
{
|
||||
case Flame::File::Type::Folder:
|
||||
{
|
||||
logWarning(tr("This 'Folder' may need extracting: %1").arg(relpath));
|
||||
// fall-through intentional, we treat these as plain old mods and dump them wherever.
|
||||
}
|
||||
case Flame::File::Type::SingleFile:
|
||||
case Flame::File::Type::Mod:
|
||||
{
|
||||
qDebug() << "Will download" << result.url << "to" << path;
|
||||
auto dl = Net::Download::makeFile(result.url, path);
|
||||
m_filesNetJob->addNetAction(dl);
|
||||
break;
|
||||
}
|
||||
case Flame::File::Type::Modpack:
|
||||
logWarning(tr("Nesting modpacks in modpacks is not implemented, nothing was downloaded: %1").arg(relpath));
|
||||
break;
|
||||
case Flame::File::Type::Cmod2:
|
||||
case Flame::File::Type::Ctoc:
|
||||
case Flame::File::Type::Unknown:
|
||||
logWarning(tr("Unrecognized/unhandled PackageType for: %1").arg(relpath));
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_modIdResolver.reset();
|
||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]()
|
||||
{
|
||||
m_filesNetJob.reset();
|
||||
emitSucceeded();
|
||||
}
|
||||
);
|
||||
connect(m_filesNetJob.get(), &NetJob::failed, [&](QString reason)
|
||||
{
|
||||
m_filesNetJob.reset();
|
||||
emitFailed(reason);
|
||||
});
|
||||
connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total)
|
||||
{
|
||||
setProgress(current, total);
|
||||
});
|
||||
setStatus(tr("Downloading mods..."));
|
||||
m_filesNetJob->start();
|
||||
}
|
||||
);
|
||||
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::failed, [&](QString reason)
|
||||
{
|
||||
m_modIdResolver.reset();
|
||||
emitFailed(tr("Unable to resolve mod IDs:\n") + reason);
|
||||
inst_creation_task->setName(*this);
|
||||
inst_creation_task->setIcon(m_instIcon);
|
||||
inst_creation_task->setGroup(m_instGroup);
|
||||
|
||||
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
||||
setOverride(inst_creation_task->shouldOverride());
|
||||
emitSucceeded();
|
||||
});
|
||||
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::progress, [&](qint64 current, qint64 total)
|
||||
{
|
||||
setProgress(current, total);
|
||||
});
|
||||
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::status, [&](QString status)
|
||||
{
|
||||
setStatus(status);
|
||||
});
|
||||
m_modIdResolver->start();
|
||||
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
||||
connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
|
||||
connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
|
||||
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);
|
||||
|
||||
connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort);
|
||||
connect(inst_creation_task, &Task::aborted, this, &Task::abort);
|
||||
connect(inst_creation_task, &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||
|
||||
inst_creation_task->start();
|
||||
}
|
||||
|
||||
void InstanceImportTask::processTechnic()
|
||||
@ -422,7 +290,7 @@ void InstanceImportTask::processTechnic()
|
||||
shared_qobject_ptr<Technic::TechnicPackProcessor> packProcessor = new Technic::TechnicPackProcessor();
|
||||
connect(packProcessor.get(), &Technic::TechnicPackProcessor::succeeded, this, &InstanceImportTask::emitSucceeded);
|
||||
connect(packProcessor.get(), &Technic::TechnicPackProcessor::failed, this, &InstanceImportTask::emitFailed);
|
||||
packProcessor->run(m_globalSettings, m_instName, m_instIcon, m_stagingPath);
|
||||
packProcessor->run(m_globalSettings, name(), m_instIcon, m_stagingPath);
|
||||
}
|
||||
|
||||
void InstanceImportTask::processMultiMC()
|
||||
@ -436,28 +304,47 @@ void InstanceImportTask::processMultiMC()
|
||||
instance.resetTimePlayed();
|
||||
|
||||
// set a new nice name
|
||||
instance.setName(m_instName);
|
||||
instance.setName(name());
|
||||
|
||||
// if the icon was specified by user, use that. otherwise pull icon from the pack
|
||||
if (m_instIcon != "default")
|
||||
{
|
||||
if (m_instIcon != "default") {
|
||||
instance.setIconKey(m_instIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
m_instIcon = instance.iconKey();
|
||||
|
||||
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
|
||||
if (!importIconPath.isNull() && QFile::exists(importIconPath))
|
||||
{
|
||||
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
|
||||
// import icon
|
||||
auto iconList = APPLICATION->icons();
|
||||
if (iconList->iconFileExists(m_instIcon))
|
||||
{
|
||||
if (iconList->iconFileExists(m_instIcon)) {
|
||||
iconList->deleteIcon(m_instIcon);
|
||||
}
|
||||
iconList->installIcons({importIconPath});
|
||||
iconList->installIcons({ importIconPath });
|
||||
}
|
||||
}
|
||||
emitSucceeded();
|
||||
}
|
||||
|
||||
void InstanceImportTask::processModrinth()
|
||||
{
|
||||
auto* inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, m_sourceUrl.toString());
|
||||
|
||||
inst_creation_task->setName(*this);
|
||||
inst_creation_task->setIcon(m_instIcon);
|
||||
inst_creation_task->setGroup(m_instGroup);
|
||||
|
||||
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
||||
setOverride(inst_creation_task->shouldOverride());
|
||||
emitSucceeded();
|
||||
});
|
||||
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
||||
connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
|
||||
connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
|
||||
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);
|
||||
|
||||
connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort);
|
||||
connect(inst_creation_task, &Task::aborted, this, &Task::abort);
|
||||
connect(inst_creation_task, &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||
|
||||
inst_creation_task->start();
|
||||
}
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -22,8 +42,9 @@
|
||||
#include <QFutureWatcher>
|
||||
#include "settings/SettingsObject.h"
|
||||
#include "QObjectPtr.h"
|
||||
#include "modplatform/flame/PackManifest.h"
|
||||
|
||||
#include <nonstd/optional>
|
||||
#include <optional>
|
||||
|
||||
class QuaZip;
|
||||
namespace Flame
|
||||
@ -35,10 +56,13 @@ class InstanceImportTask : public InstanceTask
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InstanceImportTask(const QUrl sourceUrl);
|
||||
explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr);
|
||||
|
||||
bool canAbort() const override { return true; }
|
||||
bool abort() override;
|
||||
const QVector<Flame::File> &getBlockedFiles() const
|
||||
{
|
||||
return m_blockedMods;
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Entry point for tasks.
|
||||
@ -47,13 +71,15 @@ protected:
|
||||
private:
|
||||
void processZipPack();
|
||||
void processMultiMC();
|
||||
void processFlame();
|
||||
void processTechnic();
|
||||
void processFlame();
|
||||
void processModrinth();
|
||||
|
||||
private slots:
|
||||
void downloadSucceeded();
|
||||
void downloadFailed(QString reason);
|
||||
void downloadProgressChanged(qint64 current, qint64 total);
|
||||
void downloadAborted();
|
||||
void extractFinished();
|
||||
void extractAborted();
|
||||
|
||||
@ -64,12 +90,17 @@ private: /* data */
|
||||
QString m_archivePath;
|
||||
bool m_downloadRequired = false;
|
||||
std::unique_ptr<QuaZip> m_packZip;
|
||||
QFuture<nonstd::optional<QStringList>> m_extractFuture;
|
||||
QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
|
||||
QFuture<std::optional<QStringList>> m_extractFuture;
|
||||
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
|
||||
QVector<Flame::File> m_blockedMods;
|
||||
enum class ModpackType{
|
||||
Unknown,
|
||||
MultiMC,
|
||||
Technic,
|
||||
Flame,
|
||||
Technic
|
||||
Modrinth,
|
||||
} m_modpackType = ModpackType::Unknown;
|
||||
|
||||
//FIXME: nuke
|
||||
QWidget* m_parent;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,13 +19,15 @@
|
||||
#include <QAbstractListModel>
|
||||
#include <QSet>
|
||||
#include <QList>
|
||||
#include <QStack>
|
||||
#include <QPair>
|
||||
|
||||
#include "BaseInstance.h"
|
||||
|
||||
#include "QObjectPtr.h"
|
||||
|
||||
class QFileSystemWatcher;
|
||||
class InstanceTask;
|
||||
struct InstanceName;
|
||||
|
||||
using InstanceId = QString;
|
||||
using GroupId = QString;
|
||||
using InstanceLocator = std::pair<InstancePtr, int>;
|
||||
@ -46,6 +48,12 @@ enum class GroupsState
|
||||
Dirty
|
||||
};
|
||||
|
||||
struct TrashHistoryItem {
|
||||
QString id;
|
||||
QString polyPath;
|
||||
QString trashPath;
|
||||
QString groupName;
|
||||
};
|
||||
|
||||
class InstanceList : public QAbstractListModel
|
||||
{
|
||||
@ -93,7 +101,10 @@ public:
|
||||
InstListError loadList();
|
||||
void saveNow();
|
||||
|
||||
/* O(n) */
|
||||
InstancePtr getInstanceById(QString id) const;
|
||||
/* O(n) */
|
||||
InstancePtr getInstanceByManagedName(const QString& managed_name) const;
|
||||
QModelIndex getInstanceIndexById(const QString &id) const;
|
||||
QStringList getGroups();
|
||||
bool isGroupCollapsed(const QString &groupName);
|
||||
@ -102,6 +113,9 @@ public:
|
||||
void setInstanceGroup(const InstanceId & id, const GroupId& name);
|
||||
|
||||
void deleteGroup(const GroupId & name);
|
||||
bool trashInstance(const InstanceId &id);
|
||||
bool trashedSomething();
|
||||
void undoTrashInstance();
|
||||
void deleteInstance(const InstanceId & id);
|
||||
|
||||
// Wrap an instance creation task in some more task machinery and make it ready to be used
|
||||
@ -116,8 +130,10 @@ public:
|
||||
/**
|
||||
* Commit the staging area given by @keyPath to the provider - used when creation succeeds.
|
||||
* Used by instance manipulation tasks.
|
||||
* should_override is used when another similar instance already exists, and we want to override it
|
||||
* - for instance, when updating it.
|
||||
*/
|
||||
bool commitStagedInstance(const QString & keyPath, const QString& instanceName, const QString & groupName);
|
||||
bool commitStagedInstance(const QString& keyPath, const InstanceName& instanceName, const QString& groupName, bool should_override);
|
||||
|
||||
/**
|
||||
* Destroy a previously created staging area given by @keyPath - used when creation fails.
|
||||
@ -180,4 +196,6 @@ private:
|
||||
QSet<InstanceId> instanceSet;
|
||||
bool m_groupsLoaded = false;
|
||||
bool m_instancesProbed = false;
|
||||
|
||||
QStack<TrashHistoryItem> m_trashHistory;
|
||||
};
|
||||
|
@ -33,13 +33,13 @@ public:
|
||||
values.append(new LogPage(inst));
|
||||
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
||||
values.append(new VersionPage(onesix.get()));
|
||||
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
|
||||
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
|
||||
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
|
||||
values.append(modsPage);
|
||||
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
|
||||
values.append(new ResourcePackPage(onesix.get()));
|
||||
values.append(new TexturePackPage(onesix.get()));
|
||||
values.append(new ShaderPackPage(onesix.get()));
|
||||
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList()));
|
||||
values.append(new ResourcePackPage(onesix.get(), onesix->resourcePackList()));
|
||||
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
|
||||
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
|
||||
values.append(new NotesPage(onesix.get()));
|
||||
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
|
||||
values.append(new ServersPage(onesix));
|
||||
|
@ -1,9 +1,52 @@
|
||||
#include "InstanceTask.h"
|
||||
|
||||
InstanceTask::InstanceTask()
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
|
||||
InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name)
|
||||
{
|
||||
auto dialog =
|
||||
CustomMessageBox::selectable(parent, QObject::tr("Change instance name"),
|
||||
QObject::tr("The instance's name seems to include the old version. Would you like to update it?\n\n"
|
||||
"Old name: %1\n"
|
||||
"New name: %2")
|
||||
.arg(old_name, new_name),
|
||||
QMessageBox::Question, QMessageBox::No | QMessageBox::Yes);
|
||||
auto result = dialog->exec();
|
||||
|
||||
if (result == QMessageBox::Yes)
|
||||
return InstanceNameChange::ShouldChange;
|
||||
return InstanceNameChange::ShouldKeep;
|
||||
}
|
||||
|
||||
InstanceTask::~InstanceTask()
|
||||
QString InstanceName::name() const
|
||||
{
|
||||
if (!m_modified_name.isEmpty())
|
||||
return modifiedName();
|
||||
return QString("%1 %2").arg(m_original_name, m_original_version);
|
||||
}
|
||||
|
||||
QString InstanceName::originalName() const
|
||||
{
|
||||
return m_original_name;
|
||||
}
|
||||
|
||||
QString InstanceName::modifiedName() const
|
||||
{
|
||||
if (!m_modified_name.isEmpty())
|
||||
return m_modified_name;
|
||||
return m_original_name;
|
||||
}
|
||||
|
||||
QString InstanceName::version() const
|
||||
{
|
||||
return m_original_version;
|
||||
}
|
||||
|
||||
void InstanceName::setName(InstanceName& other)
|
||||
{
|
||||
m_original_name = other.m_original_name;
|
||||
m_original_version = other.m_original_version;
|
||||
m_modified_name = other.m_modified_name;
|
||||
}
|
||||
|
||||
InstanceTask::InstanceTask() : Task(), InstanceName() {}
|
||||
|
@ -1,52 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include "tasks/Task.h"
|
||||
#include "settings/SettingsObject.h"
|
||||
#include "tasks/Task.h"
|
||||
|
||||
class InstanceTask : public Task
|
||||
{
|
||||
/* Helpers */
|
||||
enum class InstanceNameChange { ShouldChange, ShouldKeep };
|
||||
[[nodiscard]] InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name);
|
||||
|
||||
struct InstanceName {
|
||||
public:
|
||||
InstanceName() = default;
|
||||
InstanceName(QString name, QString version) : m_original_name(std::move(name)), m_original_version(std::move(version)) {}
|
||||
|
||||
[[nodiscard]] QString modifiedName() const;
|
||||
[[nodiscard]] QString originalName() const;
|
||||
[[nodiscard]] QString name() const;
|
||||
[[nodiscard]] QString version() const;
|
||||
|
||||
void setName(QString name) { m_modified_name = name; }
|
||||
void setName(InstanceName& other);
|
||||
|
||||
protected:
|
||||
QString m_original_name;
|
||||
QString m_original_version;
|
||||
|
||||
QString m_modified_name;
|
||||
};
|
||||
|
||||
class InstanceTask : public Task, public InstanceName {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InstanceTask();
|
||||
virtual ~InstanceTask();
|
||||
public:
|
||||
InstanceTask();
|
||||
~InstanceTask() override = default;
|
||||
|
||||
void setParentSettings(SettingsObjectPtr settings)
|
||||
{
|
||||
m_globalSettings = settings;
|
||||
}
|
||||
void setParentSettings(SettingsObjectPtr settings) { m_globalSettings = settings; }
|
||||
|
||||
void setStagingPath(const QString &stagingPath)
|
||||
{
|
||||
m_stagingPath = stagingPath;
|
||||
}
|
||||
void setStagingPath(const QString& stagingPath) { m_stagingPath = stagingPath; }
|
||||
|
||||
void setName(const QString &name)
|
||||
{
|
||||
m_instName = name;
|
||||
}
|
||||
QString name() const
|
||||
{
|
||||
return m_instName;
|
||||
}
|
||||
void setIcon(const QString& icon) { m_instIcon = icon; }
|
||||
|
||||
void setIcon(const QString &icon)
|
||||
{
|
||||
m_instIcon = icon;
|
||||
}
|
||||
void setGroup(const QString& group) { m_instGroup = group; }
|
||||
QString group() const { return m_instGroup; }
|
||||
|
||||
void setGroup(const QString &group)
|
||||
{
|
||||
m_instGroup = group;
|
||||
}
|
||||
QString group() const
|
||||
{
|
||||
return m_instGroup;
|
||||
}
|
||||
bool shouldOverride() const { return m_override_existing; }
|
||||
|
||||
protected: /* data */
|
||||
protected:
|
||||
void setOverride(bool override) { m_override_existing = override; }
|
||||
|
||||
protected: /* data */
|
||||
SettingsObjectPtr m_globalSettings;
|
||||
QString m_instName;
|
||||
QString m_instIcon;
|
||||
QString m_instGroup;
|
||||
QString m_stagingPath;
|
||||
|
||||
bool m_override_existing = false;
|
||||
};
|
||||
|
@ -1,10 +1,47 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "JavaCommon.h"
|
||||
#include "java/JavaUtils.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include <MMCStrings.h>
|
||||
#include <QRegularExpression>
|
||||
|
||||
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
|
||||
{
|
||||
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))
|
||||
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]"))
|
||||
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
|
||||
{
|
||||
auto warnStr = QObject::tr(
|
||||
@ -18,7 +55,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
|
||||
return false;
|
||||
}
|
||||
// block lunacy with passing required version to the JVM
|
||||
if (jvmargs.contains(QRegExp("-version:.*"))) {
|
||||
if (jvmargs.contains(QRegularExpression("-version:.*"))) {
|
||||
auto warnStr = QObject::tr(
|
||||
"You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be allowed.\n"
|
||||
"This message will be displayed until you remove this from the JVM arguments.");
|
||||
@ -65,6 +102,13 @@ void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result)
|
||||
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
||||
}
|
||||
|
||||
void JavaCommon::javaCheckNotFound(QWidget *parent)
|
||||
{
|
||||
QString text;
|
||||
text += QObject::tr("Java checker library could not be found. Please check your installation.");
|
||||
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
||||
}
|
||||
|
||||
void JavaCommon::TestCheck::run()
|
||||
{
|
||||
if (!JavaCommon::checkJVMArgs(m_args, m_parent))
|
||||
@ -72,6 +116,11 @@ void JavaCommon::TestCheck::run()
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
if (JavaUtils::getJavaCheckPath().isEmpty()) {
|
||||
javaCheckNotFound(m_parent);
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
checker.reset(new JavaChecker());
|
||||
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
|
||||
SLOT(checkFinished(JavaCheckResult)));
|
||||
|
@ -10,12 +10,14 @@ namespace JavaCommon
|
||||
{
|
||||
bool checkJVMArgs(QString args, QWidget *parent);
|
||||
|
||||
// Show a dialog saying that the Java binary was not usable
|
||||
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
|
||||
// Show a dialog saying that the Java binary was not usable because of bad options
|
||||
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
|
||||
// Show a dialog saying that the Java binary was usable
|
||||
void javaWasOk(QWidget *parent, JavaCheckResult result);
|
||||
// Show a dialog saying that the Java binary was not usable because of bad options
|
||||
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
|
||||
// Show a dialog saying that the Java binary was not usable
|
||||
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
|
||||
// Show a dialog if we couldn't find Java Checker
|
||||
void javaCheckNotFound(QWidget *parent);
|
||||
|
||||
class TestCheck : public QObject
|
||||
{
|
||||
|
@ -1,4 +1,37 @@
|
||||
// Licensed under the Apache-2.0 license. See README.md for details.
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Json.h"
|
||||
|
||||
@ -22,14 +55,6 @@ void write(const QJsonArray &array, const QString &filename)
|
||||
write(QJsonDocument(array), filename);
|
||||
}
|
||||
|
||||
QByteArray toBinary(const QJsonObject &obj)
|
||||
{
|
||||
return QJsonDocument(obj).toBinaryData();
|
||||
}
|
||||
QByteArray toBinary(const QJsonArray &array)
|
||||
{
|
||||
return QJsonDocument(array).toBinaryData();
|
||||
}
|
||||
QByteArray toText(const QJsonObject &obj)
|
||||
{
|
||||
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||
@ -48,12 +73,8 @@ QJsonDocument requireDocument(const QByteArray &data, const QString &what)
|
||||
{
|
||||
if (isBinaryJson(data))
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromBinaryData(data);
|
||||
if (doc.isNull())
|
||||
{
|
||||
throw JsonException(what + ": Invalid JSON (binary JSON detected)");
|
||||
}
|
||||
return doc;
|
||||
// FIXME: Is this needed?
|
||||
throw JsonException(what + ": Invalid JSON. Binary JSON unsupported");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,4 +1,37 @@
|
||||
// Licensed under the Apache-2.0 license. See README.md for details.
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -29,8 +62,6 @@ void write(const QJsonObject &object, const QString &filename);
|
||||
/// @throw FileSystemException
|
||||
void write(const QJsonArray &array, const QString &filename);
|
||||
|
||||
QByteArray toBinary(const QJsonObject &obj);
|
||||
QByteArray toBinary(const QJsonArray &array);
|
||||
QByteArray toText(const QJsonObject &obj);
|
||||
QByteArray toText(const QJsonArray &array);
|
||||
|
||||
|
@ -93,8 +93,8 @@ void LaunchController::decideAccount()
|
||||
auto reply = CustomMessageBox::selectable(
|
||||
m_parentWidget,
|
||||
tr("No Accounts"),
|
||||
tr("In order to play Minecraft, you must have at least one Mojang or Minecraft "
|
||||
"account logged in. "
|
||||
tr("In order to play Minecraft, you must have at least one Microsoft or Mojang "
|
||||
"account logged in. Mojang accounts can only be used offline. "
|
||||
"Would you like to open the account manager to add an account now?"),
|
||||
QMessageBox::Information,
|
||||
QMessageBox::Yes | QMessageBox::No
|
||||
@ -105,6 +105,11 @@ void LaunchController::decideAccount()
|
||||
// Open the account manager.
|
||||
APPLICATION->ShowGlobalSettings(m_parentWidget, "accounts");
|
||||
}
|
||||
else if (reply == QMessageBox::No)
|
||||
{
|
||||
// Do not open "profile select" dialog.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_accountToUse = accounts->defaultAccount();
|
||||
@ -140,18 +145,29 @@ void LaunchController::login() {
|
||||
return;
|
||||
}
|
||||
|
||||
// we try empty password first :)
|
||||
QString password;
|
||||
// we loop until the user succeeds in logging in or gives up
|
||||
bool tryagain = true;
|
||||
// the failure. the default failure.
|
||||
const QString needLoginAgain = tr("Your account is currently not logged in. Please enter your password to log in again. <br /> <br /> This could be caused by a password change.");
|
||||
QString failReason = needLoginAgain;
|
||||
unsigned int tries = 0;
|
||||
|
||||
while (tryagain)
|
||||
{
|
||||
if (tries > 0 && tries % 3 == 0) {
|
||||
auto result = QMessageBox::question(
|
||||
m_parentWidget,
|
||||
tr("Continue launch?"),
|
||||
tr("It looks like we couldn't launch after %1 tries. Do you want to continue trying?")
|
||||
.arg(tries)
|
||||
);
|
||||
|
||||
if (result == QMessageBox::No) {
|
||||
emitAborted();
|
||||
return;
|
||||
}
|
||||
}
|
||||
tries++;
|
||||
m_session = std::make_shared<AuthSession>();
|
||||
m_session->wants_online = m_online;
|
||||
m_session->demo = m_demo;
|
||||
m_accountToUse->fillSession(m_session);
|
||||
|
||||
// Launch immediately in true offline mode
|
||||
@ -169,12 +185,18 @@ void LaunchController::login() {
|
||||
if(!m_session->wants_online) {
|
||||
// we ask the user for a player name
|
||||
bool ok = false;
|
||||
|
||||
QString message = tr("Choose your offline mode player name.");
|
||||
if(m_session->demo) {
|
||||
message = tr("Choose your demo mode player name.");
|
||||
}
|
||||
|
||||
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
||||
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
|
||||
QString name = QInputDialog::getText(
|
||||
m_parentWidget,
|
||||
tr("Player name"),
|
||||
tr("Choose your offline mode player name."),
|
||||
message,
|
||||
QLineEdit::Normal,
|
||||
usedname,
|
||||
&ok
|
||||
@ -354,13 +376,13 @@ void LaunchController::launchInstance()
|
||||
}
|
||||
m_launcher->prependStep(new TextPrint(m_launcher.get(), resolved_servers, MessageLevel::Launcher));
|
||||
} else {
|
||||
online_mode = "offline";
|
||||
online_mode = m_demo ? "demo" : "offline";
|
||||
}
|
||||
|
||||
m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
|
||||
|
||||
// Prepend Version
|
||||
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_NAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
|
||||
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_DISPLAYNAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
|
||||
m_launcher->start();
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,10 @@ public:
|
||||
m_online = online;
|
||||
}
|
||||
|
||||
void setDemo(bool demo) {
|
||||
m_demo = demo;
|
||||
}
|
||||
|
||||
void setProfiler(BaseProfilerFactory *profiler) {
|
||||
m_profiler = profiler;
|
||||
}
|
||||
@ -101,6 +105,7 @@ private slots:
|
||||
private:
|
||||
BaseProfilerFactory *m_profiler = nullptr;
|
||||
bool m_online = true;
|
||||
bool m_demo = false;
|
||||
InstancePtr m_instance;
|
||||
QWidget * m_parentWidget = nullptr;
|
||||
InstanceWindow *m_console = nullptr;
|
||||
|
@ -18,13 +18,17 @@ LAUNCHER_NAME=@Launcher_APP_BINARY_NAME@
|
||||
LAUNCHER_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
echo "Launcher Dir: ${LAUNCHER_DIR}"
|
||||
|
||||
# Set up env - filter out input LD_ variables but pass them in under different names
|
||||
export GAME_LIBRARY_PATH=${GAME_LIBRARY_PATH-${LD_LIBRARY_PATH}}
|
||||
export GAME_PRELOAD=${GAME_PRELOAD-${LD_PRELOAD}}
|
||||
export LD_LIBRARY_PATH="${LAUNCHER_DIR}/lib@LIB_SUFFIX@":$LAUNCHER_LIBRARY_PATH
|
||||
export LD_PRELOAD=$LAUNCHER_PRELOAD
|
||||
export QT_PLUGIN_PATH="${LAUNCHER_DIR}/plugins"
|
||||
export QT_FONTPATH="${LAUNCHER_DIR}/fonts"
|
||||
# Set up env.
|
||||
# Pass our custom variables separately so that the launcher can remove them for child processes
|
||||
export LAUNCHER_LD_LIBRARY_PATH="${LAUNCHER_DIR}/lib@LIB_SUFFIX@"
|
||||
export LAUNCHER_LD_PRELOAD=""
|
||||
export LAUNCHER_QT_PLUGIN_PATH="${LAUNCHER_DIR}/plugins"
|
||||
export LAUNCHER_QT_FONTPATH="${LAUNCHER_DIR}/fonts"
|
||||
|
||||
export LD_LIBRARY_PATH="$LAUNCHER_LD_LIBRARY_PATH:$LD_LIBRARY_PATH"
|
||||
export LD_PRELOAD="$LAUNCHER_LD_PRELOAD:$LD_PRELOAD"
|
||||
export QT_PLUGIN_PATH="$LAUNCHER_QT_PLUGIN_PATH:$QT_PLUGIN_PATH"
|
||||
export QT_FONTPATH="$LAUNCHER_QT_FONTPATH:$QT_FONTPATH"
|
||||
|
||||
# Detect missing dependencies...
|
||||
DEPS_LIST=`ldd "${LAUNCHER_DIR}"/plugins/*/*.so 2>/dev/null | grep "not found" | sort -u | awk -vORS=", " '{ print $1 }'`
|
||||
|
@ -1,6 +1,42 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "LoggedProcess.h"
|
||||
#include "MessageLevel.h"
|
||||
#include <QDebug>
|
||||
#include <QTextDecoder>
|
||||
#include "MessageLevel.h"
|
||||
|
||||
LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
|
||||
{
|
||||
@ -8,7 +44,11 @@ LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
|
||||
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
|
||||
connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr);
|
||||
connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus)));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
connect(this, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
|
||||
#else
|
||||
connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
|
||||
#endif
|
||||
connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange);
|
||||
}
|
||||
|
||||
@ -20,25 +60,26 @@ LoggedProcess::~LoggedProcess()
|
||||
}
|
||||
}
|
||||
|
||||
QStringList reprocess(const QByteArray & data, QString & leftover)
|
||||
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder)
|
||||
{
|
||||
QString str = leftover + QString::fromLocal8Bit(data);
|
||||
|
||||
str.remove('\r');
|
||||
QStringList lines = str.split("\n");
|
||||
leftover = lines.takeLast();
|
||||
auto str = decoder.toUnicode(data);
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
auto lines = str.remove(QChar::CarriageReturn).split(QChar::LineFeed, QString::SkipEmptyParts);
|
||||
#else
|
||||
auto lines = str.remove(QChar::CarriageReturn).split(QChar::LineFeed, Qt::SkipEmptyParts);
|
||||
#endif
|
||||
return lines;
|
||||
}
|
||||
|
||||
void LoggedProcess::on_stdErr()
|
||||
{
|
||||
auto lines = reprocess(readAllStandardError(), m_err_leftover);
|
||||
auto lines = reprocess(readAllStandardError(), m_err_decoder);
|
||||
emit log(lines, MessageLevel::StdErr);
|
||||
}
|
||||
|
||||
void LoggedProcess::on_stdOut()
|
||||
{
|
||||
auto lines = reprocess(readAllStandardOutput(), m_out_leftover);
|
||||
auto lines = reprocess(readAllStandardOutput(), m_out_decoder);
|
||||
emit log(lines, MessageLevel::StdOut);
|
||||
}
|
||||
|
||||
@ -47,18 +88,6 @@ void LoggedProcess::on_exit(int exit_code, QProcess::ExitStatus status)
|
||||
// save the exit code
|
||||
m_exit_code = exit_code;
|
||||
|
||||
// Flush console window
|
||||
if (!m_err_leftover.isEmpty())
|
||||
{
|
||||
emit log({m_err_leftover}, MessageLevel::StdErr);
|
||||
m_err_leftover.clear();
|
||||
}
|
||||
if (!m_out_leftover.isEmpty())
|
||||
{
|
||||
emit log({m_err_leftover}, MessageLevel::StdOut);
|
||||
m_out_leftover.clear();
|
||||
}
|
||||
|
||||
// based on state, send signals
|
||||
if (!m_is_aborting)
|
||||
{
|
||||
@ -157,19 +186,6 @@ void LoggedProcess::on_stateChange(QProcess::ProcessState state)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
qint64 LoggedProcess::processId() const
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return pid() ? pid()->dwProcessId : 0;
|
||||
#else
|
||||
return pid();
|
||||
#endif
|
||||
}
|
||||
|
||||
void LoggedProcess::setDetachable(bool detachable)
|
||||
{
|
||||
m_is_detachable = detachable;
|
||||
|
@ -1,21 +1,42 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QProcess>
|
||||
#include <QTextDecoder>
|
||||
#include "MessageLevel.h"
|
||||
|
||||
/*
|
||||
@ -43,7 +64,6 @@ public:
|
||||
|
||||
State state() const;
|
||||
int exitCode() const;
|
||||
qint64 processId() const;
|
||||
|
||||
void setDetachable(bool detachable);
|
||||
|
||||
@ -69,8 +89,8 @@ private:
|
||||
void changeState(LoggedProcess::State state);
|
||||
|
||||
private:
|
||||
QString m_err_leftover;
|
||||
QString m_out_leftover;
|
||||
QTextDecoder m_err_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
||||
QTextDecoder m_out_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
||||
bool m_killed = false;
|
||||
State m_state = NotRunning;
|
||||
int m_exit_code = 0;
|
||||
|
@ -127,7 +127,7 @@ bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList
|
||||
}
|
||||
|
||||
// ours
|
||||
bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods)
|
||||
bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods)
|
||||
{
|
||||
QuaZip zipOut(targetJarPath);
|
||||
if (!zipOut.open(QuaZip::mdCreate))
|
||||
@ -141,42 +141,41 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
|
||||
QSet<QString> addedFiles;
|
||||
|
||||
// Modify the jar
|
||||
QListIterator<Mod> i(mods);
|
||||
i.toBack();
|
||||
while (i.hasPrevious())
|
||||
// This needs to be done in reverse-order to ensure we respect the loading order of components
|
||||
for (auto i = mods.crbegin(); i != mods.crend(); i++)
|
||||
{
|
||||
const Mod &mod = i.previous();
|
||||
const auto* mod = *i;
|
||||
// do not merge disabled mods.
|
||||
if (!mod.enabled())
|
||||
if (!mod->enabled())
|
||||
continue;
|
||||
if (mod.type() == Mod::MOD_ZIPFILE)
|
||||
if (mod->type() == ResourceType::ZIPFILE)
|
||||
{
|
||||
if (!mergeZipFiles(&zipOut, mod.filename(), addedFiles))
|
||||
if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles))
|
||||
{
|
||||
zipOut.close();
|
||||
QFile::remove(targetJarPath);
|
||||
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
|
||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (mod.type() == Mod::MOD_SINGLEFILE)
|
||||
else if (mod->type() == ResourceType::SINGLEFILE)
|
||||
{
|
||||
// FIXME: buggy - does not work with addedFiles
|
||||
auto filename = mod.filename();
|
||||
auto filename = mod->fileinfo();
|
||||
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName()))
|
||||
{
|
||||
zipOut.close();
|
||||
QFile::remove(targetJarPath);
|
||||
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
|
||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||
return false;
|
||||
}
|
||||
addedFiles.insert(filename.fileName());
|
||||
}
|
||||
else if (mod.type() == Mod::MOD_FOLDER)
|
||||
else if (mod->type() == ResourceType::FOLDER)
|
||||
{
|
||||
// untested, but seems to be unused / not possible to reach
|
||||
// FIXME: buggy - does not work with addedFiles
|
||||
auto filename = mod.filename();
|
||||
auto filename = mod->fileinfo();
|
||||
QString what_to_zip = filename.absoluteFilePath();
|
||||
QDir dir(what_to_zip);
|
||||
dir.cdUp();
|
||||
@ -193,7 +192,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
|
||||
{
|
||||
zipOut.close();
|
||||
QFile::remove(targetJarPath);
|
||||
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
|
||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||
return false;
|
||||
}
|
||||
qDebug() << "Adding folder " << filename.fileName() << " from "
|
||||
@ -204,7 +203,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
|
||||
// Make sure we do not continue launching when something is missing or undefined...
|
||||
zipOut.close();
|
||||
QFile::remove(targetJarPath);
|
||||
qCritical() << "Failed to add unknown mod type" << mod.filename().fileName() << "to the jar.";
|
||||
qCritical() << "Failed to add unknown mod type" << mod->fileinfo().fileName() << "to the jar.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -269,7 +268,7 @@ bool MMCZip::findFilesInZip(QuaZip * zip, const QString & what, QStringList & re
|
||||
|
||||
|
||||
// ours
|
||||
nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target)
|
||||
std::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target)
|
||||
{
|
||||
QDir directory(target);
|
||||
QStringList extracted;
|
||||
@ -278,7 +277,7 @@ nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString &
|
||||
auto numEntries = zip->getEntriesCount();
|
||||
if(numEntries < 0) {
|
||||
qWarning() << "Failed to enumerate files in archive";
|
||||
return nonstd::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
else if(numEntries == 0) {
|
||||
qDebug() << "Extracting empty archives seems odd...";
|
||||
@ -287,7 +286,7 @@ nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString &
|
||||
else if (!zip->goToFirstFile())
|
||||
{
|
||||
qWarning() << "Failed to seek to first file in zip";
|
||||
return nonstd::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
do
|
||||
@ -297,20 +296,40 @@ nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString &
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
name.remove(0, subdir.size());
|
||||
QString absFilePath = directory.absoluteFilePath(name);
|
||||
auto original_name = name;
|
||||
|
||||
// Fix weird "folders with a single file get squashed" thing
|
||||
QString path;
|
||||
if(name.contains('/') && !name.endsWith('/')){
|
||||
path = name.section('/', 0, -2) + "/";
|
||||
FS::ensureFolderPathExists(FS::PathCombine(target, path));
|
||||
|
||||
name = name.split('/').last();
|
||||
}
|
||||
|
||||
QString absFilePath;
|
||||
if(name.isEmpty())
|
||||
{
|
||||
absFilePath += "/";
|
||||
absFilePath = directory.absoluteFilePath(name) + "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
absFilePath = directory.absoluteFilePath(path + name);
|
||||
}
|
||||
|
||||
if (!JlCompress::extractFile(zip, "", absFilePath))
|
||||
{
|
||||
qWarning() << "Failed to extract file" << name << "to" << absFilePath;
|
||||
qWarning() << "Failed to extract file" << original_name << "to" << absFilePath;
|
||||
JlCompress::removeFile(extracted);
|
||||
return nonstd::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
extracted.append(absFilePath);
|
||||
qDebug() << "Extracted file" << name;
|
||||
QFile::setPermissions(absFilePath, QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser);
|
||||
|
||||
qDebug() << "Extracted file" << name << "to" << absFilePath;
|
||||
} while (zip->goToNextFile());
|
||||
return extracted;
|
||||
}
|
||||
@ -322,7 +341,7 @@ bool MMCZip::extractRelFile(QuaZip *zip, const QString &file, const QString &tar
|
||||
}
|
||||
|
||||
// ours
|
||||
nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString dir)
|
||||
std::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString dir)
|
||||
{
|
||||
QuaZip zip(fileCompressed);
|
||||
if (!zip.open(QuaZip::mdUnzip))
|
||||
@ -333,13 +352,13 @@ nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString
|
||||
return QStringList();
|
||||
}
|
||||
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
|
||||
return nonstd::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
return MMCZip::extractSubDir(&zip, "", dir);
|
||||
}
|
||||
|
||||
// ours
|
||||
nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir)
|
||||
std::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir)
|
||||
{
|
||||
QuaZip zip(fileCompressed);
|
||||
if (!zip.open(QuaZip::mdUnzip))
|
||||
@ -350,7 +369,7 @@ nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString
|
||||
return QStringList();
|
||||
}
|
||||
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
|
||||
return nonstd::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
return MMCZip::extractSubDir(&zip, subdir, dir);
|
||||
}
|
||||
@ -401,7 +420,7 @@ bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& s
|
||||
continue;
|
||||
}
|
||||
|
||||
files->append(e.filePath()); // we want the original paths for MMCZip::compressDirFiles
|
||||
files->append(e); // we want the original paths for MMCZip::compressDirFiles
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include <functional>
|
||||
|
||||
#include <quazip/JlCompress.h>
|
||||
#include <nonstd/optional>
|
||||
#include <optional>
|
||||
|
||||
namespace MMCZip
|
||||
{
|
||||
@ -75,7 +75,7 @@ namespace MMCZip
|
||||
/**
|
||||
* take a source jar, add mods to it, resulting in target jar
|
||||
*/
|
||||
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods);
|
||||
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods);
|
||||
|
||||
/**
|
||||
* Find a single file in archive by file name (not path)
|
||||
@ -95,7 +95,7 @@ namespace MMCZip
|
||||
/**
|
||||
* Extract a subdirectory from an archive
|
||||
*/
|
||||
nonstd::optional<QStringList> extractSubDir(QuaZip *zip, const QString & subdir, const QString &target);
|
||||
std::optional<QStringList> extractSubDir(QuaZip *zip, const QString & subdir, const QString &target);
|
||||
|
||||
bool extractRelFile(QuaZip *zip, const QString & file, const QString &target);
|
||||
|
||||
@ -106,7 +106,7 @@ namespace MMCZip
|
||||
* \param dir The directory to extract to, the current directory if left empty.
|
||||
* \return The list of the full paths of the files extracted, empty on failure.
|
||||
*/
|
||||
nonstd::optional<QStringList> extractDir(QString fileCompressed, QString dir);
|
||||
std::optional<QStringList> extractDir(QString fileCompressed, QString dir);
|
||||
|
||||
/**
|
||||
* Extract a subdirectory from an archive
|
||||
@ -116,7 +116,7 @@ namespace MMCZip
|
||||
* \param dir The directory to extract to, the current directory if left empty.
|
||||
* \return The list of the full paths of the files extracted, empty on failure.
|
||||
*/
|
||||
nonstd::optional<QStringList> extractDir(QString fileCompressed, QString subdir, QString dir);
|
||||
std::optional<QStringList> extractDir(QString fileCompressed, QString subdir, QString dir);
|
||||
|
||||
/**
|
||||
* Extract a single file from an archive into a directory
|
||||
|
@ -1,25 +1,56 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ModDownloadTask.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
|
||||
ModDownloadTask::ModDownloadTask(const QUrl sourceUrl,const QString filename, const std::shared_ptr<ModFolderModel> mods)
|
||||
: m_sourceUrl(sourceUrl), mods(mods), filename(filename) {
|
||||
}
|
||||
ModDownloadTask::ModDownloadTask(ModPlatform::IndexedPack mod, ModPlatform::IndexedVersion version, const std::shared_ptr<ModFolderModel> mods, bool is_indexed)
|
||||
: m_mod(mod), m_mod_version(version), mods(mods)
|
||||
{
|
||||
if (is_indexed) {
|
||||
m_update_task.reset(new LocalModUpdateTask(mods->indexDir(), m_mod, m_mod_version));
|
||||
connect(m_update_task.get(), &LocalModUpdateTask::hasOldMod, this, &ModDownloadTask::hasOldMod);
|
||||
|
||||
void ModDownloadTask::executeTask() {
|
||||
setStatus(tr("Downloading mod:\n%1").arg(m_sourceUrl.toString()));
|
||||
addTask(m_update_task);
|
||||
}
|
||||
|
||||
m_filesNetJob.reset(new NetJob(tr("Mod download"), APPLICATION->network()));
|
||||
m_filesNetJob->addNetAction(Net::Download::makeFile(m_sourceUrl, mods->dir().absoluteFilePath(filename)));
|
||||
m_filesNetJob->setStatus(tr("Downloading mod:\n%1").arg(m_mod_version.downloadUrl));
|
||||
|
||||
m_filesNetJob->addNetAction(Net::Download::makeFile(m_mod_version.downloadUrl, mods->dir().absoluteFilePath(getFilename())));
|
||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ModDownloadTask::downloadSucceeded);
|
||||
connect(m_filesNetJob.get(), &NetJob::progress, this, &ModDownloadTask::downloadProgressChanged);
|
||||
connect(m_filesNetJob.get(), &NetJob::failed, this, &ModDownloadTask::downloadFailed);
|
||||
m_filesNetJob->start();
|
||||
|
||||
addTask(m_filesNetJob);
|
||||
}
|
||||
|
||||
void ModDownloadTask::downloadSucceeded()
|
||||
{
|
||||
emitSucceeded();
|
||||
m_filesNetJob.reset();
|
||||
auto name = std::get<0>(to_delete);
|
||||
auto filename = std::get<1>(to_delete);
|
||||
if (!name.isEmpty() && filename != m_mod_version.fileName) {
|
||||
mods->uninstallMod(filename, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ModDownloadTask::downloadFailed(QString reason)
|
||||
@ -33,7 +64,9 @@ void ModDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
|
||||
emit progress(current, total);
|
||||
}
|
||||
|
||||
bool ModDownloadTask::abort() {
|
||||
return m_filesNetJob->abort();
|
||||
// This indirection is done so that we don't delete a mod before being sure it was
|
||||
// downloaded successfully!
|
||||
void ModDownloadTask::hasOldMod(QString name, QString filename)
|
||||
{
|
||||
to_delete = {name, filename};
|
||||
}
|
||||
|
||||
|
@ -1,34 +1,56 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "QObjectPtr.h"
|
||||
#include "tasks/Task.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
|
||||
#include "net/NetJob.h"
|
||||
#include <QUrl>
|
||||
#include "tasks/SequentialTask.h"
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "minecraft/mod/tasks/LocalModUpdateTask.h"
|
||||
|
||||
class ModDownloadTask : public Task {
|
||||
class ModFolderModel;
|
||||
|
||||
class ModDownloadTask : public SequentialTask {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ModDownloadTask(const QUrl sourceUrl, const QString filename, const std::shared_ptr<ModFolderModel> mods);
|
||||
const QString& getFilename() const { return filename; }
|
||||
|
||||
public slots:
|
||||
bool abort() override;
|
||||
protected:
|
||||
//! Entry point for tasks.
|
||||
void executeTask() override;
|
||||
explicit ModDownloadTask(ModPlatform::IndexedPack mod, ModPlatform::IndexedVersion version, const std::shared_ptr<ModFolderModel> mods, bool is_indexed = true);
|
||||
const QString& getFilename() const { return m_mod_version.fileName; }
|
||||
|
||||
private:
|
||||
QUrl m_sourceUrl;
|
||||
NetJob::Ptr m_filesNetJob;
|
||||
ModPlatform::IndexedPack m_mod;
|
||||
ModPlatform::IndexedVersion m_mod_version;
|
||||
const std::shared_ptr<ModFolderModel> mods;
|
||||
const QString filename;
|
||||
|
||||
NetJob::Ptr m_filesNetJob;
|
||||
LocalModUpdateTask::Ptr m_update_task;
|
||||
|
||||
void downloadProgressChanged(qint64 current, qint64 total);
|
||||
|
||||
void downloadFailed(QString reason);
|
||||
|
||||
void downloadSucceeded();
|
||||
|
||||
std::tuple<QString, QString> to_delete {"", ""};
|
||||
|
||||
private slots:
|
||||
void hasOldMod(QString name, QString filename);
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "BaseInstance.h"
|
||||
#include "launch/LaunchTask.h"
|
||||
@ -15,6 +50,10 @@ public:
|
||||
void saveNow() override
|
||||
{
|
||||
}
|
||||
void loadSpecificSettings() override
|
||||
{
|
||||
setSpecificSettingsLoaded(true);
|
||||
}
|
||||
QString getStatusbarDescription() override
|
||||
{
|
||||
return tr("Unknown instance type");
|
||||
@ -39,7 +78,11 @@ public:
|
||||
{
|
||||
return QProcessEnvironment();
|
||||
}
|
||||
QMap<QString, QString> getVariables() const override
|
||||
QProcessEnvironment createLaunchEnvironment() override
|
||||
{
|
||||
return QProcessEnvironment();
|
||||
}
|
||||
QMap<QString, QString> getVariables() override
|
||||
{
|
||||
return QMap<QString, QString>();
|
||||
}
|
||||
@ -76,4 +119,8 @@ public:
|
||||
QString modsRoot() const override {
|
||||
return QString();
|
||||
}
|
||||
void updateRuntimeContext()
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
};
|
||||
|
@ -1,89 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <QObject>
|
||||
|
||||
namespace details
|
||||
{
|
||||
struct DeleteQObjectLater
|
||||
{
|
||||
void operator()(QObject *obj) const
|
||||
{
|
||||
obj->deleteLater();
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* A unique pointer class with unique pointer semantics intended for derivates of QObject
|
||||
* Calls deleteLater() instead of destroying the contained object immediately
|
||||
*/
|
||||
template<typename T> using unique_qobject_ptr = std::unique_ptr<T, details::DeleteQObjectLater>;
|
||||
template <typename T>
|
||||
using unique_qobject_ptr = QScopedPointer<T, QScopedPointerDeleteLater>;
|
||||
|
||||
/**
|
||||
* A shared pointer class with shared pointer semantics intended for derivates of QObject
|
||||
* Calls deleteLater() instead of destroying the contained object immediately
|
||||
*/
|
||||
template <typename T>
|
||||
class shared_qobject_ptr
|
||||
{
|
||||
public:
|
||||
shared_qobject_ptr(){}
|
||||
shared_qobject_ptr(T * wrap)
|
||||
{
|
||||
reset(wrap);
|
||||
}
|
||||
shared_qobject_ptr(const shared_qobject_ptr<T>& other)
|
||||
{
|
||||
m_ptr = other.m_ptr;
|
||||
}
|
||||
template<typename Derived>
|
||||
shared_qobject_ptr(const shared_qobject_ptr<Derived> &other)
|
||||
{
|
||||
m_ptr = other.unwrap();
|
||||
}
|
||||
class shared_qobject_ptr : public QSharedPointer<T> {
|
||||
public:
|
||||
constexpr shared_qobject_ptr() : QSharedPointer<T>() {}
|
||||
constexpr shared_qobject_ptr(T* ptr) : QSharedPointer<T>(ptr, &QObject::deleteLater) {}
|
||||
constexpr shared_qobject_ptr(std::nullptr_t null_ptr) : QSharedPointer<T>(null_ptr, &QObject::deleteLater) {}
|
||||
|
||||
public:
|
||||
void reset(T * wrap)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
m_ptr.reset(wrap, std::bind(&QObject::deleteLater, _1));
|
||||
}
|
||||
void reset(const shared_qobject_ptr<T> &other)
|
||||
{
|
||||
m_ptr = other.m_ptr;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
m_ptr.reset();
|
||||
}
|
||||
T * get() const
|
||||
{
|
||||
return m_ptr.get();
|
||||
}
|
||||
T * operator->() const
|
||||
{
|
||||
return m_ptr.get();
|
||||
}
|
||||
T & operator*() const
|
||||
{
|
||||
return *m_ptr.get();
|
||||
}
|
||||
operator bool() const
|
||||
{
|
||||
return m_ptr.get() != nullptr;
|
||||
}
|
||||
const std::shared_ptr <T> unwrap() const
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
bool operator==(const shared_qobject_ptr<T>& other) {
|
||||
return m_ptr == other.m_ptr;
|
||||
}
|
||||
bool operator!=(const shared_qobject_ptr<T>& other) {
|
||||
return m_ptr != other.m_ptr;
|
||||
}
|
||||
template <typename Derived>
|
||||
constexpr shared_qobject_ptr(const shared_qobject_ptr<Derived>& other) : QSharedPointer<T>(other)
|
||||
{}
|
||||
|
||||
private:
|
||||
std::shared_ptr <T> m_ptr;
|
||||
void reset() { QSharedPointer<T>::reset(); }
|
||||
void reset(const shared_qobject_ptr<T>& other)
|
||||
{
|
||||
shared_qobject_ptr<T> t(other);
|
||||
this->swap(t);
|
||||
}
|
||||
};
|
||||
|
88
launcher/RuntimeContext.h
Normal file
88
launcher/RuntimeContext.h
Normal file
@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include "settings/SettingsObject.h"
|
||||
|
||||
struct RuntimeContext {
|
||||
QString javaArchitecture;
|
||||
QString javaRealArchitecture;
|
||||
QString javaPath;
|
||||
QString system;
|
||||
|
||||
QString mappedJavaRealArchitecture() const
|
||||
{
|
||||
if (javaRealArchitecture == "amd64")
|
||||
return "x86_64";
|
||||
if (javaRealArchitecture == "i386" || javaRealArchitecture == "i686")
|
||||
return "x86";
|
||||
if (javaRealArchitecture == "aarch64")
|
||||
return "arm64";
|
||||
if (javaRealArchitecture == "arm" || javaRealArchitecture == "armhf")
|
||||
return "arm32";
|
||||
return javaRealArchitecture;
|
||||
}
|
||||
|
||||
void updateFromInstanceSettings(SettingsObjectPtr instanceSettings)
|
||||
{
|
||||
javaArchitecture = instanceSettings->get("JavaArchitecture").toString();
|
||||
javaRealArchitecture = instanceSettings->get("JavaRealArchitecture").toString();
|
||||
javaPath = instanceSettings->get("JavaPath").toString();
|
||||
system = currentSystem();
|
||||
}
|
||||
|
||||
QString getClassifier() const { return system + "-" + mappedJavaRealArchitecture(); }
|
||||
|
||||
// "Legacy" refers to the fact that Mojang assumed that these are the only two architectures
|
||||
bool isLegacyArch() const
|
||||
{
|
||||
const QString mapped = mappedJavaRealArchitecture();
|
||||
return mapped == "x86_64" || mapped == "x86";
|
||||
}
|
||||
|
||||
bool classifierMatches(QString target) const
|
||||
{
|
||||
// try to match precise classifier "[os]-[arch]"
|
||||
bool x = target == getClassifier();
|
||||
// try to match imprecise classifier on legacy architectures "[os]"
|
||||
if (!x && isLegacyArch())
|
||||
x = target == system;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static QString currentSystem()
|
||||
{
|
||||
#if defined(Q_OS_LINUX)
|
||||
return "linux";
|
||||
#elif defined(Q_OS_MACOS)
|
||||
return "osx";
|
||||
#elif defined(Q_OS_WINDOWS)
|
||||
return "windows";
|
||||
#elif defined(Q_OS_FREEBSD)
|
||||
return "freebsd";
|
||||
#elif defined(Q_OS_OPENBSD)
|
||||
return "openbsd";
|
||||
#else
|
||||
return "unknown";
|
||||
#endif
|
||||
}
|
||||
};
|
@ -138,20 +138,6 @@ void UpdateController::installUpdates()
|
||||
}
|
||||
#endif
|
||||
QFileInfo destination (FS::PathCombine(m_root, op.destination));
|
||||
#ifdef Q_OS_WIN32
|
||||
if(QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
|
||||
{
|
||||
if(destination.fileName() == windowsExeName)
|
||||
{
|
||||
QDir rootDir(m_root);
|
||||
exeOrigin = rootDir.relativeFilePath(op.source);
|
||||
exePath = rootDir.relativeFilePath(op.destination);
|
||||
exeBackup = rootDir.relativeFilePath(FS::PathCombine(backupPath, destination.fileName()));
|
||||
useXPHack = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(destination.exists())
|
||||
{
|
||||
QString backupName = op.destination;
|
||||
@ -372,7 +358,7 @@ void UpdateController::fail()
|
||||
msg = QObject::tr(
|
||||
"Couldn't replace file %1. Changes will be reverted.\n"
|
||||
"See the %2 log file for details."
|
||||
).arg(m_failedFile, BuildConfig.LAUNCHER_NAME);
|
||||
).arg(m_failedFile, BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||
doRollback = true;
|
||||
QMessageBox::critical(m_parent, failTitle, msg);
|
||||
break;
|
||||
@ -382,7 +368,7 @@ void UpdateController::fail()
|
||||
msg = QObject::tr(
|
||||
"Couldn't remove file %1. Changes will be reverted.\n"
|
||||
"See the %2 log file for details."
|
||||
).arg(m_failedFile, BuildConfig.LAUNCHER_NAME);
|
||||
).arg(m_failedFile, BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||
doRollback = true;
|
||||
QMessageBox::critical(m_parent, failTitle, msg);
|
||||
break;
|
||||
@ -413,7 +399,7 @@ void UpdateController::fail()
|
||||
{
|
||||
msg = QObject::tr("The rollback failed too.\n"
|
||||
"You will have to repair %1 manually.\n"
|
||||
"Please let us know why and how this happened.").arg(BuildConfig.LAUNCHER_NAME);
|
||||
"Please let us know why and how this happened.").arg(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||
QMessageBox::critical(m_parent, rollFailTitle, msg);
|
||||
qApp->quit();
|
||||
}
|
||||
|
@ -1,6 +1,42 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QStringView>
|
||||
#include <QList>
|
||||
|
||||
class QUrl;
|
||||
@ -39,13 +75,21 @@ private:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
auto numPart = QStringView{m_fullString}.left(cutoff);
|
||||
#else
|
||||
auto numPart = m_fullString.leftRef(cutoff);
|
||||
#endif
|
||||
if(numPart.size())
|
||||
{
|
||||
numValid = true;
|
||||
m_numPart = numPart.toInt();
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
auto stringPart = QStringView{m_fullString}.mid(cutoff);
|
||||
#else
|
||||
auto stringPart = m_fullString.midRef(cutoff);
|
||||
#endif
|
||||
if(stringPart.size())
|
||||
{
|
||||
m_stringPart = stringPart.toString();
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "VersionProxyModel.h"
|
||||
#include "Application.h"
|
||||
#include <QSortFilterProxyModel>
|
||||
@ -208,7 +243,8 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
return APPLICATION->getThemedIcon("bug");
|
||||
}
|
||||
auto pixmap = QPixmapCache::find("placeholder");
|
||||
QPixmap pixmap;
|
||||
QPixmapCache::find("placeholder", &pixmap);
|
||||
if(!pixmap)
|
||||
{
|
||||
QPixmap px(16,16);
|
||||
@ -216,7 +252,7 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
|
||||
QPixmapCache::insert("placeholder", px);
|
||||
return px;
|
||||
}
|
||||
return *pixmap;
|
||||
return pixmap;
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "IconList.h"
|
||||
@ -36,7 +56,7 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren
|
||||
auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name);
|
||||
for (auto file_info : file_info_list)
|
||||
{
|
||||
builtinNames.insert(file_info.baseName());
|
||||
builtinNames.insert(file_info.completeBaseName());
|
||||
}
|
||||
}
|
||||
for(auto & builtinName : builtinNames)
|
||||
@ -51,6 +71,18 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren
|
||||
connect(m_watcher.get(), SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
|
||||
|
||||
directoryChanged(path);
|
||||
|
||||
// Forces the UI to update, so that lengthy icon names are shown properly from the start
|
||||
emit iconUpdated({});
|
||||
}
|
||||
|
||||
void IconList::sortIconList()
|
||||
{
|
||||
qDebug() << "Sorting icon list...";
|
||||
std::sort(icons.begin(), icons.end(), [](const MMCIcon& a, const MMCIcon& b) {
|
||||
return a.m_key.localeAwareCompare(b.m_key) < 0;
|
||||
});
|
||||
reindex();
|
||||
}
|
||||
|
||||
void IconList::directoryChanged(const QString &path)
|
||||
@ -74,7 +106,11 @@ void IconList::directoryChanged(const QString &path)
|
||||
QString &foo = (*it);
|
||||
foo = m_dir.filePath(foo);
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QSet<QString> new_set(new_list.begin(), new_list.end());
|
||||
#else
|
||||
auto new_set = new_list.toSet();
|
||||
#endif
|
||||
QList<QString> current_list;
|
||||
for (auto &it : icons)
|
||||
{
|
||||
@ -82,7 +118,11 @@ void IconList::directoryChanged(const QString &path)
|
||||
continue;
|
||||
current_list.push_back(it.m_images[IconType::FileBased].filename);
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QSet<QString> current_set(current_list.begin(), current_list.end());
|
||||
#else
|
||||
QSet<QString> current_set = current_list.toSet();
|
||||
#endif
|
||||
|
||||
QSet<QString> to_remove = current_set;
|
||||
to_remove -= new_set;
|
||||
@ -94,7 +134,13 @@ void IconList::directoryChanged(const QString &path)
|
||||
{
|
||||
qDebug() << "Removing " << remove;
|
||||
QFileInfo rmfile(remove);
|
||||
QString key = rmfile.baseName();
|
||||
QString key = rmfile.completeBaseName();
|
||||
|
||||
QString suffix = rmfile.suffix();
|
||||
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
|
||||
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
|
||||
key = rmfile.fileName();
|
||||
|
||||
int idx = getIconIndex(key);
|
||||
if (idx == -1)
|
||||
continue;
|
||||
@ -117,14 +163,23 @@ void IconList::directoryChanged(const QString &path)
|
||||
for (auto add : to_add)
|
||||
{
|
||||
qDebug() << "Adding " << add;
|
||||
|
||||
QFileInfo addfile(add);
|
||||
QString key = addfile.baseName();
|
||||
QString key = addfile.completeBaseName();
|
||||
|
||||
QString suffix = addfile.suffix();
|
||||
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
|
||||
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
|
||||
key = addfile.fileName();
|
||||
|
||||
if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased))
|
||||
{
|
||||
m_watcher->addPath(add);
|
||||
emit iconUpdated(key);
|
||||
}
|
||||
}
|
||||
|
||||
sortIconList();
|
||||
}
|
||||
|
||||
void IconList::fileChanged(const QString &path)
|
||||
@ -133,7 +188,7 @@ void IconList::fileChanged(const QString &path)
|
||||
QFileInfo checkfile(path);
|
||||
if (!checkfile.exists())
|
||||
return;
|
||||
QString key = checkfile.baseName();
|
||||
QString key = checkfile.completeBaseName();
|
||||
int idx = getIconIndex(key);
|
||||
if (idx == -1)
|
||||
return;
|
||||
@ -257,7 +312,7 @@ void IconList::installIcons(const QStringList &iconFiles)
|
||||
QFileInfo fileinfo(file);
|
||||
if (!fileinfo.isReadable() || !fileinfo.isFile())
|
||||
continue;
|
||||
QString target = FS::PathCombine(m_dir.dirName(), fileinfo.fileName());
|
||||
QString target = FS::PathCombine(getDirectory(), fileinfo.fileName());
|
||||
|
||||
QString suffix = fileinfo.suffix();
|
||||
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
|
||||
@ -274,7 +329,7 @@ void IconList::installIcon(const QString &file, const QString &name)
|
||||
if(!fileinfo.isReadable() || !fileinfo.isFile())
|
||||
return;
|
||||
|
||||
QString target = FS::PathCombine(m_dir.dirName(), name);
|
||||
QString target = FS::PathCombine(getDirectory(), name);
|
||||
|
||||
QFile::copy(file, target);
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ private:
|
||||
// hide assign op
|
||||
IconList &operator=(const IconList &) = delete;
|
||||
void reindex();
|
||||
void sortIconList();
|
||||
|
||||
public slots:
|
||||
void directoryChanged(const QString &path);
|
||||
|
@ -1,21 +1,41 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MMCIcon.h"
|
||||
#include <QFileInfo>
|
||||
#include <xdgicon.h>
|
||||
#include <QIcon>
|
||||
|
||||
IconType operator--(IconType &t, int)
|
||||
{
|
||||
@ -63,7 +83,7 @@ QIcon MMCIcon::icon() const
|
||||
if(!icon.isNull())
|
||||
return icon;
|
||||
// FIXME: inject this.
|
||||
return XdgIcon::fromTheme(m_images[m_current_type].key);
|
||||
return QIcon::fromTheme(m_images[m_current_type].key);
|
||||
}
|
||||
|
||||
void MMCIcon::remove(IconType rm_type)
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "JavaChecker.h"
|
||||
|
||||
#include <QFile>
|
||||
@ -16,7 +51,13 @@ JavaChecker::JavaChecker(QObject *parent) : QObject(parent)
|
||||
|
||||
void JavaChecker::performCheck()
|
||||
{
|
||||
QString checkerJar = FS::PathCombine(APPLICATION->getJarsPath(), "JavaCheck.jar");
|
||||
QString checkerJar = JavaUtils::getJavaCheckPath();
|
||||
|
||||
if (checkerJar.isEmpty())
|
||||
{
|
||||
qDebug() << "Java checker library could not be found. Please check your installation.";
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList args;
|
||||
|
||||
@ -47,7 +88,11 @@ void JavaChecker::performCheck()
|
||||
qDebug() << "Running java checker: " + m_path + args.join(" ");;
|
||||
|
||||
connect(process.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
connect(process.get(), SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
|
||||
#else
|
||||
connect(process.get(), SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
|
||||
#endif
|
||||
connect(process.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(stdoutReady()));
|
||||
connect(process.get(), SIGNAL(readyReadStandardError()), this, SLOT(stderrReady()));
|
||||
connect(&killTimer, SIGNAL(timeout()), SLOT(timeout()));
|
||||
@ -99,7 +144,12 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
||||
bool success = true;
|
||||
|
||||
QMap<QString, QString> results;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QStringList lines = m_stdout.split("\n", Qt::SkipEmptyParts);
|
||||
#else
|
||||
QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts);
|
||||
#endif
|
||||
for(QString line : lines)
|
||||
{
|
||||
line = line.trimmed();
|
||||
@ -108,7 +158,11 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
||||
continue;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
auto parts = line.split('=', Qt::SkipEmptyParts);
|
||||
#else
|
||||
auto parts = line.split('=', QString::SkipEmptyParts);
|
||||
#endif
|
||||
if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty())
|
||||
{
|
||||
continue;
|
||||
|
@ -1,21 +1,40 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <QtNetwork>
|
||||
#include <QtXml>
|
||||
#include <QRegExp>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
@ -81,7 +100,7 @@ QVariant JavaInstallList::data(const QModelIndex &index, int role) const
|
||||
switch (role)
|
||||
{
|
||||
case VersionPointerRole:
|
||||
return qVariantFromValue(m_vlist[index.row()]);
|
||||
return QVariant::fromValue(m_vlist[index.row()]);
|
||||
case VersionIdRole:
|
||||
return version->descriptor();
|
||||
case VersionRole:
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <QStringList>
|
||||
@ -24,6 +44,7 @@
|
||||
#include "java/JavaUtils.h"
|
||||
#include "java/JavaInstallList.h"
|
||||
#include "FileSystem.h"
|
||||
#include "Application.h"
|
||||
|
||||
#define IBUS "@im=ibus"
|
||||
|
||||
@ -31,26 +52,25 @@ JavaUtils::JavaUtils()
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
static QString processLD_LIBRARY_PATH(const QString & LD_LIBRARY_PATH)
|
||||
QString stripVariableEntries(QString name, QString target, QString remove)
|
||||
{
|
||||
QDir mmcBin(QCoreApplication::applicationDirPath());
|
||||
auto items = LD_LIBRARY_PATH.split(':');
|
||||
QStringList final;
|
||||
for(auto & item: items)
|
||||
{
|
||||
QDir test(item);
|
||||
if(test == mmcBin)
|
||||
{
|
||||
qDebug() << "Env:LD_LIBRARY_PATH ignoring path" << item;
|
||||
continue;
|
||||
}
|
||||
final.append(item);
|
||||
}
|
||||
return final.join(':');
|
||||
}
|
||||
char delimiter = ':';
|
||||
#ifdef Q_OS_WIN32
|
||||
delimiter = ';';
|
||||
#endif
|
||||
|
||||
auto targetItems = target.split(delimiter);
|
||||
auto toRemove = remove.split(delimiter);
|
||||
|
||||
for (QString item : toRemove) {
|
||||
bool removed = targetItems.removeOne(item);
|
||||
if (!removed)
|
||||
qWarning() << "Entry" << item
|
||||
<< "could not be stripped from variable" << name;
|
||||
}
|
||||
return targetItems.join(delimiter);
|
||||
}
|
||||
|
||||
QProcessEnvironment CleanEnviroment()
|
||||
{
|
||||
// prepare the process environment
|
||||
@ -68,6 +88,16 @@ QProcessEnvironment CleanEnviroment()
|
||||
"JAVA_OPTIONS",
|
||||
"JAVA_TOOL_OPTIONS"
|
||||
};
|
||||
|
||||
QStringList stripped =
|
||||
{
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||
"LD_LIBRARY_PATH",
|
||||
"LD_PRELOAD",
|
||||
#endif
|
||||
"QT_PLUGIN_PATH",
|
||||
"QT_FONTPATH"
|
||||
};
|
||||
for(auto key: rawenv.keys())
|
||||
{
|
||||
auto value = rawenv.value(key);
|
||||
@ -77,19 +107,22 @@ QProcessEnvironment CleanEnviroment()
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
// filter PolyMC-related things
|
||||
if(key.startsWith("QT_"))
|
||||
|
||||
// These are used to strip the original variables
|
||||
// If there is "LD_LIBRARY_PATH" and "LAUNCHER_LD_LIBRARY_PATH", we want to
|
||||
// remove all values in "LAUNCHER_LD_LIBRARY_PATH" from "LD_LIBRARY_PATH"
|
||||
if(key.startsWith("LAUNCHER_"))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
// Do not pass LD_* variables to java. They were intended for PolyMC
|
||||
if(key.startsWith("LD_"))
|
||||
if(stripped.contains(key))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
QString newValue = stripVariableEntries(key, value, rawenv.value("LAUNCHER_" + key));
|
||||
|
||||
qDebug() << "Env: stripped" << key << value << "to" << newValue;
|
||||
}
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||
// Strip IBus
|
||||
// IBus is a Linux IME framework. For some reason, it breaks MC?
|
||||
if (key == "XMODIFIERS" && value.contains(IBUS))
|
||||
@ -98,22 +131,12 @@ QProcessEnvironment CleanEnviroment()
|
||||
value.replace(IBUS, "");
|
||||
qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value;
|
||||
}
|
||||
if(key == "GAME_PRELOAD")
|
||||
{
|
||||
env.insert("LD_PRELOAD", value);
|
||||
continue;
|
||||
}
|
||||
if(key == "GAME_LIBRARY_PATH")
|
||||
{
|
||||
env.insert("LD_LIBRARY_PATH", processLD_LIBRARY_PATH(value));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
// qDebug() << "Env: " << key << value;
|
||||
env.insert(key, value);
|
||||
}
|
||||
#ifdef Q_OS_LINUX
|
||||
// HACK: Workaround for QTBUG42500
|
||||
// HACK: Workaround for QTBUG-42500
|
||||
if(!env.contains("LD_LIBRARY_PATH"))
|
||||
{
|
||||
env.insert("LD_LIBRARY_PATH", "");
|
||||
@ -151,11 +174,17 @@ JavaInstallPtr JavaUtils::GetDefaultJava()
|
||||
|
||||
QStringList addJavasFromEnv(QList<QString> javas)
|
||||
{
|
||||
QByteArray env = qgetenv("POLYMC_JAVA_PATHS");
|
||||
auto env = qEnvironmentVariable("PRISMLAUNCHER_JAVA_PATHS"); // FIXME: use launcher name from buildconfig
|
||||
#if defined(Q_OS_WIN32)
|
||||
QList<QString> javaPaths = QString::fromLocal8Bit(env).replace("\\", "/").split(QLatin1String(";"));
|
||||
QList<QString> javaPaths = env.replace("\\", "/").split(QLatin1String(";"));
|
||||
|
||||
auto envPath = qEnvironmentVariable("PATH");
|
||||
QList<QString> javaPathsfromPath = envPath.replace("\\", "/").split(QLatin1String(";"));
|
||||
for (QString string : javaPathsfromPath) {
|
||||
javaPaths.append(string + "/javaw.exe");
|
||||
}
|
||||
#else
|
||||
QList<QString> javaPaths = QString::fromLocal8Bit(env).split(QLatin1String(":"));
|
||||
QList<QString> javaPaths = env.split(QLatin1String(":"));
|
||||
#endif
|
||||
for(QString i : javaPaths)
|
||||
{
|
||||
@ -176,25 +205,17 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
|
||||
archType = "32";
|
||||
|
||||
HKEY jreKey;
|
||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName.toStdString().c_str(), 0,
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0,
|
||||
KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS)
|
||||
{
|
||||
// Read the current type version from the registry.
|
||||
// This will be used to find any key that contains the JavaHome value.
|
||||
char *value = new char[0];
|
||||
DWORD valueSz = 0;
|
||||
if (RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz) ==
|
||||
ERROR_MORE_DATA)
|
||||
{
|
||||
value = new char[valueSz];
|
||||
RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz);
|
||||
}
|
||||
|
||||
TCHAR subKeyName[255];
|
||||
WCHAR subKeyName[255];
|
||||
DWORD subKeyNameSize, numSubKeys, retCode;
|
||||
|
||||
// Get the number of subkeys
|
||||
RegQueryInfoKey(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
|
||||
RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL);
|
||||
|
||||
// Iterate until RegEnumKeyEx fails
|
||||
@ -203,34 +224,37 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
|
||||
for (DWORD i = 0; i < numSubKeys; i++)
|
||||
{
|
||||
subKeyNameSize = 255;
|
||||
retCode = RegEnumKeyEx(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
|
||||
NULL);
|
||||
retCode = RegEnumKeyExW(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
|
||||
NULL);
|
||||
QString newSubkeyName = QString::fromWCharArray(subKeyName);
|
||||
if (retCode == ERROR_SUCCESS)
|
||||
{
|
||||
// Now open the registry key for the version that we just got.
|
||||
QString newKeyName = keyName + "\\" + subKeyName + subkeySuffix;
|
||||
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
|
||||
|
||||
HKEY newKey;
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newKeyName.toStdString().c_str(), 0,
|
||||
KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().c_str(), 0,
|
||||
KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
|
||||
{
|
||||
// Read the JavaHome value to find where Java is installed.
|
||||
value = new char[0];
|
||||
valueSz = 0;
|
||||
if (RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
|
||||
&valueSz) == ERROR_MORE_DATA)
|
||||
DWORD valueSz = 0;
|
||||
if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, NULL,
|
||||
&valueSz) == ERROR_SUCCESS)
|
||||
{
|
||||
value = new char[valueSz];
|
||||
RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
|
||||
&valueSz);
|
||||
WCHAR *value = new WCHAR[valueSz];
|
||||
RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE *)value,
|
||||
&valueSz);
|
||||
|
||||
QString newValue = QString::fromWCharArray(value);
|
||||
delete [] value;
|
||||
|
||||
// Now, we construct the version object and add it to the list.
|
||||
JavaInstallPtr javaVersion(new JavaInstall());
|
||||
|
||||
javaVersion->id = subKeyName;
|
||||
javaVersion->id = newSubkeyName;
|
||||
javaVersion->arch = archType;
|
||||
javaVersion->path =
|
||||
QDir(FS::PathCombine(value, "bin")).absoluteFilePath("javaw.exe");
|
||||
QDir(FS::PathCombine(newValue, "bin")).absoluteFilePath("javaw.exe");
|
||||
javas.append(javaVersion);
|
||||
}
|
||||
|
||||
@ -355,7 +379,9 @@ QList<QString> JavaUtils::FindJavaPaths()
|
||||
}
|
||||
}
|
||||
|
||||
return addJavasFromEnv(candidates);
|
||||
candidates = addJavasFromEnv(candidates);
|
||||
candidates.removeDuplicates();
|
||||
return candidates;
|
||||
}
|
||||
|
||||
#elif defined(Q_OS_MAC)
|
||||
@ -378,7 +404,9 @@ QList<QString> JavaUtils::FindJavaPaths()
|
||||
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java");
|
||||
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
|
||||
}
|
||||
return addJavasFromEnv(javas);
|
||||
javas = addJavasFromEnv(javas);
|
||||
javas.removeDuplicates();
|
||||
return javas;
|
||||
}
|
||||
|
||||
#elif defined(Q_OS_LINUX)
|
||||
@ -417,14 +445,16 @@ QList<QString> JavaUtils::FindJavaPaths()
|
||||
scanJavaDir("/usr/lib/jvm");
|
||||
scanJavaDir("/usr/lib64/jvm");
|
||||
scanJavaDir("/usr/lib32/jvm");
|
||||
// javas stored in PolyMC's folder
|
||||
// javas stored in Prism Launcher's folder
|
||||
scanJavaDir("java");
|
||||
// manually installed JDKs in /opt
|
||||
scanJavaDir("/opt/jdk");
|
||||
scanJavaDir("/opt/jdks");
|
||||
// flatpak
|
||||
scanJavaDir("/app/jdk");
|
||||
return addJavasFromEnv(javas);
|
||||
javas = addJavasFromEnv(javas);
|
||||
javas.removeDuplicates();
|
||||
return javas;
|
||||
}
|
||||
#else
|
||||
QList<QString> JavaUtils::FindJavaPaths()
|
||||
@ -437,3 +467,8 @@ QList<QString> JavaUtils::FindJavaPaths()
|
||||
return addJavasFromEnv(javas);
|
||||
}
|
||||
#endif
|
||||
|
||||
QString JavaUtils::getJavaCheckPath()
|
||||
{
|
||||
return APPLICATION->getJarPath("JavaCheck.jar");
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
QString stripVariableEntries(QString name, QString target, QString remove);
|
||||
QProcessEnvironment CleanEnviroment();
|
||||
|
||||
class JavaUtils : public QObject
|
||||
@ -39,4 +40,6 @@ public:
|
||||
#ifdef Q_OS_WIN
|
||||
QList<JavaInstallPtr> FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix = "");
|
||||
#endif
|
||||
|
||||
static QString getJavaCheckPath();
|
||||
};
|
||||
|
@ -282,18 +282,22 @@ void LaunchTask::emitFailed(QString reason)
|
||||
Task::emitFailed(reason);
|
||||
}
|
||||
|
||||
QString LaunchTask::substituteVariables(const QString &cmd) const
|
||||
void LaunchTask::substituteVariables(QStringList &args) const
|
||||
{
|
||||
QString out = cmd;
|
||||
auto variables = m_instance->getVariables();
|
||||
for (auto it = variables.begin(); it != variables.end(); ++it)
|
||||
auto env = m_instance->createEnvironment();
|
||||
|
||||
for (auto key : env.keys())
|
||||
{
|
||||
out.replace("$" + it.key(), it.value());
|
||||
args.replaceInStrings("$" + key, env.value(key));
|
||||
}
|
||||
}
|
||||
|
||||
void LaunchTask::substituteVariables(QString &cmd) const
|
||||
{
|
||||
auto env = m_instance->createEnvironment();
|
||||
|
||||
for (auto key : env.keys())
|
||||
{
|
||||
cmd.replace("$" + key, env.value(key));
|
||||
}
|
||||
auto env = QProcessEnvironment::systemEnvironment();
|
||||
for (auto var : env.keys())
|
||||
{
|
||||
out.replace("$" + var, env.value(var));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -1,18 +1,38 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -85,7 +105,8 @@ public: /* methods */
|
||||
shared_qobject_ptr<LogModel> getLogModel();
|
||||
|
||||
public:
|
||||
QString substituteVariables(const QString &cmd) const;
|
||||
void substituteVariables(QStringList &args) const;
|
||||
void substituteVariables(QString &cmd) const;
|
||||
QString censorPrivateInfo(QString in);
|
||||
|
||||
protected: /* methods */
|
||||
|
@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
#include "CheckJava.h"
|
||||
#include "java/JavaUtils.h"
|
||||
#include <launch/LaunchTask.h>
|
||||
#include <FileSystem.h>
|
||||
#include <QStandardPaths>
|
||||
@ -71,15 +72,26 @@ void CheckJava::executeTask()
|
||||
emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::Launcher);
|
||||
}
|
||||
|
||||
if (JavaUtils::getJavaCheckPath().isEmpty())
|
||||
{
|
||||
const char *reason = QT_TR_NOOP("Java checker library could not be found. Please check your installation.");
|
||||
emit logLine(tr(reason), MessageLevel::Fatal);
|
||||
emitFailed(tr(reason));
|
||||
return;
|
||||
}
|
||||
|
||||
QFileInfo javaInfo(realJavaPath);
|
||||
qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch();
|
||||
auto storedUnixTime = settings->get("JavaTimestamp").toLongLong();
|
||||
auto storedArchitecture = settings->get("JavaArchitecture").toString();
|
||||
auto storedRealArchitecture = settings->get("JavaRealArchitecture").toString();
|
||||
auto storedVersion = settings->get("JavaVersion").toString();
|
||||
auto storedVendor = settings->get("JavaVendor").toString();
|
||||
m_javaUnixTime = javaUnixTime;
|
||||
// if timestamps are not the same, or something is missing, check!
|
||||
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0 || storedArchitecture.size() == 0 || storedVendor.size() == 0)
|
||||
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0
|
||||
|| storedArchitecture.size() == 0 || storedRealArchitecture.size() == 0
|
||||
|| storedVendor.size() == 0)
|
||||
{
|
||||
m_JavaChecker = new JavaChecker();
|
||||
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
|
||||
@ -92,8 +104,9 @@ void CheckJava::executeTask()
|
||||
{
|
||||
auto verString = instance->settings()->get("JavaVersion").toString();
|
||||
auto archString = instance->settings()->get("JavaArchitecture").toString();
|
||||
auto realArchString = settings->get("JavaRealArchitecture").toString();
|
||||
auto vendorString = instance->settings()->get("JavaVendor").toString();
|
||||
printJavaInfo(verString, archString, vendorString);
|
||||
printJavaInfo(verString, archString, realArchString, vendorString);
|
||||
}
|
||||
emitSucceeded();
|
||||
}
|
||||
@ -108,7 +121,6 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
||||
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
||||
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
||||
emit logLine(QString("\nCheck your Java settings."), MessageLevel::Launcher);
|
||||
printSystemInfo(false, false);
|
||||
emitFailed(QString("Could not start java!"));
|
||||
return;
|
||||
}
|
||||
@ -117,17 +129,16 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
||||
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
||||
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
||||
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
||||
printSystemInfo(false, false);
|
||||
emitSucceeded();
|
||||
return;
|
||||
}
|
||||
case JavaCheckResult::Validity::Valid:
|
||||
{
|
||||
auto instance = m_parent->instance();
|
||||
printJavaInfo(result.javaVersion.toString(), result.realPlatform, result.javaVendor);
|
||||
printSystemInfo(true, result.is_64bit);
|
||||
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
||||
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
||||
instance->settings()->set("JavaArchitecture", result.mojangPlatform);
|
||||
instance->settings()->set("JavaRealArchitecture", result.realPlatform);
|
||||
instance->settings()->set("JavaVendor", result.javaVendor);
|
||||
instance->settings()->set("JavaTimestamp", m_javaUnixTime);
|
||||
emitSucceeded();
|
||||
@ -136,24 +147,8 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
||||
}
|
||||
}
|
||||
|
||||
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString & vendor)
|
||||
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString & vendor)
|
||||
{
|
||||
emit logLine(QString("Java is version %1, using %2 architecture, from %3.\n\n").arg(version, architecture, vendor), MessageLevel::Launcher);
|
||||
}
|
||||
|
||||
void CheckJava::printSystemInfo(bool javaIsKnown, bool javaIs64bit)
|
||||
{
|
||||
auto cpu64 = Sys::isCPU64bit();
|
||||
auto system64 = Sys::isSystem64bit();
|
||||
if(cpu64 != system64)
|
||||
{
|
||||
emit logLine(QString("Your CPU architecture is not matching your system architecture. You might want to install a 64bit Operating System.\n\n"), MessageLevel::Error);
|
||||
}
|
||||
if(javaIsKnown)
|
||||
{
|
||||
if(javaIs64bit != system64)
|
||||
{
|
||||
emit logLine(QString("Your Java architecture is not matching your system architecture. You might want to install a 64bit Java version.\n\n"), MessageLevel::Error);
|
||||
}
|
||||
}
|
||||
emit logLine(QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n")
|
||||
.arg(version, architecture, realArchitecture, vendor), MessageLevel::Launcher);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ private slots:
|
||||
void checkJavaFinished(JavaCheckResult result);
|
||||
|
||||
private:
|
||||
void printJavaInfo(const QString & version, const QString & architecture, const QString & vendor);
|
||||
void printJavaInfo(const QString & version, const QString & architecture, const QString & realArchitecture, const QString & vendor);
|
||||
void printSystemInfo(bool javaIsKnown, bool javaIs64bit);
|
||||
|
||||
private:
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "PostLaunchCommand.h"
|
||||
@ -27,9 +47,20 @@ PostLaunchCommand::PostLaunchCommand(LaunchTask *parent) : LaunchStep(parent)
|
||||
|
||||
void PostLaunchCommand::executeTask()
|
||||
{
|
||||
QString postlaunch_cmd = m_parent->substituteVariables(m_command);
|
||||
emit logLine(tr("Running Post-Launch command: %1").arg(postlaunch_cmd), MessageLevel::Launcher);
|
||||
m_process.start(postlaunch_cmd);
|
||||
//FIXME: where to put this?
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
auto args = QProcess::splitCommand(m_command);
|
||||
m_parent->substituteVariables(args);
|
||||
|
||||
emit logLine(tr("Running Post-Launch command: %1").arg(args.join(' ')), MessageLevel::Launcher);
|
||||
const QString program = args.takeFirst();
|
||||
m_process.start(program, args);
|
||||
#else
|
||||
m_parent->substituteVariables(m_command);
|
||||
|
||||
emit logLine(tr("Running Post-Launch command: %1").arg(m_command), MessageLevel::Launcher);
|
||||
m_process.start(m_command);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PostLaunchCommand::on_state(LoggedProcess::State state)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user