File Coverage

blib/lib/Perl/Dist/APPerl.pm
Criterion Covered Total %
statement 51 456 11.1
branch 1 240 0.4
condition 2 72 2.7
subroutine 17 43 39.5
pod 0 8 0.0
total 71 819 8.6


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