File Coverage

blib/lib/Perl/Dist/APPerl.pm
Criterion Covered Total %
statement 54 546 9.8
branch 1 278 0.3
condition 2 75 2.6
subroutine 18 47 38.3
pod 0 8 0.0
total 75 954 7.8


line stmt bran cond sub pod time code
1             package Perl::Dist::APPerl;
2             # Copyright (c) 2022 Gavin Hayes, see LICENSE in the root of the project
3 1     1   1217 use version 0.77; our $VERSION = qv(v0.3.0);
  1         2133  
  1         8  
4 1     1   102 use strict;
  1         3  
  1         19  
5 1     1   7 use warnings;
  1         2  
  1         30  
6 1     1   749 use JSON::PP 2.0104 qw(decode_json);
  1         17557  
  1         86  
7 1     1   8 use File::Path 2.07 qw(make_path remove_tree);
  1         20  
  1         99  
8 1     1   7 use Cwd qw(abs_path getcwd);
  1         2  
  1         50  
9 1     1   654 use Data::Dumper qw(Dumper);
  1         6523  
  1         77  
10 1     1   9 use File::Basename qw(basename dirname);
  1         2  
  1         123  
11 1     1   597 use File::Copy qw(copy move cp);
  1         2474  
  1         65  
12 1     1   567 use FindBin qw();
  1         1171  
  1         1758  
13 1     1   8 use Fcntl qw(SEEK_SET);
  1         2  
  1         54  
14 1     1   782 use Getopt::Long qw(GetOptionsFromArray);
  1         10871  
  1         4  
15             Getopt::Long::Configure qw(gnu_getopt);
16              
17             use constant {
18 1         87 START_WD => getcwd(),
19             PROJECT_FILE => 'apperl-project.json',
20 1     1   206 };
  1         3  
21             use constant {
22 1         82 PROJECT_TMP_DIR => (START_WD.'/.apperl'),
23 1     1   8 };
  1         2  
24             use constant {
25             # DEFDATAROOT is used if the XDG base directories cannot be found
26             DEFDATAROOT => defined($ENV{HOME}) ? $ENV{HOME}
27 1 0       86 : defined($ENV{APPDATA}) ? $ENV{APPDATA} .'/apperl'
    50          
28             : PROJECT_TMP_DIR.'/site',
29             PROJECT_TMP_CONFIG_FILE => (PROJECT_TMP_DIR.'/user-project.json'),
30 1     1   6 };
  1         2  
31             use constant {
32             SITE_CONFIG_DIR => ($ENV{XDG_CONFIG_HOME} // (DEFDATAROOT.'/.config')) . '/apperl',
33 1   50     68 SITE_REPO_DIR => ($ENV{XDG_DATA_HOME} // (DEFDATAROOT.'/.local/share')).'/apperl',
      50        
34 1     1   5 };
  1         2  
35             use constant {
36 1         2687 SITE_CONFIG_FILE => (SITE_CONFIG_DIR."/site.json"),
37 1     1   6 };
  1         2  
38              
39             sub _load_apperl_configs {
40              
41             # https://packages.debian.org/experimental/amd64/perl-base/filelist with tweaks
42 0     0     my @smallmanifest = (
43             '__perllib__/AutoLoader.pm',
44             '__perllib__/Carp.pm',
45             '__perllib__/Carp/Heavy.pm',
46             '__perlarchlib__/Config.pm',
47             '__perlarchlib__/Config_git.pl',
48             '__perlarchlib__/Config_heavy.pl',
49             '__perlarchlib__/Cwd.pm',
50             '__perlarchlib__/DynaLoader.pm',
51             '__perlarchlib__/Errno.pm',
52             '__perllib__/Exporter.pm',
53             '__perllib__/Exporter/Heavy.pm',
54             '__perlarchlib__/Fcntl.pm',
55             '__perllib__/File/Basename.pm',
56             '__perlarchlib__/File/Glob.pm',
57             '__perllib__/File/Path.pm',
58             '__perlarchlib__/File/Spec.pm',
59             '__perlarchlib__/File/Spec/Unix.pm',
60             '__perllib__/File/Temp.pm',
61             '__perllib__/FileHandle.pm',
62             '__perllib__/Getopt/Long.pm',
63             '__perlarchlib__/Hash/Util.pm',
64             '__perlarchlib__/IO.pm',
65             '__perlarchlib__/IO/File.pm',
66             '__perlarchlib__/IO/Handle.pm',
67             '__perlarchlib__/IO/Pipe.pm',
68             '__perlarchlib__/IO/Seekable.pm',
69             '__perlarchlib__/IO/Select.pm',
70             '__perlarchlib__/IO/Socket.pm',
71             '__perlarchlib__/IO/Socket/INET.pm',
72             '__perllib__/IO/Socket/IP.pm',
73             '__perlarchlib__/IO/Socket/UNIX.pm',
74             '__perllib__/IPC/Open2.pm',
75             '__perllib__/IPC/Open3.pm',
76             '__perlarchlib__/List/Util.pm',
77             '__perlarchlib__/POSIX.pm',
78             '__perlarchlib__/Scalar/Util.pm',
79             '__perllib__/SelectSaver.pm',
80             '__perlarchlib__/Socket.pm',
81             '__perllib__/Symbol.pm',
82             '__perllib__/Text/ParseWords.pm',
83             '__perllib__/Text/Tabs.pm',
84             '__perllib__/Text/Wrap.pm',
85             '__perllib__/Tie/Hash.pm',
86             '__perllib__/XSLoader.pm',
87             '__perlarchlib__/attributes.pm',
88             '__perllib__/base.pm',
89             '__perllib__/builtin.pm',
90             '__perllib__/bytes.pm',
91             '__perllib__/bytes_heavy.pl',
92             '__perllib__/constant.pm',
93             '__perllib__/feature.pm',
94             '__perllib__/fields.pm',
95             '__perllib__/integer.pm',
96             '__perlarchlib__/lib.pm',
97             '__perllib__/locale.pm',
98             '__perllib__/overload.pm',
99             '__perllib__/overloading.pm',
100             '__perllib__/parent.pm',
101             '__perlarchlib__/re.pm',
102             '__perllib__/strict.pm',
103             '__perllib__/unicore/To/Age.pl',
104             '__perllib__/unicore/To/Bc.pl',
105             '__perllib__/unicore/To/Bmg.pl',
106             '__perllib__/unicore/To/Bpb.pl',
107             '__perllib__/unicore/To/Bpt.pl',
108             '__perllib__/unicore/To/Cf.pl',
109             '__perllib__/unicore/To/Ea.pl',
110             '__perllib__/unicore/To/EqUIdeo.pl',
111             '__perllib__/unicore/To/GCB.pl',
112             '__perllib__/unicore/To/Gc.pl',
113             '__perllib__/unicore/To/Hst.pl',
114             '__perllib__/unicore/To/Identif2.pl',
115             '__perllib__/unicore/To/Identifi.pl',
116             '__perllib__/unicore/To/InPC.pl',
117             '__perllib__/unicore/To/InSC.pl',
118             '__perllib__/unicore/To/Isc.pl',
119             '__perllib__/unicore/To/Jg.pl',
120             '__perllib__/unicore/To/Jt.pl',
121             '__perllib__/unicore/To/Lb.pl',
122             '__perllib__/unicore/To/Lc.pl',
123             '__perllib__/unicore/To/NFCQC.pl',
124             '__perllib__/unicore/To/NFDQC.pl',
125             '__perllib__/unicore/To/NFKCCF.pl',
126             '__perllib__/unicore/To/NFKCQC.pl',
127             '__perllib__/unicore/To/NFKDQC.pl',
128             '__perllib__/unicore/To/Na1.pl',
129             '__perllib__/unicore/To/NameAlia.pl',
130             '__perllib__/unicore/To/Nt.pl',
131             '__perllib__/unicore/To/Nv.pl',
132             '__perllib__/unicore/To/PerlDeci.pl',
133             '__perllib__/unicore/To/SB.pl',
134             '__perllib__/unicore/To/Sc.pl',
135             '__perllib__/unicore/To/Scx.pl',
136             '__perllib__/unicore/To/Tc.pl',
137             '__perllib__/unicore/To/Uc.pl',
138             '__perllib__/unicore/To/Vo.pl',
139             '__perllib__/unicore/To/WB.pl',
140             '__perllib__/unicore/To/_PerlLB.pl',
141             '__perllib__/unicore/To/_PerlSCX.pl',
142             '__perllib__/unicore/lib/Age/NA.pl',
143             '__perllib__/unicore/lib/Age/V100.pl',
144             '__perllib__/unicore/lib/Age/V11.pl',
145             '__perllib__/unicore/lib/Age/V110.pl',
146             '__perllib__/unicore/lib/Age/V120.pl',
147             '__perllib__/unicore/lib/Age/V130.pl',
148             '__perllib__/unicore/lib/Age/V140.pl',
149             '__perllib__/unicore/lib/Age/V20.pl',
150             '__perllib__/unicore/lib/Age/V30.pl',
151             '__perllib__/unicore/lib/Age/V31.pl',
152             '__perllib__/unicore/lib/Age/V32.pl',
153             '__perllib__/unicore/lib/Age/V40.pl',
154             '__perllib__/unicore/lib/Age/V41.pl',
155             '__perllib__/unicore/lib/Age/V50.pl',
156             '__perllib__/unicore/lib/Age/V51.pl',
157             '__perllib__/unicore/lib/Age/V52.pl',
158             '__perllib__/unicore/lib/Age/V60.pl',
159             '__perllib__/unicore/lib/Age/V61.pl',
160             '__perllib__/unicore/lib/Age/V70.pl',
161             '__perllib__/unicore/lib/Age/V80.pl',
162             '__perllib__/unicore/lib/Age/V90.pl',
163             '__perllib__/unicore/lib/Alpha/Y.pl',
164             '__perllib__/unicore/lib/Bc/AL.pl',
165             '__perllib__/unicore/lib/Bc/AN.pl',
166             '__perllib__/unicore/lib/Bc/B.pl',
167             '__perllib__/unicore/lib/Bc/BN.pl',
168             '__perllib__/unicore/lib/Bc/CS.pl',
169             '__perllib__/unicore/lib/Bc/EN.pl',
170             '__perllib__/unicore/lib/Bc/ES.pl',
171             '__perllib__/unicore/lib/Bc/ET.pl',
172             '__perllib__/unicore/lib/Bc/L.pl',
173             '__perllib__/unicore/lib/Bc/NSM.pl',
174             '__perllib__/unicore/lib/Bc/ON.pl',
175             '__perllib__/unicore/lib/Bc/R.pl',
176             '__perllib__/unicore/lib/Bc/WS.pl',
177             '__perllib__/unicore/lib/BidiC/Y.pl',
178             '__perllib__/unicore/lib/BidiM/Y.pl',
179             '__perllib__/unicore/lib/Blk/NB.pl',
180             '__perllib__/unicore/lib/Bpt/C.pl',
181             '__perllib__/unicore/lib/Bpt/N.pl',
182             '__perllib__/unicore/lib/Bpt/O.pl',
183             '__perllib__/unicore/lib/CE/Y.pl',
184             '__perllib__/unicore/lib/CI/Y.pl',
185             '__perllib__/unicore/lib/CWCF/Y.pl',
186             '__perllib__/unicore/lib/CWCM/Y.pl',
187             '__perllib__/unicore/lib/CWKCF/Y.pl',
188             '__perllib__/unicore/lib/CWL/Y.pl',
189             '__perllib__/unicore/lib/CWT/Y.pl',
190             '__perllib__/unicore/lib/CWU/Y.pl',
191             '__perllib__/unicore/lib/Cased/Y.pl',
192             '__perllib__/unicore/lib/Ccc/A.pl',
193             '__perllib__/unicore/lib/Ccc/AL.pl',
194             '__perllib__/unicore/lib/Ccc/AR.pl',
195             '__perllib__/unicore/lib/Ccc/ATAR.pl',
196             '__perllib__/unicore/lib/Ccc/B.pl',
197             '__perllib__/unicore/lib/Ccc/BR.pl',
198             '__perllib__/unicore/lib/Ccc/DB.pl',
199             '__perllib__/unicore/lib/Ccc/NK.pl',
200             '__perllib__/unicore/lib/Ccc/NR.pl',
201             '__perllib__/unicore/lib/Ccc/OV.pl',
202             '__perllib__/unicore/lib/Ccc/VR.pl',
203             '__perllib__/unicore/lib/CompEx/Y.pl',
204             '__perllib__/unicore/lib/DI/Y.pl',
205             '__perllib__/unicore/lib/Dash/Y.pl',
206             '__perllib__/unicore/lib/Dep/Y.pl',
207             '__perllib__/unicore/lib/Dia/Y.pl',
208             '__perllib__/unicore/lib/Dt/Com.pl',
209             '__perllib__/unicore/lib/Dt/Enc.pl',
210             '__perllib__/unicore/lib/Dt/Fin.pl',
211             '__perllib__/unicore/lib/Dt/Font.pl',
212             '__perllib__/unicore/lib/Dt/Init.pl',
213             '__perllib__/unicore/lib/Dt/Iso.pl',
214             '__perllib__/unicore/lib/Dt/Med.pl',
215             '__perllib__/unicore/lib/Dt/Nar.pl',
216             '__perllib__/unicore/lib/Dt/Nb.pl',
217             '__perllib__/unicore/lib/Dt/NonCanon.pl',
218             '__perllib__/unicore/lib/Dt/Sqr.pl',
219             '__perllib__/unicore/lib/Dt/Sub.pl',
220             '__perllib__/unicore/lib/Dt/Sup.pl',
221             '__perllib__/unicore/lib/Dt/Vert.pl',
222             '__perllib__/unicore/lib/EBase/Y.pl',
223             '__perllib__/unicore/lib/EComp/Y.pl',
224             '__perllib__/unicore/lib/EPres/Y.pl',
225             '__perllib__/unicore/lib/Ea/A.pl',
226             '__perllib__/unicore/lib/Ea/H.pl',
227             '__perllib__/unicore/lib/Ea/N.pl',
228             '__perllib__/unicore/lib/Ea/Na.pl',
229             '__perllib__/unicore/lib/Ea/W.pl',
230             '__perllib__/unicore/lib/Emoji/Y.pl',
231             '__perllib__/unicore/lib/Ext/Y.pl',
232             '__perllib__/unicore/lib/ExtPict/Y.pl',
233             '__perllib__/unicore/lib/GCB/CN.pl',
234             '__perllib__/unicore/lib/GCB/EX.pl',
235             '__perllib__/unicore/lib/GCB/LV.pl',
236             '__perllib__/unicore/lib/GCB/LVT.pl',
237             '__perllib__/unicore/lib/GCB/PP.pl',
238             '__perllib__/unicore/lib/GCB/SM.pl',
239             '__perllib__/unicore/lib/GCB/XX.pl',
240             '__perllib__/unicore/lib/Gc/C.pl',
241             '__perllib__/unicore/lib/Gc/Cf.pl',
242             '__perllib__/unicore/lib/Gc/Cn.pl',
243             '__perllib__/unicore/lib/Gc/L.pl',
244             '__perllib__/unicore/lib/Gc/LC.pl',
245             '__perllib__/unicore/lib/Gc/Ll.pl',
246             '__perllib__/unicore/lib/Gc/Lm.pl',
247             '__perllib__/unicore/lib/Gc/Lo.pl',
248             '__perllib__/unicore/lib/Gc/Lu.pl',
249             '__perllib__/unicore/lib/Gc/M.pl',
250             '__perllib__/unicore/lib/Gc/Mc.pl',
251             '__perllib__/unicore/lib/Gc/Me.pl',
252             '__perllib__/unicore/lib/Gc/Mn.pl',
253             '__perllib__/unicore/lib/Gc/N.pl',
254             '__perllib__/unicore/lib/Gc/Nd.pl',
255             '__perllib__/unicore/lib/Gc/Nl.pl',
256             '__perllib__/unicore/lib/Gc/No.pl',
257             '__perllib__/unicore/lib/Gc/P.pl',
258             '__perllib__/unicore/lib/Gc/Pc.pl',
259             '__perllib__/unicore/lib/Gc/Pd.pl',
260             '__perllib__/unicore/lib/Gc/Pe.pl',
261             '__perllib__/unicore/lib/Gc/Pf.pl',
262             '__perllib__/unicore/lib/Gc/Pi.pl',
263             '__perllib__/unicore/lib/Gc/Po.pl',
264             '__perllib__/unicore/lib/Gc/Ps.pl',
265             '__perllib__/unicore/lib/Gc/S.pl',
266             '__perllib__/unicore/lib/Gc/Sc.pl',
267             '__perllib__/unicore/lib/Gc/Sk.pl',
268             '__perllib__/unicore/lib/Gc/Sm.pl',
269             '__perllib__/unicore/lib/Gc/So.pl',
270             '__perllib__/unicore/lib/Gc/Z.pl',
271             '__perllib__/unicore/lib/Gc/Zs.pl',
272             '__perllib__/unicore/lib/GrBase/Y.pl',
273             '__perllib__/unicore/lib/GrExt/Y.pl',
274             '__perllib__/unicore/lib/Hex/Y.pl',
275             '__perllib__/unicore/lib/Hst/NA.pl',
276             '__perllib__/unicore/lib/Hyphen/T.pl',
277             '__perllib__/unicore/lib/IDC/Y.pl',
278             '__perllib__/unicore/lib/IDS/Y.pl',
279             '__perllib__/unicore/lib/IdStatus/Allowed.pl',
280             '__perllib__/unicore/lib/IdStatus/Restrict.pl',
281             '__perllib__/unicore/lib/IdType/DefaultI.pl',
282             '__perllib__/unicore/lib/IdType/Exclusio.pl',
283             '__perllib__/unicore/lib/IdType/Inclusio.pl',
284             '__perllib__/unicore/lib/IdType/LimitedU.pl',
285             '__perllib__/unicore/lib/IdType/NotChara.pl',
286             '__perllib__/unicore/lib/IdType/NotNFKC.pl',
287             '__perllib__/unicore/lib/IdType/NotXID.pl',
288             '__perllib__/unicore/lib/IdType/Obsolete.pl',
289             '__perllib__/unicore/lib/IdType/Recommen.pl',
290             '__perllib__/unicore/lib/IdType/Technica.pl',
291             '__perllib__/unicore/lib/IdType/Uncommon.pl',
292             '__perllib__/unicore/lib/Ideo/Y.pl',
293             '__perllib__/unicore/lib/In/10_0.pl',
294             '__perllib__/unicore/lib/In/11_0.pl',
295             '__perllib__/unicore/lib/In/12_0.pl',
296             '__perllib__/unicore/lib/In/12_1.pl',
297             '__perllib__/unicore/lib/In/13_0.pl',
298             '__perllib__/unicore/lib/In/14_0.pl',
299             '__perllib__/unicore/lib/In/2_0.pl',
300             '__perllib__/unicore/lib/In/2_1.pl',
301             '__perllib__/unicore/lib/In/3_0.pl',
302             '__perllib__/unicore/lib/In/3_1.pl',
303             '__perllib__/unicore/lib/In/3_2.pl',
304             '__perllib__/unicore/lib/In/4_0.pl',
305             '__perllib__/unicore/lib/In/4_1.pl',
306             '__perllib__/unicore/lib/In/5_0.pl',
307             '__perllib__/unicore/lib/In/5_1.pl',
308             '__perllib__/unicore/lib/In/5_2.pl',
309             '__perllib__/unicore/lib/In/6_0.pl',
310             '__perllib__/unicore/lib/In/6_1.pl',
311             '__perllib__/unicore/lib/In/6_2.pl',
312             '__perllib__/unicore/lib/In/6_3.pl',
313             '__perllib__/unicore/lib/In/7_0.pl',
314             '__perllib__/unicore/lib/In/8_0.pl',
315             '__perllib__/unicore/lib/In/9_0.pl',
316             '__perllib__/unicore/lib/InPC/Bottom.pl',
317             '__perllib__/unicore/lib/InPC/BottomAn.pl',
318             '__perllib__/unicore/lib/InPC/Left.pl',
319             '__perllib__/unicore/lib/InPC/LeftAndR.pl',
320             '__perllib__/unicore/lib/InPC/NA.pl',
321             '__perllib__/unicore/lib/InPC/Overstru.pl',
322             '__perllib__/unicore/lib/InPC/Right.pl',
323             '__perllib__/unicore/lib/InPC/Top.pl',
324             '__perllib__/unicore/lib/InPC/TopAndBo.pl',
325             '__perllib__/unicore/lib/InPC/TopAndL2.pl',
326             '__perllib__/unicore/lib/InPC/TopAndLe.pl',
327             '__perllib__/unicore/lib/InPC/TopAndRi.pl',
328             '__perllib__/unicore/lib/InPC/VisualOr.pl',
329             '__perllib__/unicore/lib/InSC/Avagraha.pl',
330             '__perllib__/unicore/lib/InSC/Bindu.pl',
331             '__perllib__/unicore/lib/InSC/Cantilla.pl',
332             '__perllib__/unicore/lib/InSC/Consona2.pl',
333             '__perllib__/unicore/lib/InSC/Consona3.pl',
334             '__perllib__/unicore/lib/InSC/Consona4.pl',
335             '__perllib__/unicore/lib/InSC/Consona5.pl',
336             '__perllib__/unicore/lib/InSC/Consona6.pl',
337             '__perllib__/unicore/lib/InSC/Consona7.pl',
338             '__perllib__/unicore/lib/InSC/Consona8.pl',
339             '__perllib__/unicore/lib/InSC/Consonan.pl',
340             '__perllib__/unicore/lib/InSC/Invisibl.pl',
341             '__perllib__/unicore/lib/InSC/Nukta.pl',
342             '__perllib__/unicore/lib/InSC/Number.pl',
343             '__perllib__/unicore/lib/InSC/Other.pl',
344             '__perllib__/unicore/lib/InSC/PureKill.pl',
345             '__perllib__/unicore/lib/InSC/Syllable.pl',
346             '__perllib__/unicore/lib/InSC/ToneMark.pl',
347             '__perllib__/unicore/lib/InSC/Virama.pl',
348             '__perllib__/unicore/lib/InSC/Visarga.pl',
349             '__perllib__/unicore/lib/InSC/Vowel.pl',
350             '__perllib__/unicore/lib/InSC/VowelDep.pl',
351             '__perllib__/unicore/lib/InSC/VowelInd.pl',
352             '__perllib__/unicore/lib/Jg/Ain.pl',
353             '__perllib__/unicore/lib/Jg/Alef.pl',
354             '__perllib__/unicore/lib/Jg/Beh.pl',
355             '__perllib__/unicore/lib/Jg/Dal.pl',
356             '__perllib__/unicore/lib/Jg/FarsiYeh.pl',
357             '__perllib__/unicore/lib/Jg/Feh.pl',
358             '__perllib__/unicore/lib/Jg/Gaf.pl',
359             '__perllib__/unicore/lib/Jg/Hah.pl',
360             '__perllib__/unicore/lib/Jg/HanifiRo.pl',
361             '__perllib__/unicore/lib/Jg/Kaf.pl',
362             '__perllib__/unicore/lib/Jg/Lam.pl',
363             '__perllib__/unicore/lib/Jg/NoJoinin.pl',
364             '__perllib__/unicore/lib/Jg/Noon.pl',
365             '__perllib__/unicore/lib/Jg/Qaf.pl',
366             '__perllib__/unicore/lib/Jg/Reh.pl',
367             '__perllib__/unicore/lib/Jg/Sad.pl',
368             '__perllib__/unicore/lib/Jg/Seen.pl',
369             '__perllib__/unicore/lib/Jg/Tah.pl',
370             '__perllib__/unicore/lib/Jg/Waw.pl',
371             '__perllib__/unicore/lib/Jg/Yeh.pl',
372             '__perllib__/unicore/lib/Jt/C.pl',
373             '__perllib__/unicore/lib/Jt/D.pl',
374             '__perllib__/unicore/lib/Jt/L.pl',
375             '__perllib__/unicore/lib/Jt/R.pl',
376             '__perllib__/unicore/lib/Jt/T.pl',
377             '__perllib__/unicore/lib/Jt/U.pl',
378             '__perllib__/unicore/lib/Lb/AI.pl',
379             '__perllib__/unicore/lib/Lb/AL.pl',
380             '__perllib__/unicore/lib/Lb/BA.pl',
381             '__perllib__/unicore/lib/Lb/BB.pl',
382             '__perllib__/unicore/lib/Lb/CJ.pl',
383             '__perllib__/unicore/lib/Lb/CL.pl',
384             '__perllib__/unicore/lib/Lb/CM.pl',
385             '__perllib__/unicore/lib/Lb/EX.pl',
386             '__perllib__/unicore/lib/Lb/GL.pl',
387             '__perllib__/unicore/lib/Lb/ID.pl',
388             '__perllib__/unicore/lib/Lb/IN.pl',
389             '__perllib__/unicore/lib/Lb/IS.pl',
390             '__perllib__/unicore/lib/Lb/NS.pl',
391             '__perllib__/unicore/lib/Lb/NU.pl',
392             '__perllib__/unicore/lib/Lb/OP.pl',
393             '__perllib__/unicore/lib/Lb/PO.pl',
394             '__perllib__/unicore/lib/Lb/PR.pl',
395             '__perllib__/unicore/lib/Lb/QU.pl',
396             '__perllib__/unicore/lib/Lb/SA.pl',
397             '__perllib__/unicore/lib/Lb/XX.pl',
398             '__perllib__/unicore/lib/Lower/Y.pl',
399             '__perllib__/unicore/lib/Math/Y.pl',
400             '__perllib__/unicore/lib/NFCQC/M.pl',
401             '__perllib__/unicore/lib/NFCQC/Y.pl',
402             '__perllib__/unicore/lib/NFDQC/N.pl',
403             '__perllib__/unicore/lib/NFDQC/Y.pl',
404             '__perllib__/unicore/lib/NFKCQC/N.pl',
405             '__perllib__/unicore/lib/NFKCQC/Y.pl',
406             '__perllib__/unicore/lib/NFKDQC/N.pl',
407             '__perllib__/unicore/lib/NFKDQC/Y.pl',
408             '__perllib__/unicore/lib/Nt/Di.pl',
409             '__perllib__/unicore/lib/Nt/None.pl',
410             '__perllib__/unicore/lib/Nt/Nu.pl',
411             '__perllib__/unicore/lib/Nv/0.pl',
412             '__perllib__/unicore/lib/Nv/1.pl',
413             '__perllib__/unicore/lib/Nv/10.pl',
414             '__perllib__/unicore/lib/Nv/100.pl',
415             '__perllib__/unicore/lib/Nv/1000.pl',
416             '__perllib__/unicore/lib/Nv/10000.pl',
417             '__perllib__/unicore/lib/Nv/100000.pl',
418             '__perllib__/unicore/lib/Nv/11.pl',
419             '__perllib__/unicore/lib/Nv/12.pl',
420             '__perllib__/unicore/lib/Nv/13.pl',
421             '__perllib__/unicore/lib/Nv/14.pl',
422             '__perllib__/unicore/lib/Nv/15.pl',
423             '__perllib__/unicore/lib/Nv/16.pl',
424             '__perllib__/unicore/lib/Nv/17.pl',
425             '__perllib__/unicore/lib/Nv/18.pl',
426             '__perllib__/unicore/lib/Nv/19.pl',
427             '__perllib__/unicore/lib/Nv/1_16.pl',
428             '__perllib__/unicore/lib/Nv/1_2.pl',
429             '__perllib__/unicore/lib/Nv/1_3.pl',
430             '__perllib__/unicore/lib/Nv/1_4.pl',
431             '__perllib__/unicore/lib/Nv/1_6.pl',
432             '__perllib__/unicore/lib/Nv/1_8.pl',
433             '__perllib__/unicore/lib/Nv/2.pl',
434             '__perllib__/unicore/lib/Nv/20.pl',
435             '__perllib__/unicore/lib/Nv/200.pl',
436             '__perllib__/unicore/lib/Nv/2000.pl',
437             '__perllib__/unicore/lib/Nv/20000.pl',
438             '__perllib__/unicore/lib/Nv/2_3.pl',
439             '__perllib__/unicore/lib/Nv/3.pl',
440             '__perllib__/unicore/lib/Nv/30.pl',
441             '__perllib__/unicore/lib/Nv/300.pl',
442             '__perllib__/unicore/lib/Nv/3000.pl',
443             '__perllib__/unicore/lib/Nv/30000.pl',
444             '__perllib__/unicore/lib/Nv/3_16.pl',
445             '__perllib__/unicore/lib/Nv/3_4.pl',
446             '__perllib__/unicore/lib/Nv/4.pl',
447             '__perllib__/unicore/lib/Nv/40.pl',
448             '__perllib__/unicore/lib/Nv/400.pl',
449             '__perllib__/unicore/lib/Nv/4000.pl',
450             '__perllib__/unicore/lib/Nv/40000.pl',
451             '__perllib__/unicore/lib/Nv/5.pl',
452             '__perllib__/unicore/lib/Nv/50.pl',
453             '__perllib__/unicore/lib/Nv/500.pl',
454             '__perllib__/unicore/lib/Nv/5000.pl',
455             '__perllib__/unicore/lib/Nv/50000.pl',
456             '__perllib__/unicore/lib/Nv/6.pl',
457             '__perllib__/unicore/lib/Nv/60.pl',
458             '__perllib__/unicore/lib/Nv/600.pl',
459             '__perllib__/unicore/lib/Nv/6000.pl',
460             '__perllib__/unicore/lib/Nv/60000.pl',
461             '__perllib__/unicore/lib/Nv/7.pl',
462             '__perllib__/unicore/lib/Nv/70.pl',
463             '__perllib__/unicore/lib/Nv/700.pl',
464             '__perllib__/unicore/lib/Nv/7000.pl',
465             '__perllib__/unicore/lib/Nv/70000.pl',
466             '__perllib__/unicore/lib/Nv/8.pl',
467             '__perllib__/unicore/lib/Nv/80.pl',
468             '__perllib__/unicore/lib/Nv/800.pl',
469             '__perllib__/unicore/lib/Nv/8000.pl',
470             '__perllib__/unicore/lib/Nv/80000.pl',
471             '__perllib__/unicore/lib/Nv/9.pl',
472             '__perllib__/unicore/lib/Nv/90.pl',
473             '__perllib__/unicore/lib/Nv/900.pl',
474             '__perllib__/unicore/lib/Nv/9000.pl',
475             '__perllib__/unicore/lib/Nv/90000.pl',
476             '__perllib__/unicore/lib/PCM/Y.pl',
477             '__perllib__/unicore/lib/PatSyn/Y.pl',
478             '__perllib__/unicore/lib/Perl/Alnum.pl',
479             '__perllib__/unicore/lib/Perl/Assigned.pl',
480             '__perllib__/unicore/lib/Perl/Blank.pl',
481             '__perllib__/unicore/lib/Perl/Graph.pl',
482             '__perllib__/unicore/lib/Perl/PerlWord.pl',
483             '__perllib__/unicore/lib/Perl/PosixPun.pl',
484             '__perllib__/unicore/lib/Perl/Print.pl',
485             '__perllib__/unicore/lib/Perl/SpacePer.pl',
486             '__perllib__/unicore/lib/Perl/Title.pl',
487             '__perllib__/unicore/lib/Perl/Word.pl',
488             '__perllib__/unicore/lib/Perl/XPosixPu.pl',
489             '__perllib__/unicore/lib/Perl/_PerlAny.pl',
490             '__perllib__/unicore/lib/Perl/_PerlCh2.pl',
491             '__perllib__/unicore/lib/Perl/_PerlCha.pl',
492             '__perllib__/unicore/lib/Perl/_PerlFol.pl',
493             '__perllib__/unicore/lib/Perl/_PerlIDC.pl',
494             '__perllib__/unicore/lib/Perl/_PerlIDS.pl',
495             '__perllib__/unicore/lib/Perl/_PerlIsI.pl',
496             '__perllib__/unicore/lib/Perl/_PerlNch.pl',
497             '__perllib__/unicore/lib/Perl/_PerlPat.pl',
498             '__perllib__/unicore/lib/Perl/_PerlPr2.pl',
499             '__perllib__/unicore/lib/Perl/_PerlPro.pl',
500             '__perllib__/unicore/lib/Perl/_PerlQuo.pl',
501             '__perllib__/unicore/lib/QMark/Y.pl',
502             '__perllib__/unicore/lib/SB/AT.pl',
503             '__perllib__/unicore/lib/SB/CL.pl',
504             '__perllib__/unicore/lib/SB/EX.pl',
505             '__perllib__/unicore/lib/SB/FO.pl',
506             '__perllib__/unicore/lib/SB/LE.pl',
507             '__perllib__/unicore/lib/SB/LO.pl',
508             '__perllib__/unicore/lib/SB/NU.pl',
509             '__perllib__/unicore/lib/SB/SC.pl',
510             '__perllib__/unicore/lib/SB/ST.pl',
511             '__perllib__/unicore/lib/SB/Sp.pl',
512             '__perllib__/unicore/lib/SB/UP.pl',
513             '__perllib__/unicore/lib/SB/XX.pl',
514             '__perllib__/unicore/lib/SD/Y.pl',
515             '__perllib__/unicore/lib/STerm/Y.pl',
516             '__perllib__/unicore/lib/Sc/Arab.pl',
517             '__perllib__/unicore/lib/Sc/Beng.pl',
518             '__perllib__/unicore/lib/Sc/Cprt.pl',
519             '__perllib__/unicore/lib/Sc/Cyrl.pl',
520             '__perllib__/unicore/lib/Sc/Deva.pl',
521             '__perllib__/unicore/lib/Sc/Dupl.pl',
522             '__perllib__/unicore/lib/Sc/Geor.pl',
523             '__perllib__/unicore/lib/Sc/Glag.pl',
524             '__perllib__/unicore/lib/Sc/Gong.pl',
525             '__perllib__/unicore/lib/Sc/Gonm.pl',
526             '__perllib__/unicore/lib/Sc/Gran.pl',
527             '__perllib__/unicore/lib/Sc/Grek.pl',
528             '__perllib__/unicore/lib/Sc/Gujr.pl',
529             '__perllib__/unicore/lib/Sc/Guru.pl',
530             '__perllib__/unicore/lib/Sc/Han.pl',
531             '__perllib__/unicore/lib/Sc/Hang.pl',
532             '__perllib__/unicore/lib/Sc/Hira.pl',
533             '__perllib__/unicore/lib/Sc/Kana.pl',
534             '__perllib__/unicore/lib/Sc/Knda.pl',
535             '__perllib__/unicore/lib/Sc/Latn.pl',
536             '__perllib__/unicore/lib/Sc/Limb.pl',
537             '__perllib__/unicore/lib/Sc/Linb.pl',
538             '__perllib__/unicore/lib/Sc/Mlym.pl',
539             '__perllib__/unicore/lib/Sc/Mong.pl',
540             '__perllib__/unicore/lib/Sc/Mult.pl',
541             '__perllib__/unicore/lib/Sc/Orya.pl',
542             '__perllib__/unicore/lib/Sc/Sinh.pl',
543             '__perllib__/unicore/lib/Sc/Syrc.pl',
544             '__perllib__/unicore/lib/Sc/Taml.pl',
545             '__perllib__/unicore/lib/Sc/Telu.pl',
546             '__perllib__/unicore/lib/Sc/Zinh.pl',
547             '__perllib__/unicore/lib/Sc/Zyyy.pl',
548             '__perllib__/unicore/lib/Scx/Adlm.pl',
549             '__perllib__/unicore/lib/Scx/Arab.pl',
550             '__perllib__/unicore/lib/Scx/Armn.pl',
551             '__perllib__/unicore/lib/Scx/Beng.pl',
552             '__perllib__/unicore/lib/Scx/Bhks.pl',
553             '__perllib__/unicore/lib/Scx/Bopo.pl',
554             '__perllib__/unicore/lib/Scx/Cakm.pl',
555             '__perllib__/unicore/lib/Scx/Cham.pl',
556             '__perllib__/unicore/lib/Scx/Copt.pl',
557             '__perllib__/unicore/lib/Scx/Cprt.pl',
558             '__perllib__/unicore/lib/Scx/Cyrl.pl',
559             '__perllib__/unicore/lib/Scx/Deva.pl',
560             '__perllib__/unicore/lib/Scx/Diak.pl',
561             '__perllib__/unicore/lib/Scx/Dupl.pl',
562             '__perllib__/unicore/lib/Scx/Ethi.pl',
563             '__perllib__/unicore/lib/Scx/Geor.pl',
564             '__perllib__/unicore/lib/Scx/Glag.pl',
565             '__perllib__/unicore/lib/Scx/Gong.pl',
566             '__perllib__/unicore/lib/Scx/Gonm.pl',
567             '__perllib__/unicore/lib/Scx/Gran.pl',
568             '__perllib__/unicore/lib/Scx/Grek.pl',
569             '__perllib__/unicore/lib/Scx/Gujr.pl',
570             '__perllib__/unicore/lib/Scx/Guru.pl',
571             '__perllib__/unicore/lib/Scx/Han.pl',
572             '__perllib__/unicore/lib/Scx/Hang.pl',
573             '__perllib__/unicore/lib/Scx/Hebr.pl',
574             '__perllib__/unicore/lib/Scx/Hira.pl',
575             '__perllib__/unicore/lib/Scx/Hmng.pl',
576             '__perllib__/unicore/lib/Scx/Hmnp.pl',
577             '__perllib__/unicore/lib/Scx/Kana.pl',
578             '__perllib__/unicore/lib/Scx/Khar.pl',
579             '__perllib__/unicore/lib/Scx/Khmr.pl',
580             '__perllib__/unicore/lib/Scx/Khoj.pl',
581             '__perllib__/unicore/lib/Scx/Knda.pl',
582             '__perllib__/unicore/lib/Scx/Kthi.pl',
583             '__perllib__/unicore/lib/Scx/Lana.pl',
584             '__perllib__/unicore/lib/Scx/Lao.pl',
585             '__perllib__/unicore/lib/Scx/Latn.pl',
586             '__perllib__/unicore/lib/Scx/Limb.pl',
587             '__perllib__/unicore/lib/Scx/Lina.pl',
588             '__perllib__/unicore/lib/Scx/Linb.pl',
589             '__perllib__/unicore/lib/Scx/Mlym.pl',
590             '__perllib__/unicore/lib/Scx/Mong.pl',
591             '__perllib__/unicore/lib/Scx/Mult.pl',
592             '__perllib__/unicore/lib/Scx/Mymr.pl',
593             '__perllib__/unicore/lib/Scx/Nand.pl',
594             '__perllib__/unicore/lib/Scx/Nko.pl',
595             '__perllib__/unicore/lib/Scx/Orya.pl',
596             '__perllib__/unicore/lib/Scx/Phlp.pl',
597             '__perllib__/unicore/lib/Scx/Rohg.pl',
598             '__perllib__/unicore/lib/Scx/Shrd.pl',
599             '__perllib__/unicore/lib/Scx/Sind.pl',
600             '__perllib__/unicore/lib/Scx/Sinh.pl',
601             '__perllib__/unicore/lib/Scx/Syrc.pl',
602             '__perllib__/unicore/lib/Scx/Tagb.pl',
603             '__perllib__/unicore/lib/Scx/Takr.pl',
604             '__perllib__/unicore/lib/Scx/Talu.pl',
605             '__perllib__/unicore/lib/Scx/Taml.pl',
606             '__perllib__/unicore/lib/Scx/Tang.pl',
607             '__perllib__/unicore/lib/Scx/Telu.pl',
608             '__perllib__/unicore/lib/Scx/Thaa.pl',
609             '__perllib__/unicore/lib/Scx/Tibt.pl',
610             '__perllib__/unicore/lib/Scx/Tirh.pl',
611             '__perllib__/unicore/lib/Scx/Vith.pl',
612             '__perllib__/unicore/lib/Scx/Xsux.pl',
613             '__perllib__/unicore/lib/Scx/Yezi.pl',
614             '__perllib__/unicore/lib/Scx/Yi.pl',
615             '__perllib__/unicore/lib/Scx/Zinh.pl',
616             '__perllib__/unicore/lib/Scx/Zyyy.pl',
617             '__perllib__/unicore/lib/Scx/Zzzz.pl',
618             '__perllib__/unicore/lib/Term/Y.pl',
619             '__perllib__/unicore/lib/UIdeo/Y.pl',
620             '__perllib__/unicore/lib/Upper/Y.pl',
621             '__perllib__/unicore/lib/VS/Y.pl',
622             '__perllib__/unicore/lib/Vo/R.pl',
623             '__perllib__/unicore/lib/Vo/Tr.pl',
624             '__perllib__/unicore/lib/Vo/Tu.pl',
625             '__perllib__/unicore/lib/Vo/U.pl',
626             '__perllib__/unicore/lib/WB/EX.pl',
627             '__perllib__/unicore/lib/WB/Extend.pl',
628             '__perllib__/unicore/lib/WB/FO.pl',
629             '__perllib__/unicore/lib/WB/HL.pl',
630             '__perllib__/unicore/lib/WB/KA.pl',
631             '__perllib__/unicore/lib/WB/LE.pl',
632             '__perllib__/unicore/lib/WB/MB.pl',
633             '__perllib__/unicore/lib/WB/ML.pl',
634             '__perllib__/unicore/lib/WB/MN.pl',
635             '__perllib__/unicore/lib/WB/NU.pl',
636             '__perllib__/unicore/lib/WB/WSegSpac.pl',
637             '__perllib__/unicore/lib/WB/XX.pl',
638             '__perllib__/unicore/lib/XIDC/Y.pl',
639             '__perllib__/unicore/lib/XIDS/Y.pl',
640             '__perllib__/utf8.pm',
641             '__perllib__/vars.pm',
642             '__perllib__/warnings.pm',
643             '__perllib__/warnings/register.pm',
644             );
645              
646 0           my %defconfig = (
647             cosmo_remotes => {
648             origin => 'https://github.com/G4Vi/cosmopolitan',
649             upstream => 'https://github.com/jart/cosmopolitan',
650             },
651             perl_remotes => {
652             origin => 'https://github.com/G4Vi/perl5',
653             },
654             apperl_configs => {
655             'nobuild-v0.1.0' => {
656             desc => 'base nobuild config',
657             dest => 'perl-nobuild.com',
658             MANIFEST => ['lib', 'bin'],
659             zip_extra_files => {},
660             nobuild_perl_bin => ['src/perl.com', $^X],
661             },
662             'v5.36.0-full-v0.1.0' => {
663             desc => 'Full perl v5.36.0 built with Cosmopolitan Libc 2.2',
664             perl_id => 'b22da6b83c37604132694ead0bdcf61690f74a53',
665             cosmo_id => '52f1db7220935cfcf2c8e583678f5ccc4b5bbacd',
666             cosmo_mode => '',
667             cosmo_ape_loader => 'ape-no-modify-self.o',
668             perl_flags => ['-Dprefix=/zip', '-Uversiononly', '-Dmyhostname=cosmo', '-Dmydomain=invalid'],
669             perl_extra_flags => ['-Doptimize=-Os', '-de'],
670             dest => 'perl.com',
671             MANIFEST => ['lib', 'bin'],
672             'include_Perl-Dist-APPerl' => 1,
673             perl_repo_files => {},
674             zip_extra_files => {},
675             },
676             'v5.36.0-full-v0.1.0-vista' => {
677             desc => 'Full perl v5.36.0, but with non-standard Cosmopolitan Libc that still supports vista',
678             base => 'v5.36.0-full-v0.1.0',
679             cosmo_id => '9c5a7795add7add5a214afce27d896084e0861c5',
680             dest => 'perl-vista.com',
681             },
682             'v5.36.0-small-v0.1.0' => {
683             desc => 'small perl v5.36.0 built with Cosmopolitan Libc 2.2',
684             base => 'v5.36.0-full-v0.1.0',
685             perl_onlyextensions => [qw(Cwd Fcntl File/Glob Hash/Util IO List/Util POSIX Socket attributes re)],
686             perl_extra_flags => ['-Doptimize=-Os', '-de'],
687             MANIFEST => \@smallmanifest,
688             'include_Perl-Dist-APPerl' => 0,
689             dest => 'perl-small.com',
690             },
691             'v5.36.0-small-v0.1.0-vista' => {
692             desc => 'small perl v5.36.0, but with non-standard Cosmopolitan Libc that still supports vista',
693             base => 'v5.36.0-small-v0.1.0',
694             cosmo_id => '9c5a7795add7add5a214afce27d896084e0861c5',
695             dest => 'perl-small-vista.com',
696             },
697             'full' => { desc => 'moving target: full', base => 'v5.36.0-full-v0.1.0', perl_id => 'ca87f329eeb075c0fe7ac803eb933f36af45a69b', cosmo_id => 'eb69a42863ef602a951249b801ceed5f74cbb11c', '+perl_extra_flags' => ['-Dprivlib=/zip/lib/perl5', '-Darchlib=/zip/lib/perl5/x86_64-cosmo', '-Dsitelib=/zip/lib/perl5/site_perl', '-Dsitearch=/zip/lib/perl5/site_perl/x86_64-cosmo']},
698             'full-vista' => { desc => 'moving target: full for vista', base => 'v5.36.0-full-v0.1.0-vista', perl_id => 'ca87f329eeb075c0fe7ac803eb933f36af45a69b', cosmo_id => '0740e68ea0e801168a5e354be5ad237a4795549a', '+perl_extra_flags' => ['-Dprivlib=/zip/lib/perl5', '-Darchlib=/zip/lib/perl5/x86_64-cosmo', '-Dsitelib=/zip/lib/perl5/site_perl', '-Dsitearch=/zip/lib/perl5/site_perl/x86_64-cosmo']},
699             'small' => { desc => 'moving target: small', base => 'v5.36.0-small-v0.1.0', perl_id => 'ca87f329eeb075c0fe7ac803eb933f36af45a69b', cosmo_id => 'eb69a42863ef602a951249b801ceed5f74cbb11c', '+perl_extra_flags' => ['-Dprivlib=/zip/lib/perl5', '-Darchlib=/zip/lib/perl5/x86_64-cosmo', '-Dsitelib=/zip/lib/perl5/site_perl', '-Dsitearch=/zip/lib/perl5/site_perl/x86_64-cosmo']},
700             'small-vista' => { desc => 'moving target: small for vista', base => 'v5.36.0-small-v0.1.0-vista', perl_id => 'ca87f329eeb075c0fe7ac803eb933f36af45a69b', cosmo_id => '0740e68ea0e801168a5e354be5ad237a4795549a', '+perl_extra_flags' => ['-Dprivlib=/zip/lib/perl5', '-Darchlib=/zip/lib/perl5/x86_64-cosmo', '-Dsitelib=/zip/lib/perl5/site_perl', '-Dsitearch=/zip/lib/perl5/site_perl/x86_64-cosmo']},
701             # development configs
702             'dbg' => { base => 'full', perl_extra_flags => ['-Doptimize=-g3 -gdwarf-4', '-de'], cosmo_mode => 'dbg', cosmo_id => '52f1db7220935cfcf2c8e583678f5ccc4b5bbacd'},
703             dontuse_threads => {
704             desc => "not recommended, threaded build is buggy",
705             base => 'full',
706             perl_extra_flags => ['-Doptimize=-Os', '-Dusethreads', '-de'],
707             perl_id => 'cosmo-apperl'
708             },
709             perl_cosmo_dev => {
710             desc => "For developing cosmo platform perl without apperl additions",
711             base => 'full',
712             perl_id => 'cosmo'
713             },
714             perl_cosmo_dev_on_vista => {
715             desc => "For developing cosmo platform perl without apperl additions on vista",
716             base => "perl_cosmo_dev",
717             cosmo_id => '0740e68ea0e801168a5e354be5ad237a4795549a',
718             },
719             perl_apperl_dev => {
720             desc => "For developing apperl",
721             base => 'full',
722             perl_id => 'cosmo-apperl'
723             }
724             }
725             );
726 0           $defconfig{defaultconfig} = $defconfig{apperl_configs}{full}{base};
727              
728 0           my $projectconfig = _load_json(PROJECT_FILE);
729 0 0         if($projectconfig) {
730 0           foreach my $projkey (keys %$projectconfig) {
731 0 0         if($projkey ne 'apperl_configs') {
732 0           $defconfig{$projkey} = $projectconfig->{$projkey};
733             }
734             else {
735 0           $defconfig{$projkey} = {%{$defconfig{$projkey}}, %{$projectconfig->{$projkey}}};
  0            
  0            
736             }
737             }
738             }
739 0           return \%defconfig;
740             }
741              
742             sub _build_def_config {
743             return {
744 0   0 0     base => ($_[0] // 'nobuild-v0.1.0'),
745             desc => 'description of this config',
746             dest => 'perl.com'
747             };
748             }
749              
750             sub Init {
751 0     0 0   my ($defaultconfig, $base) = @_;
752             # validate
753 0 0         die "Cannot create project config, it already exists ".PROJECT_FILE if(-e PROJECT_FILE);
754 0           my $Configs = _load_apperl_configs();
755 0 0         if(defined $base) {
756 0 0         $defaultconfig or die "Cannot set base without name for new config";
757 0 0         if(exists $Configs->{apperl_configs}{$defaultconfig}) {
758 0           die "Cannot set base for $defaultconfig, $defaultconfig already exists ";
759             }
760 0 0         exists $Configs->{apperl_configs}{$base} or die "base config $base does not exist";
761             }
762              
763             # create project config
764 0   0       my %jsondata = ( 'defaultconfig' => ($defaultconfig // 'nobuild-v0.1.0'));
765 0 0 0       if($defaultconfig && ! exists $Configs->{apperl_configs}{$defaultconfig}) {
766             $jsondata{apperl_configs} = {
767 0           $defaultconfig => _build_def_config($base),
768             };
769             }
770 0           print "writing new project\n";
771 0           _write_json(PROJECT_FILE, \%jsondata);
772              
773             # checkout default config
774 0           Set($jsondata{defaultconfig});
775             }
776              
777             sub NewConfig {
778 0     0 0   my ($name, $base) = @_;
779 0 0         $name or die "Name required to add new config";
780 0           my $Configs = _load_apperl_configs();
781 0 0         ! exists $Configs->{apperl_configs}{$name} or die "Cannot create already existing config";
782 0 0         if(defined $base) {
783 0 0         exists $Configs->{apperl_configs}{$base} or die "base config $base does not exist";
784             }
785 0 0         my $projectconfig = _load_json(PROJECT_FILE) or die "project file must already exist";
786 0           $projectconfig->{apperl_configs}{$name} = _build_def_config($base);
787 0           print "rewriting project\n";
788 0           _write_json(PROJECT_FILE, $projectconfig);
789             }
790              
791             sub InstallBuildDeps {
792 0     0 0   my ($perlrepo, $cosmorepo) = @_;
793 0           my $SiteConfig = _load_json(SITE_CONFIG_FILE);
794             # if a repo is not set, set one up by default
795 0 0 0       if((!$SiteConfig || !exists $SiteConfig->{perl_repo}) && (!$perlrepo)) {
      0        
796 0           $perlrepo = SITE_REPO_DIR."/perl5";
797 0           _setup_repo($perlrepo, _load_apperl_configs()->{perl_remotes});
798 0           print "apperlm install-build-deps: setup perl repo\n";
799             }
800 0 0 0       if((!$SiteConfig || !exists $SiteConfig->{cosmo_repo}) && (!$cosmorepo)) {
      0        
801 0           $cosmorepo = SITE_REPO_DIR."/cosmopolitan";
802 0           _setup_repo( $cosmorepo, _load_apperl_configs()->{cosmo_remotes});
803 0           print "apperlm install-build-deps: setup cosmo repo\n";
804             }
805              
806             # (re)write site config
807 0   0       $perlrepo //= $SiteConfig->{perl_repo};
808 0   0       $cosmorepo //= $SiteConfig->{cosmo_repo};
809 0           my %siteconfig = (
810             perl_repo => abs_path($perlrepo),
811             cosmo_repo => abs_path($cosmorepo)
812             );
813 0           $SiteConfig = \%siteconfig;
814 0           make_path(SITE_CONFIG_DIR);
815 0           _write_json(SITE_CONFIG_FILE, \%siteconfig);
816 0           print "apperlm install-build-deps: wrote site config to ".SITE_CONFIG_FILE."\n";
817             }
818              
819             sub _remove_arr_items_from_arr {
820 0     0     my ($src, $toremove) = @_;
821 0           foreach my $item (@{$toremove}) {
  0            
822 0           my $index = 0;
823 0           $index++ until $src->[$index] eq $item;
824 0           splice(@$src, $index, 1);
825             }
826             }
827              
828             sub Status {
829 0     0 0   my $Configs = _load_apperl_configs();
830 0           my @configlist = sort(keys %{$Configs->{apperl_configs}});
  0            
831 0           my $UserProjectConfig = _load_user_project_config();
832 0           my $CurAPPerlName;
833 0 0         if($UserProjectConfig) {
834 0 0         if(exists $UserProjectConfig->{current_apperl}) {
835 0           $CurAPPerlName = $UserProjectConfig->{current_apperl};
836 0 0         exists $Configs->{apperl_configs}{$CurAPPerlName} or die("non-existent apperl config $CurAPPerlName in user project config");
837             }
838             }
839 0 0 0       if(!defined $CurAPPerlName && exists $Configs->{'defaultconfig'}) {
840 0           $CurAPPerlName = $Configs->{'defaultconfig'};
841 0 0         exists $Configs->{apperl_configs}{$CurAPPerlName} or die("non-existent default apperl config $CurAPPerlName");
842             }
843              
844 0           my @projectitems;
845 0           my $projectconfig = _load_json(PROJECT_FILE);
846 0 0 0       if($projectconfig && exists $projectconfig->{apperl_configs}) {
847 0           @projectitems = sort (keys %{$projectconfig->{apperl_configs}});
  0            
848             }
849 0           my @stable = grep( /v\d+\.\d+\.\d+(\-vista)?$/, @configlist);
850 0           my @rolling = ('full', 'full-vista', 'small', 'small-vista');
851 0           my @internal = ('dontuse_threads', 'perl_cosmo_dev', 'perl_cosmo_dev_on_vista', 'perl_apperl_dev');
852 0           my @categories = (
853             ['PROJECT', \@projectitems],
854             ['STABLE', \@stable],
855             ['ROLLING', \@rolling],
856             ['UNSTABLE/INTERNAL', \@internal],
857             ['UNKNOWN', \@configlist]
858             );
859 0           foreach my $cat (@categories) {
860 0           foreach my $item (@{$cat->[1]}) {
  0            
861 0 0 0       print (sprintf "%s %-30.30s | %-17.17s |%s\n", $CurAPPerlName && ($item eq $CurAPPerlName) ? '*' : ' ', $item, $cat->[0], ($Configs->{apperl_configs}{$item}{desc} // ''));
      0        
862             }
863 0           _remove_arr_items_from_arr(\@configlist, \@{$cat->[1]});
  0            
864             }
865             }
866              
867             # unfortunately this needs to be called in several places to try to keep them in sync
868             # as perl's make trips up when trying to build an symlinked extension
869             sub _install_perl_repo_files {
870 0     0     my ($itemconfig, $SiteConfig) = @_;
871 0           foreach my $dest (keys %{$itemconfig->{perl_repo_files}}) {
  0            
872 0           foreach my $file (@{$itemconfig->{perl_repo_files}{$dest}}) {
  0            
873             #_command_or_die('ln', '-sf', START_WD."/$file", "$SiteConfig->{perl_repo}/$dest");
874 0           _copy_recursive(START_WD."/$file", "$SiteConfig->{perl_repo}/$dest");
875             }
876             }
877             }
878              
879             sub Set {
880 0     0 0   my ($cfgname) = @_;
881 0           my $UserProjectConfig = _load_user_project_config();
882 0 0         if($UserProjectConfig) {
883 0           delete $UserProjectConfig->{nobuild_perl_bin};
884             }
885             else {
886 0           $UserProjectConfig = {};
887             }
888 0           my $itemconfig = _load_apperl_config(_load_apperl_configs()->{apperl_configs}, $cfgname);
889 0           print Dumper($itemconfig);
890 0 0         if(! exists $itemconfig->{nobuild_perl_bin}) {
891 0 0         my $SiteConfig = _load_json(SITE_CONFIG_FILE) or die "cannot set without build deps (run apperlm install-build-deps)";
892 0 0         -d $SiteConfig->{cosmo_repo} or die $SiteConfig->{cosmo_repo} .' is not directory';
893 0 0         -d $SiteConfig->{perl_repo} or die $SiteConfig->{perl_repo} .' is not directory';
894 0           print "cd ".$SiteConfig->{cosmo_repo}."\n";
895 0 0         chdir($SiteConfig->{cosmo_repo}) or die "Failed to enter cosmo repo";
896 0           _command_or_die('git', 'checkout', $itemconfig->{cosmo_id});
897              
898 0           print "cd ".$SiteConfig->{perl_repo}."\n";
899 0 0         chdir($SiteConfig->{perl_repo}) or die "Failed to enter perl repo";
900 0           print "make veryclean\n";
901 0           system("make", "veryclean");
902 0           foreach my $todelete ('miniperl.com', 'perl.com', 'miniperl.elf', 'miniperl.com.dbg', 'perl.elf', 'perl.com.dbg') {
903 0           print "rm $todelete\n";
904 1 0 0 1   519 unlink($todelete) || $!{ENOENT} or die "failed to delete $todelete";
  1         1420  
  1         11  
  0            
905             }
906 0           _command_or_die('git', 'checkout', $itemconfig->{perl_id});
907              
908 0           print "cd ".START_WD."\n";
909 0 0         chdir(START_WD) or die "Failed to restore cwd";
910 0           _install_perl_repo_files($itemconfig, $SiteConfig);
911             }
912             else {
913 0           my $validperl;
914 0           foreach my $perlbin (@{$itemconfig->{nobuild_perl_bin}}) {
  0            
915 0           print "perlbin $perlbin\n";
916 0 0         if(-f $perlbin) {
917 0 0 0       if(( $perlbin eq $^X) && (! -d '/zip')) {
918 0           print "skipping $perlbin, it appears to not be APPerl\n";
919 0           next;
920             }
921 0           $validperl = $perlbin;
922 0           last;
923             }
924             }
925 0 0         $validperl or die "no valid perl found to use for nobuild config";
926 0           $validperl = abs_path($validperl);
927 0 0         $validperl or die "no valid perl found to use for nobuild config";
928 0           $UserProjectConfig->{nobuild_perl_bin} = $validperl;
929 0           print "Set UserProjectConfig to nobuild_perl-bin to $validperl\n";
930             }
931 0   0       $UserProjectConfig->{apperl_output} //= PROJECT_TMP_DIR."/o";
932 0           $UserProjectConfig->{current_apperl} = $cfgname;
933 0           _write_user_project_config($UserProjectConfig);
934 0           print "$0: Successfully switched to $cfgname\n";
935             }
936              
937             sub Configure {
938 0     0 0   my $Configs = _load_apperl_configs();
939 0 0         my $UserProjectConfig = _load_valid_user_project_config_with_default($Configs) or die "cannot Configure without valid UserProjectConfig";
940 0           my $CurAPPerlName = $UserProjectConfig->{current_apperl};
941 0 0         ! exists $UserProjectConfig->{nobuild_perl_bin} or die "nobuild perl cannot be configured";
942 0 0         my $SiteConfig = _load_json(SITE_CONFIG_FILE) or die "cannot Configure without build deps (run apperlm install-build-deps)";
943 0 0         -d $SiteConfig->{cosmo_repo} or die $SiteConfig->{cosmo_repo} .' is not directory';
944 0 0         -d $SiteConfig->{perl_repo} or die $SiteConfig->{perl_repo} .' is not directory';
945 0           my $itemconfig = _load_apperl_config($Configs->{apperl_configs}, $CurAPPerlName);
946 0           _install_perl_repo_files($itemconfig, $SiteConfig);
947             # build cosmo
948 0           print "$0: Building cosmo, COSMO_MODE=$itemconfig->{cosmo_mode} COSMO_APE_LOADER=$itemconfig->{cosmo_ape_loader}\n";
949 0           _command_or_die('make', '-C', $SiteConfig->{cosmo_repo}, '-j4', "MODE=$itemconfig->{cosmo_mode}",
950             "o/$itemconfig->{cosmo_mode}/cosmopolitan.a",
951             "o/$itemconfig->{cosmo_mode}/libc/crt/crt.o",
952             "o/$itemconfig->{cosmo_mode}/ape/public/ape.lds",
953             "o/$itemconfig->{cosmo_mode}/ape/$itemconfig->{cosmo_ape_loader}",
954             );
955              
956             # Finally Configure perl
957 0           print "cd ".$SiteConfig->{perl_repo}."\n";
958 0 0         chdir($SiteConfig->{perl_repo}) or die "Failed to enter perl repo";
959 0           $ENV{COSMO_REPO} = $SiteConfig->{cosmo_repo};
960 0           $ENV{COSMO_MODE} = $itemconfig->{cosmo_mode};
961 0           $ENV{COSMO_APE_LOADER} = $itemconfig->{cosmo_ape_loader};
962 0           my @onlyextensions = ();
963 0 0         push @onlyextensions, ("-Donlyextensions= ".join(' ', sort @{$itemconfig->{perl_onlyextensions}}).' ') if(exists $itemconfig->{perl_onlyextensions});
  0            
964 0           _command_or_die('sh', 'Configure', @{$itemconfig->{perl_flags}}, @onlyextensions, @{$itemconfig->{perl_extra_flags}}, @_);
  0            
  0            
965 0           print "$0: Configure successful, time for apperlm build\n";
966             }
967              
968             sub _fix_bases {
969 0     0     my ($in, $aliasmap) = @_;
970 0           foreach my $key (keys %{$aliasmap}) {
  0            
971 0           $in =~ s/^$key/$aliasmap->{$key}/;
972             }
973 0           return $in;
974             }
975              
976             # system is pretty broken on APPerl when running on Windows
977             # let's search PATH ourselves ...
978             sub _find_zip {
979 0 0 0 0     if(($^O ne 'cosmo') || (! -f '/C/Windows/System32/cmd.exe')) {
980 0           return 'zip';
981             }
982             else {
983 0           foreach my $dir (split(':', $ENV{PATH})) {
984 0           my $zippath = "$dir/zip.exe";
985 0 0         return $zippath if(-f $zippath);
986             }
987             }
988 0           die("Failed to find zip.exe, did you download Info-Zip and add the folder containing zip.exe to \%PATH\%?");
989             }
990              
991             sub Build {
992 0     0 0   my ($zippath) = @_;
993 0           my $Configs = _load_apperl_configs();
994 0 0         my $UserProjectConfig = _load_valid_user_project_config_with_default($Configs) or die "cannot Build without valid UserProjectConfig";
995 0           my $CurAPPerlName = $UserProjectConfig->{current_apperl};
996 0           my $itemconfig = _load_apperl_config($Configs->{apperl_configs}, $CurAPPerlName);
997 0           my $startdir = abs_path('./');
998              
999 0           my $PERL_APE;
1000             my @perl_config_cmd;
1001             # build cosmo perl if this isn't a nobuild config
1002 0 0         if(! exists $UserProjectConfig->{nobuild_perl_bin}){
1003 0 0         my $SiteConfig = _load_json(SITE_CONFIG_FILE) or die "cannot build without build deps (run apperlm install-build-deps)";
1004 0 0         -d $SiteConfig->{cosmo_repo} or die $SiteConfig->{cosmo_repo} .' is not directory';
1005 0 0         -d $SiteConfig->{perl_repo} or die $SiteConfig->{perl_repo} .' is not directory';
1006 0           _install_perl_repo_files($itemconfig, $SiteConfig);
1007 0           print "cd ".$SiteConfig->{perl_repo}."\n";
1008 0 0         chdir($SiteConfig->{perl_repo}) or die "Failed to enter perl repo";
1009 0           _command_or_die('make');
1010 0           $PERL_APE = "$SiteConfig->{perl_repo}/perl.com";
1011 0           @perl_config_cmd = ('./perl', '-Ilib');
1012             }
1013             else {
1014 0           $PERL_APE = $UserProjectConfig->{nobuild_perl_bin};
1015 0           @perl_config_cmd = ($PERL_APE);
1016             }
1017              
1018             # prepare for install and pack
1019 0 0         -f $PERL_APE or die "apperlm build: perl ape not found";
1020 0           my $OUTPUTDIR = "$UserProjectConfig->{apperl_output}/$CurAPPerlName";
1021 0 0         if(-d $OUTPUTDIR) {
1022 0           print "rm -rf $OUTPUTDIR\n";
1023 0           remove_tree($OUTPUTDIR);
1024             }
1025 0           my $TEMPDIR = "$OUTPUTDIR/tmp";
1026 0           print "mkdir -p $TEMPDIR\n";
1027 0           make_path($TEMPDIR);
1028 0           my %proxyConfig;
1029 0           foreach my $item (qw(prefix version archname cc installprivlib installarchlib installsitelib installsitearch installprefixexp installbin installman1dir installman3dir)) {
1030 0           $proxyConfig{$item} = _cmdoutput_or_die(@perl_config_cmd, '-e', "use Config; print \$Config{$item}");
1031             }
1032             my %aliasmap = (
1033             '__perllib__' => $proxyConfig{installprivlib},
1034             '__perlarchlib__' => $proxyConfig{installarchlib},
1035             '__sitelib__' => $proxyConfig{installsitelib},
1036             '__sitearchlib__' => $proxyConfig{installsitearch}
1037 0           );
1038 0           foreach my $libdir (keys %aliasmap) {
1039 0           $aliasmap{$libdir} =~ s/$proxyConfig{installprefixexp}\///;
1040             }
1041 0           my @zipfiles = map { _fix_bases($_, \%aliasmap) } @{$itemconfig->{MANIFEST}};
  0            
  0            
1042 0           my $ZIP_ROOT = "$TEMPDIR$proxyConfig{installprefixexp}";
1043              
1044             # install cosmo perl if this isn't a nobuild config
1045 0 0         if(! exists $UserProjectConfig->{nobuild_perl_bin}){
1046 0           _command_or_die('make', "DESTDIR=$TEMPDIR", 'install');
1047 0           my @toremove = ("$TEMPDIR$proxyConfig{installbin}/perl", "$TEMPDIR$proxyConfig{installbin}/perl$proxyConfig{version}");
1048 0           print 'rm '.join(' ', @toremove)."\n";
1049 0 0         unlink(@toremove) == scalar(@toremove) or die "Failed to unlink some files";
1050             }
1051             else {
1052 0           make_path($ZIP_ROOT);
1053             }
1054              
1055             # add zip_extra_files to the tree
1056 0           foreach my $destkey (keys %{$itemconfig->{zip_extra_files}}) {
  0            
1057 0           my $dest = "$ZIP_ROOT/"._fix_bases($destkey, \%aliasmap);
1058 0           foreach my $file (@{$itemconfig->{zip_extra_files}{$destkey}}) {
  0            
1059 0           _copy_recursive($file, $dest);
1060             }
1061             }
1062              
1063             # pack
1064 0           my $APPPATH = "$TEMPDIR/".basename($PERL_APE);
1065             my $packAPE = sub {
1066             my $copyexe = sub {
1067 0           my ($srcpath, $destpath) = @_;
1068 0           print "cp $srcpath $destpath\n";
1069 0 0         copy($srcpath, $destpath) or die "copy failed: $!";
1070 0           print "chmod 755 $destpath\n";
1071 0 0         chmod(0755, $destpath) or die $!;
1072 0     0     };
1073 0           $copyexe->($PERL_APE, $APPPATH);
1074 0           my $srcdbg = "$PERL_APE.dbg";
1075 0           for(1..2) {
1076 0 0         if(-f $srcdbg) {
1077 0           $copyexe->($srcdbg, "$APPPATH.dbg");
1078 0           last;
1079             }
1080 0           $srcdbg = $PERL_APE;
1081 0           $srcdbg =~ s/com$/elf/;
1082             }
1083 0 0 0       if((! exists $UserProjectConfig->{nobuild_perl_bin}) || scalar(keys %{$itemconfig->{zip_extra_files}})) {
  0            
1084 0           print "cd $ZIP_ROOT\n";
1085 0 0         chdir($ZIP_ROOT) or die "failed to enter ziproot";
1086 0   0       _command_or_die($zippath // _find_zip(), '-r', $APPPATH, @zipfiles);
1087             }
1088 0           };
1089 0           $packAPE->();
1090              
1091             # install modules
1092 0 0         if(exists $itemconfig->{install_modules}) {
1093 0           my $perlman1 = "$TEMPDIR$proxyConfig{installman1dir}";
1094 0           my $perlman3 = "$TEMPDIR$proxyConfig{installman3dir}";
1095 0           my $perlbin = "$TEMPDIR$proxyConfig{installbin}";
1096 0           my $perllib = "$TEMPDIR$proxyConfig{installprivlib}";
1097 0           my $perlarchlib = "$TEMPDIR$proxyConfig{installarchlib}";
1098             my $mmopt = sub {
1099 0     0     my @mmopt = ("PERL_LIB=$perllib", "PERL_ARCHLIB=$perlarchlib", "MAP_TARGET=perl.com.dbg",
1100             "INSTALLDIRS=perl",
1101             "INSTALLARCHLIB=$perlarchlib",
1102             "INSTALLPRIVLIB=$perllib",
1103             "INSTALLBIN=$perlbin",
1104             "INSTALLSCRIPT=$perlbin",
1105             "INSTALLMAN1DIR=$perlman1",
1106             "INSTALLMAN3DIR=$perlman3"
1107             );
1108 0           my $str;
1109 0           $str .= qq["$_" ] foreach @mmopt;
1110 0           chop $str;
1111 0           return $str;
1112 0           }->();
1113             my $mbopt = sub {
1114 0     0     my %mbinstall_path = (
1115             lib => $perllib,
1116             arch => $perlarchlib,
1117             script => $perlbin,
1118             bin => $perlbin,
1119             bindoc => $perlman1,
1120             libdoc => $perlman3
1121             );
1122 0           my $mbopt;
1123 0           foreach my $key (keys %mbinstall_path) {
1124 0           $mbopt .= qq[--install_path $key=$mbinstall_path{$key} ];
1125             };
1126 0           chop $mbopt;
1127 0           return $mbopt;
1128 0           }->();
1129 0           local $ENV{PERL_MB_OPT} = $mbopt;
1130 0           local $ENV{PERL_MM_OPT} = $mmopt;
1131 0           local $ENV{PERL5LIB} = $perllib;
1132 0           local $ENV{PERL_LOCAL_LIB_ROOT} = '';
1133 0           foreach my $module (@{$itemconfig->{install_modules}}) {
  0            
1134 0           my $modulepath = "$startdir/$module";
1135 0 0         if(-d $modulepath) {
    0          
1136 0           _copy_recursive($modulepath, $TEMPDIR);
1137 0           $modulepath = "$TEMPDIR/".basename($modulepath);
1138             }
1139             elsif( -f _) {
1140 0           _command_or_die('tar', 'xvf', $modulepath, '-C', $TEMPDIR);
1141 0           $modulepath = "$TEMPDIR/".basename($modulepath);
1142 0           $modulepath =~ s/\.tar.*$//;
1143             }
1144             else {
1145 0           die "Module must be a directory or tarball";
1146             }
1147              
1148 0           print "cd $modulepath\n";
1149 0 0         chdir($modulepath) or die "Failed to enter module dir";
1150             # Module::Build (including installing Module::Build)
1151             # Beware, Module::Build has no support for relinking the Perl binary like EU::MM - https://rt.cpan.org/Public/Bug/Display.html?id=47282
1152 0 0         if(-f 'Build.PL') {
    0          
1153 0           _command_or_die($APPPATH, 'Build.PL');
1154 0           _command_or_die($APPPATH, 'Build');
1155 0           _command_or_die($APPPATH, 'Build', 'install');
1156             }
1157             # ExtUtils::MakeMaker
1158             elsif( -f 'Makefile.PL') {
1159             # build
1160 0           _command_or_die($APPPATH, 'Makefile.PL');
1161 0           _command_or_die('make');
1162             # install into the src tree
1163 0           _command_or_die('make', 'install');
1164             # build a new perl binary, convert to APE, and repack zip
1165 0           _command_or_die('make', 'perl.com.dbg');
1166 0           _command_or_die(dirname($proxyConfig{cc})."/x86_64-linux-musl-objcopy", '-S', '-O', 'binary', 'perl.com.dbg', 'perl.com');
1167 0           $PERL_APE = abs_path('./perl.com');
1168             }
1169             else {
1170 0           die "No Makefile.PL or Build.PL found, unable to install module";
1171             }
1172 0           $packAPE->();
1173             }
1174             }
1175              
1176             # patch default script
1177 0 0         if(exists $itemconfig->{default_script}) {
1178 0 0         length($itemconfig->{default_script}) <= 255 or die "default script path is too long";
1179 0 0         open(my $fh, '+<:raw', $APPPATH) or die "$!";
1180 0           my $fsize = (stat($fh))[7];
1181 0           my $bread = read($fh, my $outdata, $fsize);
1182 0 0 0       $bread && $bread == $fsize or die "failed to read full file $APPPATH";
1183 0           my $sentinel = "APPERL_DEFAULT_SCRIPT";
1184 0           my $sentinelpos = index($outdata, $sentinel);
1185 0 0         $sentinelpos != -1 or die "Failed to find APPERL_DEFAULT_SCRIPT, is this an old APPerl binary?";
1186 0           print "patching default script at " . ($sentinelpos+length($sentinel)+1) . "\n";
1187 0 0         seek($fh, $sentinelpos+length($sentinel)+1, SEEK_SET) or die "$!";
1188 0 0         print $fh $itemconfig->{default_script}."\0" or die "$!";
1189 0           close($fh);
1190             }
1191              
1192 0           foreach my $file ('perl.com', 'perl.com.dbg') {
1193 0           my $srcpath = "$TEMPDIR/$file";
1194 0 0         -e $srcpath or next;
1195 0           my $destpath = "$OUTPUTDIR/$file";
1196 0           print "mv $srcpath $destpath\n";
1197 0 0         move($srcpath, $destpath) or die "move failed: $!";
1198             }
1199              
1200             # copy to user specified location
1201 0 0         if(exists $itemconfig->{dest}) {
1202 0           print "cd ".START_WD."\n";
1203 0 0         chdir(START_WD) or die "Failed to restore cwd";
1204 0           foreach my $srcfile ('perl.com', 'perl.com.dbg') {
1205 0           my $destfile = $itemconfig->{dest};
1206 0 0         $destfile .= '.dbg' if ($srcfile =~ /dbg$/);
1207 0           my @args = ("$UserProjectConfig->{apperl_output}/$CurAPPerlName/$srcfile", $destfile);
1208 0 0         -e $args[0] or next;
1209 0           print 'cp '.join(' ', @args)."\n";
1210 0 0         cp(@args) or die "copy failed: $!";
1211             }
1212             }
1213             }
1214              
1215             sub apperlm {
1216 0     0 0   my $generic_usage = <<'END_USAGE';
1217             apperlm [...]
1218             List of commands, try apperlm --help for info about a command
1219             list | List available APPerl configurations
1220             init | Create an APPerl project in the current dir
1221             new-config | Add a new APPerl configuration to the project
1222             checkout | Switch to another APPerl configurations
1223             install-build-deps | Install build dependencies for APPerl
1224             configure | `Configure` Perl (only valid with build config)
1225             build | Build APPerl
1226             help | Prints this message
1227              
1228             Actually Portable Perl Manager (apperlm) handles configuring and
1229             building Actually Portable Perl (APPerl). See
1230             `perldoc Perl::Dist::APPerl` for more info.
1231             END_USAGE
1232 0 0         my $command = shift(@_) if(@_);
1233 0 0         $command or die($generic_usage);
1234 0 0         if($command eq 'list') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1235 0           my $usage = <<'END_USAGE';
1236             apperlm list
1237             List available APPerl configs; checks apperl-project.json and built-in
1238             to Perl::Dist::APPerl configs. If a current config is set it is denoted
1239             with a '*'.
1240             END_USAGE
1241 0 0         die($usage) if(@_);
1242 0           Perl::Dist::APPerl::Status();
1243             }
1244             elsif($command eq 'build') {
1245 0           my $usage = <<'END_USAGE';
1246             apperlm build [-z|--zippath ]
1247             -z|--zippath Path to InfoZip zip executable
1248             Build APPerl. If the current config is a from-scratch build, you must
1249             run `apperlm configure` first.
1250             END_USAGE
1251 0           my $zippath;
1252             my $help;
1253 0 0         GetOptionsFromArray(\@_, "zippath|z=s" => \$zippath,
1254             "help|h" => \$help,
1255             ) or die($usage);
1256 0 0         if($help) {
1257 0           print $usage;
1258 0           exit 0;
1259             }
1260 0           Perl::Dist::APPerl::Build($zippath);
1261             }
1262             elsif($command eq 'configure') {
1263 0           Perl::Dist::APPerl::Configure(@_);
1264             }
1265             elsif($command =~ /^(\-)*(halp|help|h)$/i) {
1266 0           print $generic_usage;
1267             }
1268             elsif($command =~ /^(\-)*(version|v)$/i) {
1269 0           my $message = <<"END_USAGE";
1270             apperlm $VERSION
1271             Copyright (C) 2022 Gavin Arthur Hayes
1272             This is free software; you can redistribute it and/or modify it under
1273             the same terms as the Perl 5 programming language system itself.
1274             END_USAGE
1275 0           print $message;
1276             }
1277             elsif($command eq 'checkout') {
1278 0 0         scalar(@_) == 1 or die('bad args');
1279 0           my $cfgname = $_[0];
1280 0           Perl::Dist::APPerl::Set($cfgname);
1281             }
1282             elsif($command eq 'init') {
1283 0           my $usage = <<'END_USAGE';
1284             apperlm init [-h|--help] [-n|--name ] [-b|--base ]
1285             -n|--name name of the default config
1286             -b|--base base class of the config
1287             -h|--help Show this message
1288             Create an APPerl project, create a config if -n specified and it
1289             doesn't already exist, checkout the config.
1290             END_USAGE
1291 0           my $name;
1292             my $base;
1293 0           my $help;
1294 0 0         GetOptionsFromArray(\@_, "name|n=s" => \$name,
1295             "base|b=s" => \$base,
1296             "help|h" => \$help,
1297             ) or die($usage);
1298 0 0         if($help) {
1299 0           print $usage;
1300 0           exit 0;
1301             }
1302 0           Perl::Dist::APPerl::Init($name, $base);
1303             }
1304             elsif($command eq 'install-build-deps') {
1305 0           my $usage = <<'END_USAGE';
1306             apperlm install-build-deps [-h|--help] [-c|--cosmo ] [-p|--perl ]
1307             -c|--cosmo set path to cosmopolitan repo (skips git initialization)
1308             -p|--perl set path to perl repo (skips git initialization)
1309             -h|--help Show this message
1310             Install build dependencies for APPerl, use -c or -p to skip initializing
1311             those repos by providing a path to it.
1312             END_USAGE
1313 0           my $cosmo;
1314             my $perl;
1315 0           my $help;
1316 0 0         GetOptionsFromArray(\@_, "cosmo|c=s" => \$cosmo,
1317             "perl|p=s" => \$perl,
1318             "help|h" => \$help,
1319             ) or die($usage);
1320 0 0         if($help) {
1321 0           print $usage;
1322 0           exit 0;
1323             }
1324 0           Perl::Dist::APPerl::InstallBuildDeps($perl, $cosmo);
1325             }
1326             elsif($command eq 'new-config') {
1327 0           my $usage = <<'END_USAGE';
1328             apperlm new-config [-h|--help] [-n|--name ] [-b|--base ]
1329             -n|--name name of the default config
1330             -b|--base base class of the config
1331             -h|--help Show this message
1332             Create a new APPerl config and add it to the project
1333             END_USAGE
1334 0           my $name;
1335             my $base;
1336 0           my $help;
1337 0 0         GetOptionsFromArray(\@_, "name|n=s" => \$name,
1338             "base|b=s" => \$base,
1339             "help|h" => \$help,
1340             ) or die($usage);
1341 0 0         if($help) {
1342 0           print $usage;
1343 0           exit 0;
1344             }
1345 0           Perl::Dist::APPerl::NewConfig($name, $base);
1346             }
1347             elsif($command eq 'get-config-key') {
1348 0 0         scalar(@_) == 2 or die('bad args');
1349 0           my $itemconfig = _load_apperl_config(_load_apperl_configs()->{apperl_configs}, $_[0]);
1350 0           print $itemconfig->{$_[1]};
1351             }
1352             else {
1353 0           die($generic_usage);
1354             }
1355 0           1;
1356             }
1357              
1358             sub _command_or_die {
1359 0     0     print join(' ', @_), "\n";
1360 0 0         system(@_) == 0 or die;
1361             }
1362              
1363             sub _cmdoutput_or_die {
1364 0     0     print join(' ', @_), "\n";
1365 0 0         my $kid = open(my $from_kid, '-|', @_) or die "can't fork $!";
1366 0           my $output = do { local $/; <$from_kid> };
  0            
  0            
1367 0           waitpid($kid, 0);
1368 0 0         (($? >> 8) == 0) or die("child failed");
1369 0           return $output;
1370             }
1371              
1372             sub _setup_repo {
1373 0     0     my ($repopath, $remotes) = @_;
1374 0           print "mkdir -p $repopath\n";
1375 0           make_path($repopath);
1376 0           print "cd $repopath\n";
1377 0 0         chdir($repopath) or die "Failed to chdir $repopath";
1378 0           _command_or_die('git', 'init');
1379 0           _command_or_die('git', 'checkout', '-b', 'placeholder_dont_use');
1380 0           foreach my $remote (keys %{$remotes}) {
  0            
1381 0           _command_or_die('git', 'remote', 'add', $remote, $remotes->{$remote});
1382 0           _command_or_die('git', 'fetch', $remote);
1383             }
1384             }
1385              
1386             sub _write_json {
1387 0     0     my ($destpath, $obj) = @_;
1388 0 0         open(my $fh, '>', $destpath) or die("Failed to open $destpath for writing");
1389 0           print $fh JSON::PP->new->pretty->encode($obj);
1390 0           close($fh);
1391             }
1392              
1393             sub _load_json {
1394 0     0     my ($jsonpath) = @_;
1395 0 0         open(my $fh, '<', $jsonpath) or return undef;
1396 0           my $file_content = do { local $/; <$fh> };
  0            
  0            
1397 0           close($fh);
1398 0           return decode_json($file_content);
1399             }
1400              
1401             sub _load_apperl_config {
1402 0     0     my ($apperlconfigs, $cfgname) = @_;
1403 0 0         exists $apperlconfigs->{$cfgname} or die "Unknown config: $cfgname";
1404              
1405             # find the base classes
1406 0           my $item = $apperlconfigs->{$cfgname};
1407 0           my @configlist = ($item);
1408 0           while(exists $item->{base}) {
1409 0           $item = $apperlconfigs->{$item->{base}};
1410 0           push @configlist, $item;
1411             }
1412 0           @configlist = reverse @configlist;
1413              
1414             # build the config from oldest to newest
1415             # keys that start with '+' are appended to the non-plus variant instead of replacing
1416             # keys that start with '-' are removed from the non-plus variant instead of replacing
1417             # Removing a key added the same stage or vice versa is undefined
1418 0           my %itemconfig;
1419 0           foreach my $config (@configlist) {
1420 0           foreach my $key (keys %$config) {
1421 0 0         if($key =~ /^(\+|\-)(.+)/) {
1422 0           my $append = $1 eq '+';
1423 0           my $realkey = $2;
1424 0 0         exists $itemconfig{$realkey} or die "cannot append without existing key: $realkey";
1425 0           my $rtype = ref($itemconfig{$realkey});
1426 0 0         $rtype or die("not ref");
1427 0 0         if($append) {
1428 0 0         if($rtype eq 'ARRAY') {
    0          
1429 0           $itemconfig{$realkey} = [@{$itemconfig{$realkey}}, @{$config->{$key}}];
  0            
  0            
1430             }
1431             elsif($rtype eq 'HASH') {
1432 0           foreach my $dest (keys %{$config->{$key}}) {
  0            
1433 0           push @{$itemconfig{$realkey}{$dest}}, @{$config->{$key}{$dest}};
  0            
  0            
1434             }
1435             }
1436             else {
1437 0           die($rtype);
1438             }
1439             }
1440             else {
1441 0 0         if($rtype eq 'ARRAY') {
1442 0           _remove_arr_items_from_arr($itemconfig{$realkey}, $config->{$key});
1443             }
1444             else {
1445 0           die($rtype);
1446             }
1447             }
1448             }
1449             else {
1450 0           $itemconfig{$key} = $config->{$key};
1451             }
1452             }
1453             }
1454              
1455             # switch these from relative paths to abs paths
1456 0           foreach my $destdir (keys %{$itemconfig{zip_extra_files}}) {
  0            
1457 0           foreach my $path (@{$itemconfig{zip_extra_files}{$destdir}}) {
  0            
1458 0           $path = abs_path($path);
1459 0 0         $path or die "zip_extra_files: check that all files exist for destdir: $destdir";
1460 0 0         -e $path or die "zip_extra_files: missing file $path";
1461             }
1462             }
1463              
1464             # add in ourselves for bootstrapping, this even works when running internal Perl::Dist::APPerl from a bootstrapped build
1465 0 0 0       if(exists $itemconfig{'include_Perl-Dist-APPerl'} && $itemconfig{'include_Perl-Dist-APPerl'}) {
1466 0           my $thispath = abs_path(__FILE__);
1467 0 0         defined($thispath) or die(__FILE__.'issues?');
1468 0           push @{$itemconfig{zip_extra_files}{"__perllib__/Perl/Dist"}}, $thispath;
  0            
1469 0           my $apperlm = $0;
1470 0 0         if(basename($0) ne 'apperlm') {
1471 0           $apperlm = dirname($thispath)."/../../../script/apperlm";
1472             }
1473 0           $apperlm = abs_path($apperlm);
1474 0 0         defined($apperlm) or die "error getting path to apperlm";
1475 0           my @additionalfiles = ($apperlm);
1476 0   0       -e $_ or die("$_ $!") foreach @additionalfiles;
1477 0           push @{$itemconfig{zip_extra_files}{bin}}, @additionalfiles;
  0            
1478             }
1479              
1480             # verify apperl config sanity
1481 0 0         if(! exists $itemconfig{nobuild_perl_bin}) {
1482 0   0       $itemconfig{cosmo_ape_loader} //= 'ape-no-modify-self.o';
1483 0 0 0       ($itemconfig{cosmo_ape_loader} eq 'ape-no-modify-self.o') || ($itemconfig{cosmo_ape_loader} eq 'ape.o') or die "Unknown ape loader: " . $itemconfig{cosmo_ape_loader};
1484             }
1485              
1486 0           return \%itemconfig;
1487             }
1488              
1489             sub _load_user_project_config {
1490 0     0     return _load_json(PROJECT_TMP_CONFIG_FILE);
1491             }
1492              
1493             sub _load_valid_user_project_config {
1494 0     0     my ($Configs) = @_;
1495 0           my $UserProjectConfig = _load_user_project_config();
1496 0 0         if($UserProjectConfig) {
1497 0 0         if(exists $UserProjectConfig->{current_apperl}) {
1498 0           my $CurAPPerlName = $UserProjectConfig->{current_apperl};
1499 0 0         exists $Configs->{apperl_configs}{$CurAPPerlName} or die("non-existent apperl config $CurAPPerlName in user project config");
1500 0           return $UserProjectConfig;
1501             }
1502             }
1503 0           return undef;
1504             }
1505              
1506             sub _load_valid_user_project_config_with_default {
1507 0     0     my ($Configs) = @_;
1508 0           my $UserProjectConfig = _load_valid_user_project_config($Configs);
1509 0 0 0       return $UserProjectConfig if($UserProjectConfig || !exists $Configs->{defaultconfig});
1510 0           Set($Configs->{defaultconfig});
1511 0           return _load_valid_user_project_config($Configs);
1512             }
1513              
1514             sub _write_user_project_config {
1515 0     0     my ($config) = @_;
1516 0 0         if(! -d PROJECT_TMP_DIR) {
1517 0           make_path(PROJECT_TMP_DIR);
1518             };
1519 0           _write_json(PROJECT_TMP_CONFIG_FILE, $config);
1520             }
1521              
1522             sub _copy_recursive {
1523 0     0     my ($src, $dest) = @_;
1524 0 0         if(! -d $dest) {
1525 0           make_path($dest);
1526             }
1527 0           goto &_copy_recursive_inner;
1528             }
1529              
1530             sub _copy_recursive_inner {
1531 0     0     my ($src, $dest) = @_;
1532 0           print "_copy_recursive $src $dest\n";
1533 0 0         if(-f $src) {
    0          
1534 0 0         copy($src, $dest) or die("Failed to copy $!");
1535             }
1536             elsif(-d $src) {
1537 0           my $dest = "$dest/".basename($src);
1538 0 0         if(! -d $dest) {
1539 0 0         mkdir($dest) or die("Failed to mkdir $!");
1540             }
1541 0 0         opendir(my $dh, $src) or die("Failed to opendir");
1542 0           while(my $file = readdir($dh)) {
1543 0 0 0       next if(($file eq '.') || ($file eq '..'));
1544 0           _copy_recursive("$src/$file", $dest);
1545             }
1546 0           closedir($dh);
1547             }
1548             else {
1549 0           die "Unhandled file type for $src";
1550             }
1551             }
1552              
1553             1;
1554              
1555             __END__